Home | History | Annotate | Line # | Download | only in bfd
elf64-bpf.c revision 1.1
      1  1.1  christos /* Linux bpf specific support for 64-bit ELF
      2  1.1  christos    Copyright (C) 2019-2020 Free Software Foundation, Inc.
      3  1.1  christos    Contributed by Oracle Inc.
      4  1.1  christos 
      5  1.1  christos    This file is part of BFD, the Binary File Descriptor library.
      6  1.1  christos 
      7  1.1  christos    This program is free software; you can redistribute it and/or modify
      8  1.1  christos    it under the terms of the GNU General Public License as published by
      9  1.1  christos    the Free Software Foundation; either version 3 of the License, or
     10  1.1  christos    (at your option) any later version.
     11  1.1  christos 
     12  1.1  christos    This program is distributed in the hope that it will be useful,
     13  1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15  1.1  christos    GNU General Public License for more details.
     16  1.1  christos 
     17  1.1  christos    You should have received a copy of the GNU General Public License
     18  1.1  christos    along with this program; if not, write to the Free Software
     19  1.1  christos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     20  1.1  christos    MA 02110-1301, USA.  */
     21  1.1  christos 
     22  1.1  christos #include "sysdep.h"
     23  1.1  christos #include "bfd.h"
     24  1.1  christos #include "libbfd.h"
     25  1.1  christos #include "elf-bfd.h"
     26  1.1  christos #include "elf/bpf.h"
     27  1.1  christos #include "libiberty.h"
     28  1.1  christos 
     29  1.1  christos /* In case we're on a 32-bit machine, construct a 64-bit "-1" value.  */
     30  1.1  christos #define MINUS_ONE (~ (bfd_vma) 0)
     31  1.1  christos 
     32  1.1  christos #define BASEADDR(SEC)	((SEC)->output_section->vma + (SEC)->output_offset)
     33  1.1  christos 
     34  1.1  christos /* Relocation tables.  */
     35  1.1  christos static reloc_howto_type bpf_elf_howto_table [] =
     36  1.1  christos {
     37  1.1  christos   /* This reloc does nothing.  */
     38  1.1  christos   HOWTO (R_BPF_NONE,		/* type */
     39  1.1  christos 	 0,			/* rightshift */
     40  1.1  christos 	 3,			/* size (0 = byte, 1 = short, 2 = long) */
     41  1.1  christos 	 0,			/* bitsize */
     42  1.1  christos 	 FALSE,			/* pc_relative */
     43  1.1  christos 	 0,			/* bitpos */
     44  1.1  christos 	 complain_overflow_dont, /* complain_on_overflow */
     45  1.1  christos 	 bfd_elf_generic_reloc, /* special_function */
     46  1.1  christos 	 "R_BPF_NONE",		/* name */
     47  1.1  christos 	 FALSE,			/* partial_inplace */
     48  1.1  christos 	 0,			/* src_mask */
     49  1.1  christos 	 0,			/* dst_mask */
     50  1.1  christos 	 FALSE),		/* pcrel_offset */
     51  1.1  christos 
     52  1.1  christos   /* 64-immediate in LDDW instruction.  */
     53  1.1  christos   HOWTO (R_BPF_INSN_64,		/* type */
     54  1.1  christos 	 0,			/* rightshift */
     55  1.1  christos 	 4,			/* size (0 = byte, 1 = short, 2 = long) */
     56  1.1  christos 	 64,			/* bitsize */
     57  1.1  christos 	 FALSE,			/* pc_relative */
     58  1.1  christos 	 0,			/* bitpos */
     59  1.1  christos 	 complain_overflow_signed, /* complain_on_overflow */
     60  1.1  christos 	 bfd_elf_generic_reloc, /* special_function */
     61  1.1  christos 	 "R_BPF_INSN_64",	/* name */
     62  1.1  christos 	 FALSE,			/* partial_inplace */
     63  1.1  christos 	 0,			/* src_mask */
     64  1.1  christos 	 MINUS_ONE,		/* dst_mask */
     65  1.1  christos 	 TRUE),			/* pcrel_offset */
     66  1.1  christos 
     67  1.1  christos   /* 32-immediate in LDDW instruction.  */
     68  1.1  christos   HOWTO (R_BPF_INSN_32,		/* type */
     69  1.1  christos 	 0,			/* rightshift */
     70  1.1  christos 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
     71  1.1  christos 	 32,			/* bitsize */
     72  1.1  christos 	 FALSE,			/* pc_relative */
     73  1.1  christos 	 0,			/* bitpos */
     74  1.1  christos 	 complain_overflow_signed, /* complain_on_overflow */
     75  1.1  christos 	 bfd_elf_generic_reloc, /* special_function */
     76  1.1  christos 	 "R_BPF_INSN_32",	/* name */
     77  1.1  christos 	 FALSE,			/* partial_inplace */
     78  1.1  christos 	 0,			/* src_mask */
     79  1.1  christos 	 0xffffffff,		/* dst_mask */
     80  1.1  christos 	 TRUE),			/* pcrel_offset */
     81  1.1  christos 
     82  1.1  christos   /* 16-bit offsets in instructions.  */
     83  1.1  christos   HOWTO (R_BPF_INSN_16,		/* type */
     84  1.1  christos 	 0,			/* rightshift */
     85  1.1  christos 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
     86  1.1  christos 	 16,			/* bitsize */
     87  1.1  christos 	 FALSE,			/* pc_relative */
     88  1.1  christos 	 0,			/* bitpos */
     89  1.1  christos 	 complain_overflow_signed, /* complain_on_overflow */
     90  1.1  christos 	 bfd_elf_generic_reloc, /* special_function */
     91  1.1  christos 	 "R_BPF_INSN_16",	/* name */
     92  1.1  christos 	 FALSE,			/* partial_inplace */
     93  1.1  christos 	 0,			/* src_mask */
     94  1.1  christos 	 0x0000ffff,		/* dst_mask */
     95  1.1  christos 	 TRUE),			/* pcrel_offset */
     96  1.1  christos 
     97  1.1  christos   /* 16-bit PC-relative address in jump instructions.  */
     98  1.1  christos   HOWTO (R_BPF_INSN_DISP16,	/* type */
     99  1.1  christos 	 0,			/* rightshift */
    100  1.1  christos 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    101  1.1  christos 	 16,			/* bitsize */
    102  1.1  christos 	 TRUE,			/* pc_relative */
    103  1.1  christos 	 32,			/* bitpos */
    104  1.1  christos 	 complain_overflow_signed, /* complain_on_overflow */
    105  1.1  christos 	 bfd_elf_generic_reloc, /* special_function */
    106  1.1  christos 	 "R_BPF_INSN_DISP16",   /* name */
    107  1.1  christos 	 FALSE,			/* partial_inplace */
    108  1.1  christos 	 0xffff,		/* src_mask */
    109  1.1  christos 	 0xffff,		/* dst_mask */
    110  1.1  christos 	 TRUE),			/* pcrel_offset */
    111  1.1  christos 
    112  1.1  christos   HOWTO (R_BPF_DATA_8_PCREL,
    113  1.1  christos 	 0,			/* rightshift */
    114  1.1  christos 	 0,			/* size (0 = byte, 1 = short, 2 = long) */
    115  1.1  christos 	 8,			/* bitsize */
    116  1.1  christos 	 TRUE,			/* pc_relative */
    117  1.1  christos 	 0,			/* bitpos */
    118  1.1  christos 	 complain_overflow_signed, /* complain_on_overflow */
    119  1.1  christos 	 bfd_elf_generic_reloc, /* special_function */
    120  1.1  christos 	 "R_BPF_8_PCREL",	/* name */
    121  1.1  christos 	 FALSE,			/* partial_inplace */
    122  1.1  christos 	 0,			/* src_mask */
    123  1.1  christos 	 0xff,			/* dst_mask */
    124  1.1  christos 	 TRUE),			/* pcrel_offset */
    125  1.1  christos 
    126  1.1  christos   HOWTO (R_BPF_DATA_16_PCREL,
    127  1.1  christos 	 0,			/* rightshift */
    128  1.1  christos 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    129  1.1  christos 	 16,			/* bitsize */
    130  1.1  christos 	 TRUE,			/* pc_relative */
    131  1.1  christos 	 0,			/* bitpos */
    132  1.1  christos 	 complain_overflow_signed, /* complain_on_overflow */
    133  1.1  christos 	 bfd_elf_generic_reloc, /* special_function */
    134  1.1  christos 	 "R_BPF_16_PCREL",	/* name */
    135  1.1  christos 	 FALSE,			/* partial_inplace */
    136  1.1  christos 	 0,			/* src_mask */
    137  1.1  christos 	 0xffff,		/* dst_mask */
    138  1.1  christos 	 TRUE),			/* pcrel_offset */
    139  1.1  christos 
    140  1.1  christos   HOWTO (R_BPF_DATA_32_PCREL,
    141  1.1  christos 	 0,			/* rightshift */
    142  1.1  christos 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
    143  1.1  christos 	 32,			/* bitsize */
    144  1.1  christos 	 TRUE,			/* pc_relative */
    145  1.1  christos 	 0,			/* bitpos */
    146  1.1  christos 	 complain_overflow_signed, /* complain_on_overflow */
    147  1.1  christos 	 bfd_elf_generic_reloc, /* special_function */
    148  1.1  christos 	 "R_BPF_32_PCREL",	/* name */
    149  1.1  christos 	 FALSE,			/* partial_inplace */
    150  1.1  christos 	 0,			/* src_mask */
    151  1.1  christos 	 0xffffffff,		/* dst_mask */
    152  1.1  christos 	 TRUE),			/* pcrel_offset */
    153  1.1  christos 
    154  1.1  christos   HOWTO (R_BPF_DATA_8,
    155  1.1  christos 	 0,			/* rightshift */
    156  1.1  christos 	 0,			/* size (0 = byte, 1 = short, 2 = long) */
    157  1.1  christos 	 8,			/* bitsize */
    158  1.1  christos 	 FALSE,			/* pc_relative */
    159  1.1  christos 	 0,			/* bitpos */
    160  1.1  christos 	 complain_overflow_unsigned, /* complain_on_overflow */
    161  1.1  christos 	 bfd_elf_generic_reloc, /* special_function */
    162  1.1  christos 	 "R_BPF_DATA_8",	/* name */
    163  1.1  christos 	 FALSE,			/* partial_inplace */
    164  1.1  christos 	 0,			/* src_mask */
    165  1.1  christos 	 0xff,			/* dst_mask */
    166  1.1  christos 	 FALSE),		/* pcrel_offset */
    167  1.1  christos 
    168  1.1  christos   HOWTO (R_BPF_DATA_16,
    169  1.1  christos 	 0,			/* rightshift */
    170  1.1  christos 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    171  1.1  christos 	 16,			/* bitsize */
    172  1.1  christos 	 FALSE,			/* pc_relative */
    173  1.1  christos 	 0,			/* bitpos */
    174  1.1  christos 	 complain_overflow_unsigned, /* complain_on_overflow */
    175  1.1  christos 	 bfd_elf_generic_reloc, /* special_function */
    176  1.1  christos 	 "R_BPF_DATA_16",	/* name */
    177  1.1  christos 	 FALSE,			/* partial_inplace */
    178  1.1  christos 	 0,			/* src_mask */
    179  1.1  christos 	 0xffff,		/* dst_mask */
    180  1.1  christos 	 FALSE),		/* pcrel_offset */
    181  1.1  christos 
    182  1.1  christos   /* 32-bit PC-relative address in call instructions.  */
    183  1.1  christos   HOWTO (R_BPF_INSN_DISP32,	/* type */
    184  1.1  christos 	 0,			/* rightshift */
    185  1.1  christos 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
    186  1.1  christos 	 32,			/* bitsize */
    187  1.1  christos 	 TRUE,			/* pc_relative */
    188  1.1  christos 	 0,			/* bitpos */
    189  1.1  christos 	 complain_overflow_signed, /* complain_on_overflow */
    190  1.1  christos 	 bfd_elf_generic_reloc, /* special_function */
    191  1.1  christos 	 "R_BPF_INSN_DISP32",   /* name */
    192  1.1  christos 	 FALSE,			/* partial_inplace */
    193  1.1  christos 	 0xffffffff,		/* src_mask */
    194  1.1  christos 	 0xffffffff,		/* dst_mask */
    195  1.1  christos 	 TRUE),			/* pcrel_offset */
    196  1.1  christos 
    197  1.1  christos   /* 32-bit data.  */
    198  1.1  christos   HOWTO (R_BPF_DATA_32,		/* type */
    199  1.1  christos 	 0,			/* rightshift */
    200  1.1  christos 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
    201  1.1  christos 	 32,			/* bitsize */
    202  1.1  christos 	 FALSE,			/* pc_relative */
    203  1.1  christos 	 0,			/* bitpos */
    204  1.1  christos 	 complain_overflow_bitfield, /* complain_on_overflow */
    205  1.1  christos 	 bfd_elf_generic_reloc, /* special_function */
    206  1.1  christos 	 "R_BPF_DATA_32",	/* name */
    207  1.1  christos 	 FALSE,			/* partial_inplace */
    208  1.1  christos 	 0,			/* src_mask */
    209  1.1  christos 	 0xffffffff,		/* dst_mask */
    210  1.1  christos 	 TRUE),			/* pcrel_offset */
    211  1.1  christos 
    212  1.1  christos   /* 64-bit data.  */
    213  1.1  christos   HOWTO (R_BPF_DATA_64,		/* type */
    214  1.1  christos 	 0,			/* rightshift */
    215  1.1  christos 	 4,			/* size (0 = byte, 1 = short, 2 = long) */
    216  1.1  christos 	 64,			/* bitsize */
    217  1.1  christos 	 FALSE,			/* pc_relative */
    218  1.1  christos 	 0,			/* bitpos */
    219  1.1  christos 	 complain_overflow_bitfield, /* complain_on_overflow */
    220  1.1  christos 	 bfd_elf_generic_reloc, /* special_function */
    221  1.1  christos 	 "R_BPF_DATA_64",	/* name */
    222  1.1  christos 	 FALSE,			/* partial_inplace */
    223  1.1  christos 	 0,			/* src_mask */
    224  1.1  christos 	 MINUS_ONE,		/* dst_mask */
    225  1.1  christos 	 TRUE),			/* pcrel_offset */
    226  1.1  christos 
    227  1.1  christos   HOWTO (R_BPF_DATA_64_PCREL,
    228  1.1  christos 	 0,			/* rightshift */
    229  1.1  christos 	 4,			/* size (0 = byte, 1 = short, 2 = long) */
    230  1.1  christos 	 64,			/* bitsize */
    231  1.1  christos 	 TRUE,			/* pc_relative */
    232  1.1  christos 	 0,			/* bitpos */
    233  1.1  christos 	 complain_overflow_signed, /* complain_on_overflow */
    234  1.1  christos 	 bfd_elf_generic_reloc, /* special_function */
    235  1.1  christos 	 "R_BPF_64_PCREL",	/* name */
    236  1.1  christos 	 FALSE,			/* partial_inplace */
    237  1.1  christos 	 0,			/* src_mask */
    238  1.1  christos 	 MINUS_ONE,		/* dst_mask */
    239  1.1  christos 	 TRUE),			/* pcrel_offset */
    240  1.1  christos };
    241  1.1  christos #undef AHOW
    242  1.1  christos 
    243  1.1  christos /* Map BFD reloc types to bpf ELF reloc types.  */
    244  1.1  christos 
    245  1.1  christos static reloc_howto_type *
    246  1.1  christos bpf_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
    247  1.1  christos                         bfd_reloc_code_real_type code)
    248  1.1  christos {
    249  1.1  christos   /* Note that the bpf_elf_howto_table is indexed by the R_ constants.
    250  1.1  christos      Thus, the order that the howto records appear in the table *must*
    251  1.1  christos      match the order of the relocation types defined in
    252  1.1  christos      include/elf/bpf.h.  */
    253  1.1  christos 
    254  1.1  christos   switch (code)
    255  1.1  christos     {
    256  1.1  christos     case BFD_RELOC_NONE:
    257  1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_NONE];
    258  1.1  christos 
    259  1.1  christos     case BFD_RELOC_8_PCREL:
    260  1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_DATA_8_PCREL];
    261  1.1  christos     case BFD_RELOC_16_PCREL:
    262  1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_DATA_16_PCREL];
    263  1.1  christos     case BFD_RELOC_32_PCREL:
    264  1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_DATA_32_PCREL];
    265  1.1  christos     case BFD_RELOC_64_PCREL:
    266  1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_DATA_64_PCREL];
    267  1.1  christos 
    268  1.1  christos     case BFD_RELOC_8:
    269  1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_DATA_8];
    270  1.1  christos     case BFD_RELOC_16:
    271  1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_DATA_16];
    272  1.1  christos     case BFD_RELOC_32:
    273  1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_DATA_32];
    274  1.1  christos     case BFD_RELOC_64:
    275  1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_DATA_64];
    276  1.1  christos 
    277  1.1  christos     case BFD_RELOC_BPF_64:
    278  1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_INSN_64];
    279  1.1  christos     case BFD_RELOC_BPF_32:
    280  1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_INSN_32];
    281  1.1  christos     case BFD_RELOC_BPF_16:
    282  1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_INSN_16];
    283  1.1  christos     case BFD_RELOC_BPF_DISP16:
    284  1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_INSN_DISP16];
    285  1.1  christos     case BFD_RELOC_BPF_DISP32:
    286  1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_INSN_DISP32];
    287  1.1  christos 
    288  1.1  christos     default:
    289  1.1  christos       /* Pacify gcc -Wall.  */
    290  1.1  christos       return NULL;
    291  1.1  christos     }
    292  1.1  christos   return NULL;
    293  1.1  christos }
    294  1.1  christos 
    295  1.1  christos /* Map BFD reloc names to bpf ELF reloc names.  */
    296  1.1  christos 
    297  1.1  christos static reloc_howto_type *
    298  1.1  christos bpf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
    299  1.1  christos {
    300  1.1  christos   unsigned int i;
    301  1.1  christos 
    302  1.1  christos   for (i = 0; i < ARRAY_SIZE (bpf_elf_howto_table); i++)
    303  1.1  christos     if (bpf_elf_howto_table[i].name != NULL
    304  1.1  christos 	&& strcasecmp (bpf_elf_howto_table[i].name, r_name) == 0)
    305  1.1  christos       return &bpf_elf_howto_table[i];
    306  1.1  christos 
    307  1.1  christos   return NULL;
    308  1.1  christos }
    309  1.1  christos 
    310  1.1  christos /* Set the howto pointer for a bpf reloc.  */
    311  1.1  christos 
    312  1.1  christos static bfd_boolean
    313  1.1  christos bpf_info_to_howto (bfd *abfd, arelent *bfd_reloc,
    314  1.1  christos                     Elf_Internal_Rela *elf_reloc)
    315  1.1  christos {
    316  1.1  christos   unsigned int r_type;
    317  1.1  christos 
    318  1.1  christos   r_type = ELF64_R_TYPE (elf_reloc->r_info);
    319  1.1  christos   if (r_type >= (unsigned int) R_BPF_max)
    320  1.1  christos     {
    321  1.1  christos       /* xgettext:c-format */
    322  1.1  christos       _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
    323  1.1  christos                           abfd, r_type);
    324  1.1  christos       bfd_set_error (bfd_error_bad_value);
    325  1.1  christos       return FALSE;
    326  1.1  christos     }
    327  1.1  christos 
    328  1.1  christos   bfd_reloc->howto = &bpf_elf_howto_table [r_type];
    329  1.1  christos   return TRUE;
    330  1.1  christos }
    331  1.1  christos 
    332  1.1  christos /* Relocate an eBPF ELF section.
    333  1.1  christos 
    334  1.1  christos    The RELOCATE_SECTION function is called by the new ELF backend linker
    335  1.1  christos    to handle the relocations for a section.
    336  1.1  christos 
    337  1.1  christos    The relocs are always passed as Rela structures; if the section
    338  1.1  christos    actually uses Rel structures, the r_addend field will always be
    339  1.1  christos    zero.
    340  1.1  christos 
    341  1.1  christos    This function is responsible for adjusting the section contents as
    342  1.1  christos    necessary, and (if using Rela relocs and generating a relocatable
    343  1.1  christos    output file) adjusting the reloc addend as necessary.
    344  1.1  christos 
    345  1.1  christos    This function does not have to worry about setting the reloc
    346  1.1  christos    address or the reloc symbol index.
    347  1.1  christos 
    348  1.1  christos    LOCAL_SYMS is a pointer to the swapped in local symbols.
    349  1.1  christos 
    350  1.1  christos    LOCAL_SECTIONS is an array giving the section in the input file
    351  1.1  christos    corresponding to the st_shndx field of each local symbol.
    352  1.1  christos 
    353  1.1  christos    The global hash table entry for the global symbols can be found
    354  1.1  christos    via elf_sym_hashes (input_bfd).
    355  1.1  christos 
    356  1.1  christos    When generating relocatable output, this function must handle
    357  1.1  christos    STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
    358  1.1  christos    going to be the section symbol corresponding to the output
    359  1.1  christos    section, which means that the addend must be adjusted
    360  1.1  christos    accordingly.  */
    361  1.1  christos 
    362  1.1  christos #define sec_addr(sec) ((sec)->output_section->vma + (sec)->output_offset)
    363  1.1  christos 
    364  1.1  christos static bfd_boolean
    365  1.1  christos bpf_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
    366  1.1  christos                           struct bfd_link_info *info,
    367  1.1  christos                           bfd *input_bfd,
    368  1.1  christos                           asection *input_section,
    369  1.1  christos                           bfd_byte *contents,
    370  1.1  christos                           Elf_Internal_Rela *relocs,
    371  1.1  christos                           Elf_Internal_Sym *local_syms,
    372  1.1  christos                           asection **local_sections)
    373  1.1  christos {
    374  1.1  christos   Elf_Internal_Shdr *symtab_hdr;
    375  1.1  christos   struct elf_link_hash_entry **sym_hashes;
    376  1.1  christos   Elf_Internal_Rela *rel;
    377  1.1  christos   Elf_Internal_Rela *relend;
    378  1.1  christos 
    379  1.1  christos   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
    380  1.1  christos   sym_hashes = elf_sym_hashes (input_bfd);
    381  1.1  christos   relend     = relocs + input_section->reloc_count;
    382  1.1  christos 
    383  1.1  christos   for (rel = relocs; rel < relend; rel ++)
    384  1.1  christos     {
    385  1.1  christos       reloc_howto_type *	   howto;
    386  1.1  christos       unsigned long		   r_symndx;
    387  1.1  christos       Elf_Internal_Sym *	   sym;
    388  1.1  christos       asection *		   sec;
    389  1.1  christos       struct elf_link_hash_entry * h;
    390  1.1  christos       bfd_vma			   relocation;
    391  1.1  christos       bfd_reloc_status_type	   r;
    392  1.1  christos       const char *		   name = NULL;
    393  1.1  christos       int			   r_type ATTRIBUTE_UNUSED;
    394  1.1  christos 
    395  1.1  christos       r_type = ELF64_R_TYPE (rel->r_info);
    396  1.1  christos       r_symndx = ELF64_R_SYM (rel->r_info);
    397  1.1  christos       howto  = bpf_elf_howto_table + ELF64_R_TYPE (rel->r_info);
    398  1.1  christos       h      = NULL;
    399  1.1  christos       sym    = NULL;
    400  1.1  christos       sec    = NULL;
    401  1.1  christos 
    402  1.1  christos       if (r_symndx < symtab_hdr->sh_info)
    403  1.1  christos 	{
    404  1.1  christos 	  sym = local_syms + r_symndx;
    405  1.1  christos 	  sec = local_sections [r_symndx];
    406  1.1  christos 	  relocation = BASEADDR (sec) + sym->st_value;
    407  1.1  christos 
    408  1.1  christos 	  name = bfd_elf_string_from_elf_section
    409  1.1  christos 	    (input_bfd, symtab_hdr->sh_link, sym->st_name);
    410  1.1  christos 	  name = name == NULL ? bfd_section_name (sec) : name;
    411  1.1  christos 	}
    412  1.1  christos       else
    413  1.1  christos 	{
    414  1.1  christos 	  bfd_boolean warned ATTRIBUTE_UNUSED;
    415  1.1  christos 	  bfd_boolean unresolved_reloc ATTRIBUTE_UNUSED;
    416  1.1  christos 	  bfd_boolean ignored ATTRIBUTE_UNUSED;
    417  1.1  christos 
    418  1.1  christos 	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
    419  1.1  christos 				   r_symndx, symtab_hdr, sym_hashes,
    420  1.1  christos 				   h, sec, relocation,
    421  1.1  christos 				   unresolved_reloc, warned, ignored);
    422  1.1  christos 
    423  1.1  christos 	  name = h->root.root.string;
    424  1.1  christos 	}
    425  1.1  christos 
    426  1.1  christos       if (sec != NULL && discarded_section (sec))
    427  1.1  christos 	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
    428  1.1  christos 					 rel, 1, relend, howto, 0, contents);
    429  1.1  christos 
    430  1.1  christos       if (bfd_link_relocatable (info))
    431  1.1  christos 	continue;
    432  1.1  christos 
    433  1.1  christos       switch (howto->type)
    434  1.1  christos         {
    435  1.1  christos         case R_BPF_INSN_DISP16:
    436  1.1  christos         case R_BPF_INSN_DISP32:
    437  1.1  christos           {
    438  1.1  christos             bfd_signed_vma addend;
    439  1.1  christos 
    440  1.1  christos             /* Make the relocation PC-relative, and change its unit to
    441  1.1  christos                64-bit words.  */
    442  1.1  christos             relocation -= sec_addr (input_section) + rel->r_offset;
    443  1.1  christos             /* Make it 64-bit words.  */
    444  1.1  christos             relocation = relocation / 8;
    445  1.1  christos 
    446  1.1  christos             /* Get the addend from the instruction and apply it.  */
    447  1.1  christos             addend = bfd_get (howto->bitsize, input_bfd,
    448  1.1  christos                               contents + rel->r_offset
    449  1.1  christos                               + (howto->bitsize == 16 ? 2 : 4));
    450  1.1  christos 
    451  1.1  christos             if ((addend & (((~howto->src_mask) >> 1) & howto->src_mask)) != 0)
    452  1.1  christos               addend -= (((~howto->src_mask) >> 1) & howto->src_mask) << 1;
    453  1.1  christos             relocation += addend;
    454  1.1  christos 
    455  1.1  christos             /* Write out the relocated value.  */
    456  1.1  christos             bfd_put (howto->bitsize, input_bfd, relocation,
    457  1.1  christos                      contents + rel->r_offset
    458  1.1  christos                      + (howto->bitsize == 16 ? 2 : 4));
    459  1.1  christos 
    460  1.1  christos             r = bfd_reloc_ok;
    461  1.1  christos             break;
    462  1.1  christos           }
    463  1.1  christos         default:
    464  1.1  christos           r = _bfd_final_link_relocate (howto, input_bfd, input_section,
    465  1.1  christos                                         contents, rel->r_offset, relocation,
    466  1.1  christos                                         rel->r_addend);
    467  1.1  christos         }
    468  1.1  christos 
    469  1.1  christos       if (r != bfd_reloc_ok)
    470  1.1  christos 	{
    471  1.1  christos 	  const char * msg = NULL;
    472  1.1  christos 
    473  1.1  christos 	  switch (r)
    474  1.1  christos 	    {
    475  1.1  christos 	    case bfd_reloc_overflow:
    476  1.1  christos 	      (*info->callbacks->reloc_overflow)
    477  1.1  christos 		(info, (h ? &h->root : NULL), name, howto->name,
    478  1.1  christos 		 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
    479  1.1  christos 	      break;
    480  1.1  christos 
    481  1.1  christos 	    case bfd_reloc_undefined:
    482  1.1  christos 	      (*info->callbacks->undefined_symbol)
    483  1.1  christos 		(info, name, input_bfd, input_section, rel->r_offset, TRUE);
    484  1.1  christos 	      break;
    485  1.1  christos 
    486  1.1  christos 	    case bfd_reloc_outofrange:
    487  1.1  christos 	      msg = _("internal error: out of range error");
    488  1.1  christos 	      break;
    489  1.1  christos 
    490  1.1  christos 	    case bfd_reloc_notsupported:
    491  1.1  christos 	      if (sym != NULL) /* Only if it's not an unresolved symbol.  */
    492  1.1  christos                 msg = _("internal error: relocation not supported");
    493  1.1  christos 	      break;
    494  1.1  christos 
    495  1.1  christos 	    case bfd_reloc_dangerous:
    496  1.1  christos 	      msg = _("internal error: dangerous relocation");
    497  1.1  christos 	      break;
    498  1.1  christos 
    499  1.1  christos 	    default:
    500  1.1  christos 	      msg = _("internal error: unknown error");
    501  1.1  christos 	      break;
    502  1.1  christos 	    }
    503  1.1  christos 
    504  1.1  christos 	  if (msg)
    505  1.1  christos 	    (*info->callbacks->warning) (info, msg, name, input_bfd,
    506  1.1  christos 					 input_section, rel->r_offset);
    507  1.1  christos 	}
    508  1.1  christos     }
    509  1.1  christos 
    510  1.1  christos   return TRUE;
    511  1.1  christos }
    512  1.1  christos 
    513  1.1  christos /* Merge backend specific data from an object file to the output
    514  1.1  christos    object file when linking.  */
    515  1.1  christos 
    516  1.1  christos static bfd_boolean
    517  1.1  christos elf64_bpf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
    518  1.1  christos {
    519  1.1  christos   /* Check if we have the same endianness.  */
    520  1.1  christos   if (! _bfd_generic_verify_endian_match (ibfd, info))
    521  1.1  christos     return FALSE;
    522  1.1  christos 
    523  1.1  christos   return TRUE;
    524  1.1  christos }
    525  1.1  christos 
    526  1.1  christos /* The macros below configure the architecture.  */
    527  1.1  christos 
    528  1.1  christos #define TARGET_LITTLE_SYM bpf_elf64_le_vec
    529  1.1  christos #define TARGET_LITTLE_NAME "elf64-bpfle"
    530  1.1  christos 
    531  1.1  christos #define TARGET_BIG_SYM bpf_elf64_be_vec
    532  1.1  christos #define TARGET_BIG_NAME "elf64-bpfbe"
    533  1.1  christos 
    534  1.1  christos #define ELF_ARCH bfd_arch_bpf
    535  1.1  christos #define ELF_MACHINE_CODE EM_BPF
    536  1.1  christos 
    537  1.1  christos #define ELF_MAXPAGESIZE 0x100000
    538  1.1  christos 
    539  1.1  christos #define elf_info_to_howto_rel bpf_info_to_howto
    540  1.1  christos #define elf_info_to_howto bpf_info_to_howto
    541  1.1  christos 
    542  1.1  christos #define elf_backend_may_use_rel_p		1
    543  1.1  christos #define elf_backend_may_use_rela_p		0
    544  1.1  christos #define elf_backend_default_use_rela_p		0
    545  1.1  christos #define elf_backend_relocate_section		bpf_elf_relocate_section
    546  1.1  christos 
    547  1.1  christos #define elf_backend_can_gc_sections		0
    548  1.1  christos 
    549  1.1  christos #define elf_symbol_leading_char			'_'
    550  1.1  christos #define bfd_elf64_bfd_reloc_type_lookup		bpf_reloc_type_lookup
    551  1.1  christos #define bfd_elf64_bfd_reloc_name_lookup		bpf_reloc_name_lookup
    552  1.1  christos 
    553  1.1  christos #define bfd_elf64_bfd_merge_private_bfd_data elf64_bpf_merge_private_bfd_data
    554  1.1  christos 
    555  1.1  christos #include "elf64-target.h"
    556