Home | History | Annotate | Line # | Download | only in bfd
elf64-bpf.c revision 1.1.1.2
      1      1.1  christos /* Linux bpf specific support for 64-bit ELF
      2  1.1.1.2  christos    Copyright (C) 2019-2022 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.1.2  christos static bfd_reloc_status_type bpf_elf_generic_reloc
     35  1.1.1.2  christos   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
     36  1.1.1.2  christos 
     37      1.1  christos /* Relocation tables.  */
     38      1.1  christos static reloc_howto_type bpf_elf_howto_table [] =
     39      1.1  christos {
     40      1.1  christos   /* This reloc does nothing.  */
     41      1.1  christos   HOWTO (R_BPF_NONE,		/* type */
     42      1.1  christos 	 0,			/* rightshift */
     43  1.1.1.2  christos 	 0,			/* size */
     44      1.1  christos 	 0,			/* bitsize */
     45  1.1.1.2  christos 	 false,			/* pc_relative */
     46      1.1  christos 	 0,			/* bitpos */
     47      1.1  christos 	 complain_overflow_dont, /* complain_on_overflow */
     48  1.1.1.2  christos 	 bpf_elf_generic_reloc, /* special_function */
     49      1.1  christos 	 "R_BPF_NONE",		/* name */
     50  1.1.1.2  christos 	 false,			/* partial_inplace */
     51      1.1  christos 	 0,			/* src_mask */
     52      1.1  christos 	 0,			/* dst_mask */
     53  1.1.1.2  christos 	 false),		/* pcrel_offset */
     54      1.1  christos 
     55      1.1  christos   /* 64-immediate in LDDW instruction.  */
     56      1.1  christos   HOWTO (R_BPF_INSN_64,		/* type */
     57      1.1  christos 	 0,			/* rightshift */
     58  1.1.1.2  christos 	 8,			/* size */
     59      1.1  christos 	 64,			/* bitsize */
     60  1.1.1.2  christos 	 false,			/* pc_relative */
     61  1.1.1.2  christos 	 32,			/* bitpos */
     62      1.1  christos 	 complain_overflow_signed, /* complain_on_overflow */
     63  1.1.1.2  christos 	 bpf_elf_generic_reloc, /* special_function */
     64      1.1  christos 	 "R_BPF_INSN_64",	/* name */
     65  1.1.1.2  christos 	 true,			/* partial_inplace */
     66  1.1.1.2  christos 	 MINUS_ONE,		/* src_mask */
     67      1.1  christos 	 MINUS_ONE,		/* dst_mask */
     68  1.1.1.2  christos 	 true),			/* pcrel_offset */
     69      1.1  christos 
     70  1.1.1.2  christos   /* 32-immediate in many instructions.  */
     71      1.1  christos   HOWTO (R_BPF_INSN_32,		/* type */
     72      1.1  christos 	 0,			/* rightshift */
     73  1.1.1.2  christos 	 4,			/* size */
     74      1.1  christos 	 32,			/* bitsize */
     75  1.1.1.2  christos 	 false,			/* pc_relative */
     76  1.1.1.2  christos 	 32,			/* bitpos */
     77      1.1  christos 	 complain_overflow_signed, /* complain_on_overflow */
     78  1.1.1.2  christos 	 bpf_elf_generic_reloc, /* special_function */
     79      1.1  christos 	 "R_BPF_INSN_32",	/* name */
     80  1.1.1.2  christos 	 true,			/* partial_inplace */
     81  1.1.1.2  christos 	 0xffffffff,		/* src_mask */
     82      1.1  christos 	 0xffffffff,		/* dst_mask */
     83  1.1.1.2  christos 	 true),			/* pcrel_offset */
     84      1.1  christos 
     85      1.1  christos   /* 16-bit offsets in instructions.  */
     86      1.1  christos   HOWTO (R_BPF_INSN_16,		/* type */
     87      1.1  christos 	 0,			/* rightshift */
     88  1.1.1.2  christos 	 2,			/* size */
     89      1.1  christos 	 16,			/* bitsize */
     90  1.1.1.2  christos 	 false,			/* pc_relative */
     91  1.1.1.2  christos 	 16,			/* bitpos */
     92      1.1  christos 	 complain_overflow_signed, /* complain_on_overflow */
     93  1.1.1.2  christos 	 bpf_elf_generic_reloc, /* special_function */
     94      1.1  christos 	 "R_BPF_INSN_16",	/* name */
     95  1.1.1.2  christos 	 true,			/* partial_inplace */
     96  1.1.1.2  christos 	 0x0000ffff,		/* src_mask */
     97      1.1  christos 	 0x0000ffff,		/* dst_mask */
     98  1.1.1.2  christos 	 true),			/* pcrel_offset */
     99      1.1  christos 
    100      1.1  christos   /* 16-bit PC-relative address in jump instructions.  */
    101      1.1  christos   HOWTO (R_BPF_INSN_DISP16,	/* type */
    102      1.1  christos 	 0,			/* rightshift */
    103  1.1.1.2  christos 	 2,			/* size */
    104      1.1  christos 	 16,			/* bitsize */
    105  1.1.1.2  christos 	 true,			/* pc_relative */
    106  1.1.1.2  christos 	 16,			/* bitpos */
    107      1.1  christos 	 complain_overflow_signed, /* complain_on_overflow */
    108  1.1.1.2  christos 	 bpf_elf_generic_reloc, /* special_function */
    109      1.1  christos 	 "R_BPF_INSN_DISP16",   /* name */
    110  1.1.1.2  christos 	 true,			/* partial_inplace */
    111      1.1  christos 	 0xffff,		/* src_mask */
    112      1.1  christos 	 0xffff,		/* dst_mask */
    113  1.1.1.2  christos 	 true),			/* pcrel_offset */
    114      1.1  christos 
    115      1.1  christos   HOWTO (R_BPF_DATA_8_PCREL,
    116      1.1  christos 	 0,			/* rightshift */
    117  1.1.1.2  christos 	 1,			/* size */
    118      1.1  christos 	 8,			/* bitsize */
    119  1.1.1.2  christos 	 true,			/* pc_relative */
    120      1.1  christos 	 0,			/* bitpos */
    121      1.1  christos 	 complain_overflow_signed, /* complain_on_overflow */
    122  1.1.1.2  christos 	 bpf_elf_generic_reloc, /* special_function */
    123      1.1  christos 	 "R_BPF_8_PCREL",	/* name */
    124  1.1.1.2  christos 	 true,			/* partial_inplace */
    125  1.1.1.2  christos 	 0xff,			/* src_mask */
    126      1.1  christos 	 0xff,			/* dst_mask */
    127  1.1.1.2  christos 	 true),			/* pcrel_offset */
    128      1.1  christos 
    129      1.1  christos   HOWTO (R_BPF_DATA_16_PCREL,
    130      1.1  christos 	 0,			/* rightshift */
    131  1.1.1.2  christos 	 2,			/* size */
    132      1.1  christos 	 16,			/* bitsize */
    133  1.1.1.2  christos 	 true,			/* pc_relative */
    134      1.1  christos 	 0,			/* bitpos */
    135      1.1  christos 	 complain_overflow_signed, /* complain_on_overflow */
    136  1.1.1.2  christos 	 bpf_elf_generic_reloc, /* special_function */
    137      1.1  christos 	 "R_BPF_16_PCREL",	/* name */
    138  1.1.1.2  christos 	 false,			/* partial_inplace */
    139  1.1.1.2  christos 	 0xffff,		/* src_mask */
    140      1.1  christos 	 0xffff,		/* dst_mask */
    141  1.1.1.2  christos 	 true),			/* pcrel_offset */
    142      1.1  christos 
    143      1.1  christos   HOWTO (R_BPF_DATA_32_PCREL,
    144      1.1  christos 	 0,			/* rightshift */
    145  1.1.1.2  christos 	 4,			/* size */
    146      1.1  christos 	 32,			/* bitsize */
    147  1.1.1.2  christos 	 true,			/* pc_relative */
    148      1.1  christos 	 0,			/* bitpos */
    149      1.1  christos 	 complain_overflow_signed, /* complain_on_overflow */
    150  1.1.1.2  christos 	 bpf_elf_generic_reloc, /* special_function */
    151      1.1  christos 	 "R_BPF_32_PCREL",	/* name */
    152  1.1.1.2  christos 	 false,			/* partial_inplace */
    153  1.1.1.2  christos 	 0xffffffff,		/* src_mask */
    154      1.1  christos 	 0xffffffff,		/* dst_mask */
    155  1.1.1.2  christos 	 true),			/* pcrel_offset */
    156      1.1  christos 
    157      1.1  christos   HOWTO (R_BPF_DATA_8,
    158      1.1  christos 	 0,			/* rightshift */
    159  1.1.1.2  christos 	 1,			/* size */
    160      1.1  christos 	 8,			/* bitsize */
    161  1.1.1.2  christos 	 false,			/* pc_relative */
    162      1.1  christos 	 0,			/* bitpos */
    163      1.1  christos 	 complain_overflow_unsigned, /* complain_on_overflow */
    164  1.1.1.2  christos 	 bpf_elf_generic_reloc, /* special_function */
    165      1.1  christos 	 "R_BPF_DATA_8",	/* name */
    166  1.1.1.2  christos 	 true,			/* partial_inplace */
    167  1.1.1.2  christos 	 0xff,			/* src_mask */
    168      1.1  christos 	 0xff,			/* dst_mask */
    169  1.1.1.2  christos 	 false),		/* pcrel_offset */
    170      1.1  christos 
    171      1.1  christos   HOWTO (R_BPF_DATA_16,
    172      1.1  christos 	 0,			/* rightshift */
    173  1.1.1.2  christos 	 2,			/* size */
    174      1.1  christos 	 16,			/* bitsize */
    175  1.1.1.2  christos 	 false,			/* pc_relative */
    176      1.1  christos 	 0,			/* bitpos */
    177      1.1  christos 	 complain_overflow_unsigned, /* complain_on_overflow */
    178  1.1.1.2  christos 	 bpf_elf_generic_reloc, /* special_function */
    179      1.1  christos 	 "R_BPF_DATA_16",	/* name */
    180  1.1.1.2  christos 	 false,			/* partial_inplace */
    181  1.1.1.2  christos 	 0xffff,		/* src_mask */
    182      1.1  christos 	 0xffff,		/* dst_mask */
    183  1.1.1.2  christos 	 false),		/* pcrel_offset */
    184      1.1  christos 
    185      1.1  christos   /* 32-bit PC-relative address in call instructions.  */
    186      1.1  christos   HOWTO (R_BPF_INSN_DISP32,	/* type */
    187      1.1  christos 	 0,			/* rightshift */
    188  1.1.1.2  christos 	 4,			/* size */
    189      1.1  christos 	 32,			/* bitsize */
    190  1.1.1.2  christos 	 true,			/* pc_relative */
    191  1.1.1.2  christos 	 32,			/* bitpos */
    192      1.1  christos 	 complain_overflow_signed, /* complain_on_overflow */
    193  1.1.1.2  christos 	 bpf_elf_generic_reloc, /* special_function */
    194      1.1  christos 	 "R_BPF_INSN_DISP32",   /* name */
    195  1.1.1.2  christos 	 true,			/* partial_inplace */
    196      1.1  christos 	 0xffffffff,		/* src_mask */
    197      1.1  christos 	 0xffffffff,		/* dst_mask */
    198  1.1.1.2  christos 	 true),			/* pcrel_offset */
    199      1.1  christos 
    200      1.1  christos   /* 32-bit data.  */
    201      1.1  christos   HOWTO (R_BPF_DATA_32,		/* type */
    202      1.1  christos 	 0,			/* rightshift */
    203  1.1.1.2  christos 	 4,			/* size */
    204      1.1  christos 	 32,			/* bitsize */
    205  1.1.1.2  christos 	 false,			/* pc_relative */
    206      1.1  christos 	 0,			/* bitpos */
    207      1.1  christos 	 complain_overflow_bitfield, /* complain_on_overflow */
    208  1.1.1.2  christos 	 bpf_elf_generic_reloc, /* special_function */
    209      1.1  christos 	 "R_BPF_DATA_32",	/* name */
    210  1.1.1.2  christos 	 false,			/* partial_inplace */
    211  1.1.1.2  christos 	 0xffffffff,		/* src_mask */
    212      1.1  christos 	 0xffffffff,		/* dst_mask */
    213  1.1.1.2  christos 	 true),			/* pcrel_offset */
    214      1.1  christos 
    215      1.1  christos   /* 64-bit data.  */
    216      1.1  christos   HOWTO (R_BPF_DATA_64,		/* type */
    217      1.1  christos 	 0,			/* rightshift */
    218  1.1.1.2  christos 	 8,			/* size */
    219      1.1  christos 	 64,			/* bitsize */
    220  1.1.1.2  christos 	 false,			/* pc_relative */
    221      1.1  christos 	 0,			/* bitpos */
    222      1.1  christos 	 complain_overflow_bitfield, /* complain_on_overflow */
    223  1.1.1.2  christos 	 bpf_elf_generic_reloc, /* special_function */
    224      1.1  christos 	 "R_BPF_DATA_64",	/* name */
    225  1.1.1.2  christos 	 false,			/* partial_inplace */
    226      1.1  christos 	 0,			/* src_mask */
    227      1.1  christos 	 MINUS_ONE,		/* dst_mask */
    228  1.1.1.2  christos 	 true),			/* pcrel_offset */
    229      1.1  christos 
    230      1.1  christos   HOWTO (R_BPF_DATA_64_PCREL,
    231      1.1  christos 	 0,			/* rightshift */
    232  1.1.1.2  christos 	 8,			/* size */
    233      1.1  christos 	 64,			/* bitsize */
    234  1.1.1.2  christos 	 true,			/* pc_relative */
    235      1.1  christos 	 0,			/* bitpos */
    236      1.1  christos 	 complain_overflow_signed, /* complain_on_overflow */
    237  1.1.1.2  christos 	 bpf_elf_generic_reloc, /* special_function */
    238      1.1  christos 	 "R_BPF_64_PCREL",	/* name */
    239  1.1.1.2  christos 	 false,			/* partial_inplace */
    240  1.1.1.2  christos 	 MINUS_ONE,		/* src_mask */
    241      1.1  christos 	 MINUS_ONE,		/* dst_mask */
    242  1.1.1.2  christos 	 true),			/* pcrel_offset */
    243      1.1  christos };
    244      1.1  christos #undef AHOW
    245      1.1  christos 
    246      1.1  christos /* Map BFD reloc types to bpf ELF reloc types.  */
    247      1.1  christos 
    248      1.1  christos static reloc_howto_type *
    249      1.1  christos bpf_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
    250      1.1  christos                         bfd_reloc_code_real_type code)
    251      1.1  christos {
    252      1.1  christos   /* Note that the bpf_elf_howto_table is indexed by the R_ constants.
    253      1.1  christos      Thus, the order that the howto records appear in the table *must*
    254      1.1  christos      match the order of the relocation types defined in
    255      1.1  christos      include/elf/bpf.h.  */
    256      1.1  christos 
    257      1.1  christos   switch (code)
    258      1.1  christos     {
    259      1.1  christos     case BFD_RELOC_NONE:
    260      1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_NONE];
    261      1.1  christos 
    262      1.1  christos     case BFD_RELOC_8_PCREL:
    263      1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_DATA_8_PCREL];
    264      1.1  christos     case BFD_RELOC_16_PCREL:
    265      1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_DATA_16_PCREL];
    266      1.1  christos     case BFD_RELOC_32_PCREL:
    267      1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_DATA_32_PCREL];
    268      1.1  christos     case BFD_RELOC_64_PCREL:
    269      1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_DATA_64_PCREL];
    270      1.1  christos 
    271      1.1  christos     case BFD_RELOC_8:
    272      1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_DATA_8];
    273      1.1  christos     case BFD_RELOC_16:
    274      1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_DATA_16];
    275      1.1  christos     case BFD_RELOC_32:
    276      1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_DATA_32];
    277      1.1  christos     case BFD_RELOC_64:
    278      1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_DATA_64];
    279      1.1  christos 
    280      1.1  christos     case BFD_RELOC_BPF_64:
    281      1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_INSN_64];
    282      1.1  christos     case BFD_RELOC_BPF_32:
    283      1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_INSN_32];
    284      1.1  christos     case BFD_RELOC_BPF_16:
    285      1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_INSN_16];
    286      1.1  christos     case BFD_RELOC_BPF_DISP16:
    287      1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_INSN_DISP16];
    288      1.1  christos     case BFD_RELOC_BPF_DISP32:
    289      1.1  christos       return &bpf_elf_howto_table[ (int) R_BPF_INSN_DISP32];
    290      1.1  christos 
    291      1.1  christos     default:
    292      1.1  christos       /* Pacify gcc -Wall.  */
    293      1.1  christos       return NULL;
    294      1.1  christos     }
    295      1.1  christos   return NULL;
    296      1.1  christos }
    297      1.1  christos 
    298      1.1  christos /* Map BFD reloc names to bpf ELF reloc names.  */
    299      1.1  christos 
    300      1.1  christos static reloc_howto_type *
    301      1.1  christos bpf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
    302      1.1  christos {
    303      1.1  christos   unsigned int i;
    304      1.1  christos 
    305      1.1  christos   for (i = 0; i < ARRAY_SIZE (bpf_elf_howto_table); i++)
    306      1.1  christos     if (bpf_elf_howto_table[i].name != NULL
    307      1.1  christos 	&& strcasecmp (bpf_elf_howto_table[i].name, r_name) == 0)
    308      1.1  christos       return &bpf_elf_howto_table[i];
    309      1.1  christos 
    310      1.1  christos   return NULL;
    311      1.1  christos }
    312      1.1  christos 
    313      1.1  christos /* Set the howto pointer for a bpf reloc.  */
    314      1.1  christos 
    315  1.1.1.2  christos static bool
    316      1.1  christos bpf_info_to_howto (bfd *abfd, arelent *bfd_reloc,
    317      1.1  christos                     Elf_Internal_Rela *elf_reloc)
    318      1.1  christos {
    319      1.1  christos   unsigned int r_type;
    320      1.1  christos 
    321      1.1  christos   r_type = ELF64_R_TYPE (elf_reloc->r_info);
    322      1.1  christos   if (r_type >= (unsigned int) R_BPF_max)
    323      1.1  christos     {
    324      1.1  christos       /* xgettext:c-format */
    325      1.1  christos       _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
    326      1.1  christos                           abfd, r_type);
    327      1.1  christos       bfd_set_error (bfd_error_bad_value);
    328  1.1.1.2  christos       return false;
    329      1.1  christos     }
    330      1.1  christos 
    331      1.1  christos   bfd_reloc->howto = &bpf_elf_howto_table [r_type];
    332  1.1.1.2  christos   return true;
    333      1.1  christos }
    334      1.1  christos 
    335      1.1  christos /* Relocate an eBPF ELF section.
    336      1.1  christos 
    337      1.1  christos    The RELOCATE_SECTION function is called by the new ELF backend linker
    338      1.1  christos    to handle the relocations for a section.
    339      1.1  christos 
    340      1.1  christos    The relocs are always passed as Rela structures; if the section
    341      1.1  christos    actually uses Rel structures, the r_addend field will always be
    342      1.1  christos    zero.
    343      1.1  christos 
    344      1.1  christos    This function is responsible for adjusting the section contents as
    345      1.1  christos    necessary, and (if using Rela relocs and generating a relocatable
    346      1.1  christos    output file) adjusting the reloc addend as necessary.
    347      1.1  christos 
    348      1.1  christos    This function does not have to worry about setting the reloc
    349      1.1  christos    address or the reloc symbol index.
    350      1.1  christos 
    351      1.1  christos    LOCAL_SYMS is a pointer to the swapped in local symbols.
    352      1.1  christos 
    353      1.1  christos    LOCAL_SECTIONS is an array giving the section in the input file
    354      1.1  christos    corresponding to the st_shndx field of each local symbol.
    355      1.1  christos 
    356      1.1  christos    The global hash table entry for the global symbols can be found
    357      1.1  christos    via elf_sym_hashes (input_bfd).
    358      1.1  christos 
    359      1.1  christos    When generating relocatable output, this function must handle
    360      1.1  christos    STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
    361      1.1  christos    going to be the section symbol corresponding to the output
    362      1.1  christos    section, which means that the addend must be adjusted
    363      1.1  christos    accordingly.  */
    364      1.1  christos 
    365      1.1  christos #define sec_addr(sec) ((sec)->output_section->vma + (sec)->output_offset)
    366      1.1  christos 
    367  1.1.1.2  christos static int
    368      1.1  christos bpf_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
    369      1.1  christos                           struct bfd_link_info *info,
    370      1.1  christos                           bfd *input_bfd,
    371      1.1  christos                           asection *input_section,
    372      1.1  christos                           bfd_byte *contents,
    373      1.1  christos                           Elf_Internal_Rela *relocs,
    374      1.1  christos                           Elf_Internal_Sym *local_syms,
    375      1.1  christos                           asection **local_sections)
    376      1.1  christos {
    377      1.1  christos   Elf_Internal_Shdr *symtab_hdr;
    378      1.1  christos   struct elf_link_hash_entry **sym_hashes;
    379      1.1  christos   Elf_Internal_Rela *rel;
    380      1.1  christos   Elf_Internal_Rela *relend;
    381      1.1  christos 
    382      1.1  christos   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
    383      1.1  christos   sym_hashes = elf_sym_hashes (input_bfd);
    384      1.1  christos   relend     = relocs + input_section->reloc_count;
    385      1.1  christos 
    386      1.1  christos   for (rel = relocs; rel < relend; rel ++)
    387      1.1  christos     {
    388      1.1  christos       reloc_howto_type *	   howto;
    389      1.1  christos       unsigned long		   r_symndx;
    390      1.1  christos       Elf_Internal_Sym *	   sym;
    391      1.1  christos       asection *		   sec;
    392      1.1  christos       struct elf_link_hash_entry * h;
    393      1.1  christos       bfd_vma			   relocation;
    394      1.1  christos       bfd_reloc_status_type	   r;
    395      1.1  christos       const char *		   name = NULL;
    396      1.1  christos       int			   r_type ATTRIBUTE_UNUSED;
    397  1.1.1.2  christos       bfd_signed_vma               addend;
    398  1.1.1.2  christos       bfd_byte                   * where;
    399      1.1  christos 
    400      1.1  christos       r_type = ELF64_R_TYPE (rel->r_info);
    401      1.1  christos       r_symndx = ELF64_R_SYM (rel->r_info);
    402      1.1  christos       howto  = bpf_elf_howto_table + ELF64_R_TYPE (rel->r_info);
    403      1.1  christos       h      = NULL;
    404      1.1  christos       sym    = NULL;
    405      1.1  christos       sec    = NULL;
    406  1.1.1.2  christos       where  = contents + rel->r_offset;
    407      1.1  christos 
    408      1.1  christos       if (r_symndx < symtab_hdr->sh_info)
    409      1.1  christos 	{
    410      1.1  christos 	  sym = local_syms + r_symndx;
    411      1.1  christos 	  sec = local_sections [r_symndx];
    412      1.1  christos 	  relocation = BASEADDR (sec) + sym->st_value;
    413      1.1  christos 
    414      1.1  christos 	  name = bfd_elf_string_from_elf_section
    415      1.1  christos 	    (input_bfd, symtab_hdr->sh_link, sym->st_name);
    416      1.1  christos 	  name = name == NULL ? bfd_section_name (sec) : name;
    417      1.1  christos 	}
    418      1.1  christos       else
    419      1.1  christos 	{
    420  1.1.1.2  christos 	  bool warned ATTRIBUTE_UNUSED;
    421  1.1.1.2  christos 	  bool unresolved_reloc ATTRIBUTE_UNUSED;
    422  1.1.1.2  christos 	  bool ignored ATTRIBUTE_UNUSED;
    423      1.1  christos 
    424      1.1  christos 	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
    425      1.1  christos 				   r_symndx, symtab_hdr, sym_hashes,
    426      1.1  christos 				   h, sec, relocation,
    427      1.1  christos 				   unresolved_reloc, warned, ignored);
    428      1.1  christos 
    429      1.1  christos 	  name = h->root.root.string;
    430      1.1  christos 	}
    431      1.1  christos 
    432      1.1  christos       if (sec != NULL && discarded_section (sec))
    433      1.1  christos 	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
    434      1.1  christos 					 rel, 1, relend, howto, 0, contents);
    435      1.1  christos 
    436      1.1  christos       if (bfd_link_relocatable (info))
    437      1.1  christos 	continue;
    438      1.1  christos 
    439      1.1  christos       switch (howto->type)
    440      1.1  christos         {
    441      1.1  christos         case R_BPF_INSN_DISP16:
    442      1.1  christos         case R_BPF_INSN_DISP32:
    443      1.1  christos           {
    444      1.1  christos             /* Make the relocation PC-relative, and change its unit to
    445  1.1.1.2  christos                64-bit words.  Note we need *signed* arithmetic
    446  1.1.1.2  christos                here.  */
    447  1.1.1.2  christos             relocation = ((bfd_signed_vma) relocation
    448  1.1.1.2  christos 			  - (sec_addr (input_section) + rel->r_offset));
    449  1.1.1.2  christos             relocation = (bfd_signed_vma) relocation / 8;
    450      1.1  christos 
    451      1.1  christos             /* Get the addend from the instruction and apply it.  */
    452      1.1  christos             addend = bfd_get (howto->bitsize, input_bfd,
    453      1.1  christos                               contents + rel->r_offset
    454      1.1  christos                               + (howto->bitsize == 16 ? 2 : 4));
    455      1.1  christos 
    456      1.1  christos             if ((addend & (((~howto->src_mask) >> 1) & howto->src_mask)) != 0)
    457      1.1  christos               addend -= (((~howto->src_mask) >> 1) & howto->src_mask) << 1;
    458      1.1  christos             relocation += addend;
    459      1.1  christos 
    460      1.1  christos             /* Write out the relocated value.  */
    461      1.1  christos             bfd_put (howto->bitsize, input_bfd, relocation,
    462      1.1  christos                      contents + rel->r_offset
    463      1.1  christos                      + (howto->bitsize == 16 ? 2 : 4));
    464      1.1  christos 
    465      1.1  christos             r = bfd_reloc_ok;
    466      1.1  christos             break;
    467      1.1  christos           }
    468  1.1.1.2  christos 	case R_BPF_DATA_8:
    469  1.1.1.2  christos 	case R_BPF_DATA_16:
    470  1.1.1.2  christos 	case R_BPF_DATA_32:
    471  1.1.1.2  christos 	case R_BPF_DATA_64:
    472  1.1.1.2  christos 	  {
    473  1.1.1.2  christos 	    addend = bfd_get (howto->bitsize, input_bfd, where);
    474  1.1.1.2  christos 	    relocation += addend;
    475  1.1.1.2  christos 	    bfd_put (howto->bitsize, input_bfd, relocation, where);
    476  1.1.1.2  christos 
    477  1.1.1.2  christos 	    r = bfd_reloc_ok;
    478  1.1.1.2  christos 	    break;
    479  1.1.1.2  christos 	  }
    480  1.1.1.2  christos 	case R_BPF_INSN_16:
    481  1.1.1.2  christos 	  {
    482  1.1.1.2  christos 
    483  1.1.1.2  christos 	    addend = bfd_get_16 (input_bfd, where + 2);
    484  1.1.1.2  christos 	    relocation += addend;
    485  1.1.1.2  christos 	    bfd_put_16 (input_bfd, relocation, where + 2);
    486  1.1.1.2  christos 
    487  1.1.1.2  christos 	    r = bfd_reloc_ok;
    488  1.1.1.2  christos 	    break;
    489  1.1.1.2  christos 	  }
    490  1.1.1.2  christos         case R_BPF_INSN_32:
    491  1.1.1.2  christos           {
    492  1.1.1.2  christos             /*  Write relocated value */
    493  1.1.1.2  christos 
    494  1.1.1.2  christos 	    addend = bfd_get_32 (input_bfd, where + 4);
    495  1.1.1.2  christos 	    relocation += addend;
    496  1.1.1.2  christos             bfd_put_32 (input_bfd, relocation, where + 4);
    497  1.1.1.2  christos 
    498  1.1.1.2  christos             r = bfd_reloc_ok;
    499  1.1.1.2  christos             break;
    500  1.1.1.2  christos           }
    501  1.1.1.2  christos         case R_BPF_INSN_64:
    502  1.1.1.2  christos           {
    503  1.1.1.2  christos             /*
    504  1.1.1.2  christos                 LDDW instructions are 128 bits long, with a 64-bit immediate.
    505  1.1.1.2  christos                 The lower 32 bits of the immediate are in the same position
    506  1.1.1.2  christos                 as the imm32 field of other instructions.
    507  1.1.1.2  christos                 The upper 32 bits of the immediate are stored at the end of
    508  1.1.1.2  christos                 the instruction.
    509  1.1.1.2  christos              */
    510  1.1.1.2  christos 
    511  1.1.1.2  christos 
    512  1.1.1.2  christos             /* Get the addend. The upper and lower 32 bits are split.
    513  1.1.1.2  christos                'where' is the beginning of the 16-byte instruction. */
    514  1.1.1.2  christos             addend = bfd_get_32 (input_bfd, where + 4);
    515  1.1.1.2  christos             addend |= (bfd_get_32 (input_bfd, where + 12) << 32);
    516  1.1.1.2  christos 
    517  1.1.1.2  christos             relocation += addend;
    518  1.1.1.2  christos 
    519  1.1.1.2  christos             bfd_put_32 (input_bfd, (relocation & 0xFFFFFFFF), where + 4);
    520  1.1.1.2  christos             bfd_put_32 (input_bfd, (relocation >> 32), where + 12);
    521  1.1.1.2  christos             r = bfd_reloc_ok;
    522  1.1.1.2  christos             break;
    523  1.1.1.2  christos           }
    524      1.1  christos         default:
    525  1.1.1.2  christos 	  r = bfd_reloc_notsupported;
    526      1.1  christos         }
    527      1.1  christos 
    528  1.1.1.2  christos       if (r == bfd_reloc_ok)
    529  1.1.1.2  christos 	  r = bfd_check_overflow (howto->complain_on_overflow,
    530  1.1.1.2  christos 				  howto->bitsize,
    531  1.1.1.2  christos 				  howto->rightshift,
    532  1.1.1.2  christos 				  64, relocation);
    533  1.1.1.2  christos 
    534      1.1  christos       if (r != bfd_reloc_ok)
    535      1.1  christos 	{
    536      1.1  christos 	  const char * msg = NULL;
    537      1.1  christos 
    538      1.1  christos 	  switch (r)
    539      1.1  christos 	    {
    540      1.1  christos 	    case bfd_reloc_overflow:
    541      1.1  christos 	      (*info->callbacks->reloc_overflow)
    542      1.1  christos 		(info, (h ? &h->root : NULL), name, howto->name,
    543      1.1  christos 		 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
    544      1.1  christos 	      break;
    545      1.1  christos 
    546      1.1  christos 	    case bfd_reloc_undefined:
    547      1.1  christos 	      (*info->callbacks->undefined_symbol)
    548  1.1.1.2  christos 		(info, name, input_bfd, input_section, rel->r_offset, true);
    549      1.1  christos 	      break;
    550      1.1  christos 
    551      1.1  christos 	    case bfd_reloc_outofrange:
    552      1.1  christos 	      msg = _("internal error: out of range error");
    553      1.1  christos 	      break;
    554      1.1  christos 
    555      1.1  christos 	    case bfd_reloc_notsupported:
    556      1.1  christos 	      if (sym != NULL) /* Only if it's not an unresolved symbol.  */
    557      1.1  christos                 msg = _("internal error: relocation not supported");
    558      1.1  christos 	      break;
    559      1.1  christos 
    560      1.1  christos 	    case bfd_reloc_dangerous:
    561      1.1  christos 	      msg = _("internal error: dangerous relocation");
    562      1.1  christos 	      break;
    563      1.1  christos 
    564      1.1  christos 	    default:
    565      1.1  christos 	      msg = _("internal error: unknown error");
    566      1.1  christos 	      break;
    567      1.1  christos 	    }
    568      1.1  christos 
    569      1.1  christos 	  if (msg)
    570      1.1  christos 	    (*info->callbacks->warning) (info, msg, name, input_bfd,
    571      1.1  christos 					 input_section, rel->r_offset);
    572      1.1  christos 	}
    573      1.1  christos     }
    574      1.1  christos 
    575  1.1.1.2  christos   return true;
    576      1.1  christos }
    577      1.1  christos 
    578      1.1  christos /* Merge backend specific data from an object file to the output
    579      1.1  christos    object file when linking.  */
    580      1.1  christos 
    581  1.1.1.2  christos static bool
    582      1.1  christos elf64_bpf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
    583      1.1  christos {
    584      1.1  christos   /* Check if we have the same endianness.  */
    585      1.1  christos   if (! _bfd_generic_verify_endian_match (ibfd, info))
    586  1.1.1.2  christos     return false;
    587      1.1  christos 
    588  1.1.1.2  christos   return true;
    589      1.1  christos }
    590      1.1  christos 
    591  1.1.1.2  christos /* A generic howto special function for installing BPF relocations.
    592  1.1.1.2  christos    This function will be called by the assembler (via bfd_install_relocation),
    593  1.1.1.2  christos    and by various get_relocated_section_contents functions.
    594  1.1.1.2  christos    At link time, bpf_elf_relocate_section will resolve the final relocations.
    595  1.1.1.2  christos 
    596  1.1.1.2  christos    BPF instructions are always big endian, and this approach avoids problems in
    597  1.1.1.2  christos    bfd_install_relocation.  */
    598  1.1.1.2  christos 
    599  1.1.1.2  christos static bfd_reloc_status_type
    600  1.1.1.2  christos bpf_elf_generic_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
    601  1.1.1.2  christos 		       void *data, asection *input_section,
    602  1.1.1.2  christos 		       bfd *output_bfd ATTRIBUTE_UNUSED,
    603  1.1.1.2  christos 		       char **error_message ATTRIBUTE_UNUSED)
    604  1.1.1.2  christos {
    605  1.1.1.2  christos 
    606  1.1.1.2  christos   bfd_signed_vma relocation;
    607  1.1.1.2  christos   bfd_reloc_status_type status;
    608  1.1.1.2  christos   bfd_byte *where;
    609  1.1.1.2  christos 
    610  1.1.1.2  christos   /* Sanity check that the address is in range.  */
    611  1.1.1.2  christos   bfd_size_type end = bfd_get_section_limit_octets (abfd, input_section);
    612  1.1.1.2  christos   bfd_size_type reloc_size;
    613  1.1.1.2  christos   if (reloc_entry->howto->type == R_BPF_INSN_64)
    614  1.1.1.2  christos     reloc_size = 16;
    615  1.1.1.2  christos   else
    616  1.1.1.2  christos     reloc_size = (reloc_entry->howto->bitsize
    617  1.1.1.2  christos 		  + reloc_entry->howto->bitpos) / 8;
    618  1.1.1.2  christos 
    619  1.1.1.2  christos   if (reloc_entry->address > end
    620  1.1.1.2  christos       || end - reloc_entry->address < reloc_size)
    621  1.1.1.2  christos     return bfd_reloc_outofrange;
    622  1.1.1.2  christos 
    623  1.1.1.2  christos   /*  Get the symbol value.  */
    624  1.1.1.2  christos   if (bfd_is_com_section (symbol->section))
    625  1.1.1.2  christos     relocation = 0;
    626  1.1.1.2  christos   else
    627  1.1.1.2  christos     relocation = symbol->value;
    628  1.1.1.2  christos 
    629  1.1.1.2  christos   if (symbol->flags & BSF_SECTION_SYM)
    630  1.1.1.2  christos     /* Relocation against a section symbol: add in the section base address.  */
    631  1.1.1.2  christos     relocation += BASEADDR (symbol->section);
    632  1.1.1.2  christos 
    633  1.1.1.2  christos   relocation += reloc_entry->addend;
    634  1.1.1.2  christos 
    635  1.1.1.2  christos   where = (bfd_byte *) data + reloc_entry->address;
    636  1.1.1.2  christos 
    637  1.1.1.2  christos   status = bfd_check_overflow (reloc_entry->howto->complain_on_overflow,
    638  1.1.1.2  christos 			       reloc_entry->howto->bitsize,
    639  1.1.1.2  christos 			       reloc_entry->howto->rightshift, 64, relocation);
    640  1.1.1.2  christos 
    641  1.1.1.2  christos   if (status != bfd_reloc_ok)
    642  1.1.1.2  christos     return status;
    643  1.1.1.2  christos 
    644  1.1.1.2  christos   /* Now finally install the relocation.  */
    645  1.1.1.2  christos   if (reloc_entry->howto->type == R_BPF_INSN_64)
    646  1.1.1.2  christos     {
    647  1.1.1.2  christos       /* lddw is a 128-bit (!) instruction that allows loading a 64-bit
    648  1.1.1.2  christos 	 immediate into a register. the immediate is split in half, with the
    649  1.1.1.2  christos 	 lower 32 bits in the same position as the imm32 field of other
    650  1.1.1.2  christos 	 instructions, and the upper 32 bits placed at the very end of the
    651  1.1.1.2  christos 	 instruction. that is, there are 32 unused bits between them. */
    652  1.1.1.2  christos 
    653  1.1.1.2  christos       bfd_put_32 (abfd, (relocation & 0xFFFFFFFF), where + 4);
    654  1.1.1.2  christos       bfd_put_32 (abfd, (relocation >> 32), where + 12);
    655  1.1.1.2  christos     }
    656  1.1.1.2  christos   else
    657  1.1.1.2  christos     {
    658  1.1.1.2  christos       /* For other kinds of relocations, the relocated value simply goes
    659  1.1.1.2  christos 	 BITPOS bits from the start of the entry. This is always a multiple
    660  1.1.1.2  christos 	 of 8, i.e. whole bytes.  */
    661  1.1.1.2  christos       bfd_put (reloc_entry->howto->bitsize, abfd, relocation,
    662  1.1.1.2  christos 	       where + reloc_entry->howto->bitpos / 8);
    663  1.1.1.2  christos     }
    664  1.1.1.2  christos 
    665  1.1.1.2  christos   reloc_entry->addend = relocation;
    666  1.1.1.2  christos   reloc_entry->address += input_section->output_offset;
    667  1.1.1.2  christos 
    668  1.1.1.2  christos   return bfd_reloc_ok;
    669  1.1.1.2  christos }
    670  1.1.1.2  christos 
    671  1.1.1.2  christos 
    672      1.1  christos /* The macros below configure the architecture.  */
    673      1.1  christos 
    674      1.1  christos #define TARGET_LITTLE_SYM bpf_elf64_le_vec
    675      1.1  christos #define TARGET_LITTLE_NAME "elf64-bpfle"
    676      1.1  christos 
    677      1.1  christos #define TARGET_BIG_SYM bpf_elf64_be_vec
    678      1.1  christos #define TARGET_BIG_NAME "elf64-bpfbe"
    679      1.1  christos 
    680      1.1  christos #define ELF_ARCH bfd_arch_bpf
    681      1.1  christos #define ELF_MACHINE_CODE EM_BPF
    682      1.1  christos 
    683      1.1  christos #define ELF_MAXPAGESIZE 0x100000
    684      1.1  christos 
    685      1.1  christos #define elf_info_to_howto_rel bpf_info_to_howto
    686      1.1  christos #define elf_info_to_howto bpf_info_to_howto
    687      1.1  christos 
    688      1.1  christos #define elf_backend_may_use_rel_p		1
    689      1.1  christos #define elf_backend_may_use_rela_p		0
    690      1.1  christos #define elf_backend_default_use_rela_p		0
    691      1.1  christos #define elf_backend_relocate_section		bpf_elf_relocate_section
    692      1.1  christos 
    693      1.1  christos #define elf_backend_can_gc_sections		0
    694      1.1  christos 
    695      1.1  christos #define elf_symbol_leading_char			'_'
    696      1.1  christos #define bfd_elf64_bfd_reloc_type_lookup		bpf_reloc_type_lookup
    697      1.1  christos #define bfd_elf64_bfd_reloc_name_lookup		bpf_reloc_name_lookup
    698      1.1  christos 
    699      1.1  christos #define bfd_elf64_bfd_merge_private_bfd_data elf64_bpf_merge_private_bfd_data
    700      1.1  christos 
    701      1.1  christos #include "elf64-target.h"
    702