(root)/
binutils-2.41/
bfd/
elf64-bpf.c
       1  /* Linux bpf specific support for 64-bit ELF
       2     Copyright (C) 2019-2023 Free Software Foundation, Inc.
       3     Contributed by Oracle Inc.
       4  
       5     This file is part of BFD, the Binary File Descriptor library.
       6  
       7     This program is free software; you can redistribute it and/or modify
       8     it under the terms of the GNU General Public License as published by
       9     the Free Software Foundation; either version 3 of the License, or
      10     (at your option) any later version.
      11  
      12     This program is distributed in the hope that it will be useful,
      13     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15     GNU General Public License for more details.
      16  
      17     You should have received a copy of the GNU General Public License
      18     along with this program; if not, write to the Free Software
      19     Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
      20     MA 02110-1301, USA.  */
      21  
      22  #include "sysdep.h"
      23  #include "bfd.h"
      24  #include "libbfd.h"
      25  #include "elf-bfd.h"
      26  #include "elf/bpf.h"
      27  #include "libiberty.h"
      28  
      29  /* In case we're on a 32-bit machine, construct a 64-bit "-1" value.  */
      30  #define MINUS_ONE (~ (bfd_vma) 0)
      31  
      32  #define BASEADDR(SEC)	((SEC)->output_section->vma + (SEC)->output_offset)
      33  
      34  static bfd_reloc_status_type bpf_elf_generic_reloc
      35    (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
      36  
      37  #undef BPF_HOWTO
      38  #define BPF_HOWTO(type, right, size, bits, pcrel, left, ovf, func, name,   \
      39  		  inplace, src_mask, dst_mask, pcrel_off)                  \
      40  	type##_IDX,
      41  enum bpf_reloc_index {
      42    R_BPF_INVALID_IDX = -1,
      43  #include "bpf-reloc.def"
      44    R_BPF_SIZE
      45  };
      46  #undef BPF_HOWTO
      47  
      48  /* Relocation tables.  */
      49  #define BPF_HOWTO(...) HOWTO(__VA_ARGS__),
      50  static reloc_howto_type bpf_elf_howto_table [] =
      51  {
      52    #include "bpf-reloc.def"
      53  };
      54  #undef AHOW
      55  #undef BPF_HOWTO
      56  
      57  #define BPF_HOWTO(type, right, size, bits, pcrel, left, ovf, func, name,   \
      58  		  inplace, src_mask, dst_mask, pcrel_off)                  \
      59      case type: { return type##_IDX; }
      60  static enum bpf_reloc_index
      61  bpf_index_for_rtype(unsigned int r_type)
      62  {
      63    switch(r_type) {
      64  #include "bpf-reloc.def"
      65      default:
      66        /* Unreachable code. */
      67        BFD_ASSERT(0);
      68        return -1;
      69    };
      70  }
      71  
      72  /* Map BFD reloc types to bpf ELF reloc types.  */
      73  
      74  static reloc_howto_type *
      75  bpf_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
      76                          bfd_reloc_code_real_type code)
      77  {
      78    switch (code)
      79      {
      80      case BFD_RELOC_NONE:
      81        return &bpf_elf_howto_table[ (int) R_BPF_NONE_IDX];
      82  
      83      case BFD_RELOC_32:
      84        return &bpf_elf_howto_table[ (int) R_BPF_64_ABS32_IDX];
      85      case BFD_RELOC_64:
      86        return &bpf_elf_howto_table[ (int) R_BPF_64_ABS64_IDX];
      87  
      88      case BFD_RELOC_BPF_64:
      89        return &bpf_elf_howto_table[ (int) R_BPF_64_64_IDX];
      90      case BFD_RELOC_BPF_DISP32:
      91        return &bpf_elf_howto_table[ (int) R_BPF_64_32_IDX];
      92  
      93      default:
      94        /* Pacify gcc -Wall.  */
      95        return NULL;
      96      }
      97    return NULL;
      98  }
      99  
     100  /* Map BFD reloc names to bpf ELF reloc names.  */
     101  
     102  static reloc_howto_type *
     103  bpf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
     104  {
     105    unsigned int i;
     106  
     107    for (i = 0; i < R_BPF_SIZE; i++)
     108      if (bpf_elf_howto_table[i].name != NULL
     109  	&& strcasecmp (bpf_elf_howto_table[i].name, r_name) == 0)
     110        return &bpf_elf_howto_table[i];
     111  
     112    return NULL;
     113  }
     114  
     115  /* Set the howto pointer for a bpf reloc.  */
     116  
     117  static bool
     118  bpf_info_to_howto (bfd *abfd, arelent *bfd_reloc,
     119                      Elf_Internal_Rela *elf_reloc)
     120  {
     121    unsigned int r_type;
     122    unsigned int i;
     123    r_type = ELF64_R_TYPE (elf_reloc->r_info);
     124  
     125    i = bpf_index_for_rtype(r_type);
     126    if (i == (unsigned int) -1)
     127      {
     128        /* xgettext:c-format */
     129        _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
     130                            abfd, r_type);
     131        bfd_set_error (bfd_error_bad_value);
     132        return false;
     133      }
     134  
     135    bfd_reloc->howto = &bpf_elf_howto_table [i];
     136    return true;
     137  }
     138  
     139  /* Relocate an eBPF ELF section.
     140  
     141     The RELOCATE_SECTION function is called by the new ELF backend linker
     142     to handle the relocations for a section.
     143  
     144     The relocs are always passed as Rela structures; if the section
     145     actually uses Rel structures, the r_addend field will always be
     146     zero.
     147  
     148     This function is responsible for adjusting the section contents as
     149     necessary, and (if using Rela relocs and generating a relocatable
     150     output file) adjusting the reloc addend as necessary.
     151  
     152     This function does not have to worry about setting the reloc
     153     address or the reloc symbol index.
     154  
     155     LOCAL_SYMS is a pointer to the swapped in local symbols.
     156  
     157     LOCAL_SECTIONS is an array giving the section in the input file
     158     corresponding to the st_shndx field of each local symbol.
     159  
     160     The global hash table entry for the global symbols can be found
     161     via elf_sym_hashes (input_bfd).
     162  
     163     When generating relocatable output, this function must handle
     164     STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
     165     going to be the section symbol corresponding to the output
     166     section, which means that the addend must be adjusted
     167     accordingly.  */
     168  
     169  #define sec_addr(sec) ((sec)->output_section->vma + (sec)->output_offset)
     170  
     171  static int
     172  bpf_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
     173                            struct bfd_link_info *info,
     174                            bfd *input_bfd,
     175                            asection *input_section,
     176                            bfd_byte *contents,
     177                            Elf_Internal_Rela *relocs,
     178                            Elf_Internal_Sym *local_syms,
     179                            asection **local_sections)
     180  {
     181    Elf_Internal_Shdr *symtab_hdr;
     182    struct elf_link_hash_entry **sym_hashes;
     183    Elf_Internal_Rela *rel;
     184    Elf_Internal_Rela *relend;
     185  
     186    symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
     187    sym_hashes = elf_sym_hashes (input_bfd);
     188    relend     = relocs + input_section->reloc_count;
     189  
     190    for (rel = relocs; rel < relend; rel ++)
     191      {
     192        reloc_howto_type *	   howto;
     193        unsigned int		   howto_index;
     194        unsigned long		   r_symndx;
     195        Elf_Internal_Sym *	   sym;
     196        asection *		   sec;
     197        struct elf_link_hash_entry * h;
     198        bfd_vma			   relocation;
     199        bfd_reloc_status_type	   r;
     200        const char *		   name = NULL;
     201        int			   r_type ATTRIBUTE_UNUSED;
     202        bfd_signed_vma               addend;
     203        bfd_byte                   * where;
     204  
     205        r_type = ELF64_R_TYPE (rel->r_info);
     206        r_symndx = ELF64_R_SYM (rel->r_info);
     207  
     208        howto_index = bpf_index_for_rtype (ELF64_R_TYPE (rel->r_info));
     209        howto  = &bpf_elf_howto_table[howto_index];
     210        h      = NULL;
     211        sym    = NULL;
     212        sec    = NULL;
     213        where  = contents + rel->r_offset;
     214  
     215        if (r_symndx < symtab_hdr->sh_info)
     216  	{
     217  	  sym = local_syms + r_symndx;
     218  	  sec = local_sections [r_symndx];
     219  	  relocation = BASEADDR (sec) + sym->st_value;
     220  
     221  	  name = bfd_elf_string_from_elf_section
     222  	    (input_bfd, symtab_hdr->sh_link, sym->st_name);
     223  	  name = name == NULL ? bfd_section_name (sec) : name;
     224  	}
     225        else
     226  	{
     227  	  bool warned ATTRIBUTE_UNUSED;
     228  	  bool unresolved_reloc ATTRIBUTE_UNUSED;
     229  	  bool ignored ATTRIBUTE_UNUSED;
     230  
     231  	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
     232  				   r_symndx, symtab_hdr, sym_hashes,
     233  				   h, sec, relocation,
     234  				   unresolved_reloc, warned, ignored);
     235  
     236  	  name = h->root.root.string;
     237  	}
     238  
     239        if (sec != NULL && discarded_section (sec))
     240  	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
     241  					 rel, 1, relend, howto, 0, contents);
     242  
     243        if (bfd_link_relocatable (info))
     244  	continue;
     245  
     246        switch (howto->type)
     247          {
     248  	case R_BPF_64_32:
     249            {
     250              /* Make the relocation PC-relative, and change its unit to
     251                 64-bit words.  Note we need *signed* arithmetic
     252                 here.  */
     253              relocation = ((bfd_signed_vma) relocation
     254  			  - (sec_addr (input_section) + rel->r_offset));
     255              relocation = (bfd_signed_vma) relocation / 8;
     256              
     257              /* Get the addend from the instruction and apply it.  */
     258              addend = bfd_get (howto->bitsize, input_bfd,
     259                                contents + rel->r_offset
     260                                + (howto->bitsize == 16 ? 2 : 4));
     261                                
     262              if ((addend & (((~howto->src_mask) >> 1) & howto->src_mask)) != 0)
     263                addend -= (((~howto->src_mask) >> 1) & howto->src_mask) << 1;
     264              relocation += addend;
     265  
     266              /* Write out the relocated value.  */
     267              bfd_put (howto->bitsize, input_bfd, relocation,
     268                       contents + rel->r_offset
     269                       + (howto->bitsize == 16 ? 2 : 4));
     270  
     271              r = bfd_reloc_ok;
     272              break;
     273            }
     274  	case R_BPF_64_ABS64:
     275  	case R_BPF_64_ABS32:
     276  	  {
     277  	    addend = bfd_get (howto->bitsize, input_bfd, where);
     278  	    relocation += addend;
     279  	    bfd_put (howto->bitsize, input_bfd, relocation, where);
     280  
     281  	    r = bfd_reloc_ok;
     282  	    break;
     283  	  }
     284  	case R_BPF_64_64:
     285            {
     286              /*
     287                  LDDW instructions are 128 bits long, with a 64-bit immediate.
     288                  The lower 32 bits of the immediate are in the same position
     289                  as the imm32 field of other instructions.
     290                  The upper 32 bits of the immediate are stored at the end of
     291                  the instruction.
     292               */
     293  
     294  
     295              /* Get the addend. The upper and lower 32 bits are split.
     296                 'where' is the beginning of the 16-byte instruction. */
     297              addend = bfd_get_32 (input_bfd, where + 4);
     298              addend |= (bfd_get_32 (input_bfd, where + 12) << 32);
     299  
     300              relocation += addend;
     301  
     302              bfd_put_32 (input_bfd, (relocation & 0xFFFFFFFF), where + 4);
     303              bfd_put_32 (input_bfd, (relocation >> 32), where + 12);
     304              r = bfd_reloc_ok;
     305              break;
     306            }
     307          default:
     308  	  r = bfd_reloc_notsupported;
     309          }
     310  
     311        if (r == bfd_reloc_ok)
     312  	  r = bfd_check_overflow (howto->complain_on_overflow,
     313  				  howto->bitsize,
     314  				  howto->rightshift,
     315  				  64, relocation);
     316  
     317        if (r != bfd_reloc_ok)
     318  	{
     319  	  const char * msg = NULL;
     320  
     321  	  switch (r)
     322  	    {
     323  	    case bfd_reloc_overflow:
     324  	      (*info->callbacks->reloc_overflow)
     325  		(info, (h ? &h->root : NULL), name, howto->name,
     326  		 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
     327  	      break;
     328  
     329  	    case bfd_reloc_undefined:
     330  	      (*info->callbacks->undefined_symbol)
     331  		(info, name, input_bfd, input_section, rel->r_offset, true);
     332  	      break;
     333  
     334  	    case bfd_reloc_outofrange:
     335  	      msg = _("internal error: out of range error");
     336  	      break;
     337  
     338  	    case bfd_reloc_notsupported:
     339  	      if (sym != NULL) /* Only if it's not an unresolved symbol.  */
     340                  msg = _("internal error: relocation not supported");
     341  	      break;
     342  
     343  	    case bfd_reloc_dangerous:
     344  	      msg = _("internal error: dangerous relocation");
     345  	      break;
     346  
     347  	    default:
     348  	      msg = _("internal error: unknown error");
     349  	      break;
     350  	    }
     351  
     352  	  if (msg)
     353  	    (*info->callbacks->warning) (info, msg, name, input_bfd,
     354  					 input_section, rel->r_offset);
     355  	}
     356      }
     357  
     358    return true;
     359  }
     360  
     361  /* Merge backend specific data from an object file to the output
     362     object file when linking.  */
     363  
     364  static bool
     365  elf64_bpf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
     366  {
     367    /* Check if we have the same endianness.  */
     368    if (! _bfd_generic_verify_endian_match (ibfd, info))
     369      return false;
     370  
     371    return true;
     372  }
     373  
     374  /* A generic howto special function for installing BPF relocations.
     375     This function will be called by the assembler (via bfd_install_relocation),
     376     and by various get_relocated_section_contents functions.
     377     At link time, bpf_elf_relocate_section will resolve the final relocations.
     378  
     379     BPF instructions are always big endian, and this approach avoids problems in
     380     bfd_install_relocation.  */
     381  
     382  static bfd_reloc_status_type
     383  bpf_elf_generic_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
     384  		       void *data, asection *input_section,
     385  		       bfd *output_bfd ATTRIBUTE_UNUSED,
     386  		       char **error_message ATTRIBUTE_UNUSED)
     387  {
     388  
     389    bfd_signed_vma relocation;
     390    bfd_reloc_status_type status;
     391    bfd_byte *where;
     392  
     393    /* Sanity check that the address is in range.  */
     394    bfd_size_type end = bfd_get_section_limit_octets (abfd, input_section);
     395    bfd_size_type reloc_size;
     396    if (reloc_entry->howto->type == R_BPF_64_64)
     397      reloc_size = 16;
     398    else
     399      reloc_size = (reloc_entry->howto->bitsize
     400  		  + reloc_entry->howto->bitpos) / 8;
     401  
     402    if (reloc_entry->address > end
     403        || end - reloc_entry->address < reloc_size)
     404      return bfd_reloc_outofrange;
     405  
     406    /*  Get the symbol value.  */
     407    if (bfd_is_com_section (symbol->section))
     408      relocation = 0;
     409    else
     410      relocation = symbol->value;
     411  
     412    if (symbol->flags & BSF_SECTION_SYM)
     413      /* Relocation against a section symbol: add in the section base address.  */
     414      relocation += BASEADDR (symbol->section);
     415  
     416    relocation += reloc_entry->addend;
     417  
     418    where = (bfd_byte *) data + reloc_entry->address;
     419  
     420    status = bfd_check_overflow (reloc_entry->howto->complain_on_overflow,
     421  			       reloc_entry->howto->bitsize,
     422  			       reloc_entry->howto->rightshift, 64, relocation);
     423  
     424    if (status != bfd_reloc_ok)
     425      return status;
     426  
     427    /* Now finally install the relocation.  */
     428    if (reloc_entry->howto->type == R_BPF_64_64)
     429      {
     430        /* lddw is a 128-bit (!) instruction that allows loading a 64-bit
     431  	 immediate into a register. the immediate is split in half, with the
     432  	 lower 32 bits in the same position as the imm32 field of other
     433  	 instructions, and the upper 32 bits placed at the very end of the
     434  	 instruction. that is, there are 32 unused bits between them. */
     435  
     436        bfd_put_32 (abfd, (relocation & 0xFFFFFFFF), where + 4);
     437        bfd_put_32 (abfd, (relocation >> 32), where + 12);
     438      }
     439    else
     440      {
     441        /* For other kinds of relocations, the relocated value simply goes
     442  	 BITPOS bits from the start of the entry. This is always a multiple
     443  	 of 8, i.e. whole bytes.  */
     444        bfd_put (reloc_entry->howto->bitsize, abfd, relocation,
     445  	       where + reloc_entry->howto->bitpos / 8);
     446      }
     447  
     448    reloc_entry->addend = relocation;
     449    reloc_entry->address += input_section->output_offset;
     450  
     451    return bfd_reloc_ok;
     452  }
     453  
     454  
     455  /* The macros below configure the architecture.  */
     456  
     457  #define TARGET_LITTLE_SYM bpf_elf64_le_vec
     458  #define TARGET_LITTLE_NAME "elf64-bpfle"
     459  
     460  #define TARGET_BIG_SYM bpf_elf64_be_vec
     461  #define TARGET_BIG_NAME "elf64-bpfbe"
     462  
     463  #define ELF_ARCH bfd_arch_bpf
     464  #define ELF_MACHINE_CODE EM_BPF
     465  
     466  #define ELF_MAXPAGESIZE 0x100000
     467  
     468  #define elf_info_to_howto_rel bpf_info_to_howto
     469  #define elf_info_to_howto bpf_info_to_howto
     470  
     471  #define elf_backend_may_use_rel_p		1
     472  #define elf_backend_may_use_rela_p		0
     473  #define elf_backend_default_use_rela_p		0
     474  #define elf_backend_relocate_section		bpf_elf_relocate_section
     475  
     476  #define elf_backend_can_gc_sections		0
     477  
     478  #define elf_symbol_leading_char			'_'
     479  #define bfd_elf64_bfd_reloc_type_lookup		bpf_reloc_type_lookup
     480  #define bfd_elf64_bfd_reloc_name_lookup		bpf_reloc_name_lookup
     481  
     482  #define bfd_elf64_bfd_merge_private_bfd_data elf64_bpf_merge_private_bfd_data
     483  
     484  #include "elf64-target.h"