Handle array- and string-like values in no-op pretty printers
[binutils-gdb.git] / bfd / elf64-bpf.c
index bf488af81f6409c996052dfaabd20d506b06cbfc..aefad7da5ac0708797f7a0d55a88199eb719e984 100644 (file)
@@ -1,5 +1,5 @@
 /* Linux bpf specific support for 64-bit ELF
-   Copyright (C) 2019-2020 Free Software Foundation, Inc.
+   Copyright (C) 2019-2023 Free Software Foundation, Inc.
    Contributed by Oracle Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
 #define BASEADDR(SEC)  ((SEC)->output_section->vma + (SEC)->output_offset)
 
+static bfd_reloc_status_type bpf_elf_generic_reloc
+  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+
+#undef BPF_HOWTO
+#define BPF_HOWTO(type, right, size, bits, pcrel, left, ovf, func, name,   \
+                 inplace, src_mask, dst_mask, pcrel_off)                  \
+       type##_IDX,
+enum bpf_reloc_index {
+  R_BPF_INVALID_IDX = -1,
+#include "bpf-reloc.def"
+  R_BPF_SIZE
+};
+#undef BPF_HOWTO
+
 /* Relocation tables.  */
+#define BPF_HOWTO(...) HOWTO(__VA_ARGS__),
 static reloc_howto_type bpf_elf_howto_table [] =
 {
-  /* This reloc does nothing.  */
-  HOWTO (R_BPF_NONE,           /* type */
-        0,                     /* rightshift */
-        3,                     /* size (0 = byte, 1 = short, 2 = long) */
-        0,                     /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_BPF_NONE",          /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
-        FALSE),                /* pcrel_offset */
-
-  /* 64-immediate in LDDW instruction.  */
-  HOWTO (R_BPF_INSN_64,                /* type */
-        0,                     /* rightshift */
-        4,                     /* size (0 = byte, 1 = short, 2 = long) */
-        64,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_BPF_INSN_64",       /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        MINUS_ONE,             /* dst_mask */
-        TRUE),                 /* pcrel_offset */
-
-  /* 32-immediate in LDDW instruction.  */
-  HOWTO (R_BPF_INSN_32,                /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_BPF_INSN_32",       /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffffffff,            /* dst_mask */
-        TRUE),                 /* pcrel_offset */
-
-  /* 16-bit offsets in instructions.  */
-  HOWTO (R_BPF_INSN_16,                /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_BPF_INSN_16",       /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0x0000ffff,            /* dst_mask */
-        TRUE),                 /* pcrel_offset */
-
-  /* 16-bit PC-relative address in jump instructions.  */
-  HOWTO (R_BPF_INSN_DISP16,    /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        32,                    /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_BPF_INSN_DISP16",   /* name */
-        FALSE,                 /* partial_inplace */
-        0xffff,                /* src_mask */
-        0xffff,                /* dst_mask */
-        TRUE),                 /* pcrel_offset */
-
-  HOWTO (R_BPF_DATA_8_PCREL,
-        0,                     /* rightshift */
-        0,                     /* size (0 = byte, 1 = short, 2 = long) */
-        8,                     /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_BPF_8_PCREL",       /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xff,                  /* dst_mask */
-        TRUE),                 /* pcrel_offset */
-
-  HOWTO (R_BPF_DATA_16_PCREL,
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_BPF_16_PCREL",      /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        TRUE),                 /* pcrel_offset */
-
-  HOWTO (R_BPF_DATA_32_PCREL,
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_BPF_32_PCREL",      /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffffffff,            /* dst_mask */
-        TRUE),                 /* pcrel_offset */
-
-  HOWTO (R_BPF_DATA_8,
-        0,                     /* rightshift */
-        0,                     /* size (0 = byte, 1 = short, 2 = long) */
-        8,                     /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_unsigned, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_BPF_DATA_8",        /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xff,                  /* dst_mask */
-        FALSE),                /* pcrel_offset */
-
-  HOWTO (R_BPF_DATA_16,
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_unsigned, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_BPF_DATA_16",       /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
-
-  /* 32-bit PC-relative address in call instructions.  */
-  HOWTO (R_BPF_INSN_DISP32,    /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_BPF_INSN_DISP32",   /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        TRUE),                 /* pcrel_offset */
-
-  /* 32-bit data.  */
-  HOWTO (R_BPF_DATA_32,                /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_BPF_DATA_32",       /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffffffff,            /* dst_mask */
-        TRUE),                 /* pcrel_offset */
-
-  /* 64-bit data.  */
-  HOWTO (R_BPF_DATA_64,                /* type */
-        0,                     /* rightshift */
-        4,                     /* size (0 = byte, 1 = short, 2 = long) */
-        64,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_BPF_DATA_64",       /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        MINUS_ONE,             /* dst_mask */
-        TRUE),                 /* pcrel_offset */
-
-  HOWTO (R_BPF_DATA_64_PCREL,
-        0,                     /* rightshift */
-        4,                     /* size (0 = byte, 1 = short, 2 = long) */
-        64,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_BPF_64_PCREL",      /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        MINUS_ONE,             /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  #include "bpf-reloc.def"
 };
 #undef AHOW
+#undef BPF_HOWTO
+
+#define BPF_HOWTO(type, right, size, bits, pcrel, left, ovf, func, name,   \
+                 inplace, src_mask, dst_mask, pcrel_off)                  \
+    case type: { return type##_IDX; }
+static enum bpf_reloc_index
+bpf_index_for_rtype(unsigned int r_type)
+{
+  switch(r_type) {
+#include "bpf-reloc.def"
+    default:
+      /* Unreachable code. */
+      BFD_ASSERT(0);
+      return -1;
+  };
+}
 
 /* Map BFD reloc types to bpf ELF reloc types.  */
 
@@ -246,44 +75,23 @@ static reloc_howto_type *
 bpf_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
                         bfd_reloc_code_real_type code)
 {
-  /* Note that the bpf_elf_howto_table is indexed by the R_ constants.
-     Thus, the order that the howto records appear in the table *must*
-     match the order of the relocation types defined in
-     include/elf/bpf.h.  */
-
   switch (code)
     {
     case BFD_RELOC_NONE:
-      return &bpf_elf_howto_table[ (int) R_BPF_NONE];
-
-    case BFD_RELOC_8_PCREL:
-      return &bpf_elf_howto_table[ (int) R_BPF_DATA_8_PCREL];
-    case BFD_RELOC_16_PCREL:
-      return &bpf_elf_howto_table[ (int) R_BPF_DATA_16_PCREL];
-    case BFD_RELOC_32_PCREL:
-      return &bpf_elf_howto_table[ (int) R_BPF_DATA_32_PCREL];
-    case BFD_RELOC_64_PCREL:
-      return &bpf_elf_howto_table[ (int) R_BPF_DATA_64_PCREL];
-
-    case BFD_RELOC_8:
-      return &bpf_elf_howto_table[ (int) R_BPF_DATA_8];
-    case BFD_RELOC_16:
-      return &bpf_elf_howto_table[ (int) R_BPF_DATA_16];
+      return &bpf_elf_howto_table[ (int) R_BPF_NONE_IDX];
+
     case BFD_RELOC_32:
-      return &bpf_elf_howto_table[ (int) R_BPF_DATA_32];
+      return &bpf_elf_howto_table[ (int) R_BPF_64_ABS32_IDX];
     case BFD_RELOC_64:
-      return &bpf_elf_howto_table[ (int) R_BPF_DATA_64];
+      return &bpf_elf_howto_table[ (int) R_BPF_64_ABS64_IDX];
 
     case BFD_RELOC_BPF_64:
-      return &bpf_elf_howto_table[ (int) R_BPF_INSN_64];
-    case BFD_RELOC_BPF_32:
-      return &bpf_elf_howto_table[ (int) R_BPF_INSN_32];
-    case BFD_RELOC_BPF_16:
-      return &bpf_elf_howto_table[ (int) R_BPF_INSN_16];
-    case BFD_RELOC_BPF_DISP16:
-      return &bpf_elf_howto_table[ (int) R_BPF_INSN_DISP16];
+      return &bpf_elf_howto_table[ (int) R_BPF_64_64_IDX];
     case BFD_RELOC_BPF_DISP32:
-      return &bpf_elf_howto_table[ (int) R_BPF_INSN_DISP32];
+    case BFD_RELOC_BPF_DISPCALL32:
+      return &bpf_elf_howto_table[ (int) R_BPF_64_32_IDX];
+    case BFD_RELOC_BPF_DISP16:
+      return &bpf_elf_howto_table[ (int) R_BPF_GNU_64_16_IDX];
 
     default:
       /* Pacify gcc -Wall.  */
@@ -299,7 +107,7 @@ bpf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
 {
   unsigned int i;
 
-  for (i = 0; i < ARRAY_SIZE (bpf_elf_howto_table); i++)
+  for (i = 0; i < R_BPF_SIZE; i++)
     if (bpf_elf_howto_table[i].name != NULL
        && strcasecmp (bpf_elf_howto_table[i].name, r_name) == 0)
       return &bpf_elf_howto_table[i];
@@ -309,24 +117,26 @@ bpf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
 
 /* Set the howto pointer for a bpf reloc.  */
 
-static bfd_boolean
+static bool
 bpf_info_to_howto (bfd *abfd, arelent *bfd_reloc,
                     Elf_Internal_Rela *elf_reloc)
 {
   unsigned int r_type;
-
+  unsigned int i;
   r_type = ELF64_R_TYPE (elf_reloc->r_info);
-  if (r_type >= (unsigned int) R_BPF_max)
+
+  i = bpf_index_for_rtype(r_type);
+  if (i == (unsigned int) -1)
     {
       /* xgettext:c-format */
       _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
                           abfd, r_type);
       bfd_set_error (bfd_error_bad_value);
-      return FALSE;
+      return false;
     }
 
-  bfd_reloc->howto = &bpf_elf_howto_table [r_type];
-  return TRUE;
+  bfd_reloc->howto = &bpf_elf_howto_table [i];
+  return true;
 }
 
 /* Relocate an eBPF ELF section.
@@ -361,7 +171,7 @@ bpf_info_to_howto (bfd *abfd, arelent *bfd_reloc,
 
 #define sec_addr(sec) ((sec)->output_section->vma + (sec)->output_offset)
 
-static bfd_boolean
+static int
 bpf_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
                           struct bfd_link_info *info,
                           bfd *input_bfd,
@@ -383,6 +193,7 @@ bpf_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
   for (rel = relocs; rel < relend; rel ++)
     {
       reloc_howto_type *          howto;
+      unsigned int                howto_index;
       unsigned long               r_symndx;
       Elf_Internal_Sym *          sym;
       asection *                  sec;
@@ -391,13 +202,18 @@ bpf_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
       bfd_reloc_status_type       r;
       const char *                name = NULL;
       int                         r_type ATTRIBUTE_UNUSED;
+      bfd_signed_vma               addend;
+      bfd_byte                   * where;
 
       r_type = ELF64_R_TYPE (rel->r_info);
       r_symndx = ELF64_R_SYM (rel->r_info);
-      howto  = bpf_elf_howto_table + ELF64_R_TYPE (rel->r_info);
+
+      howto_index = bpf_index_for_rtype (ELF64_R_TYPE (rel->r_info));
+      howto  = &bpf_elf_howto_table[howto_index];
       h      = NULL;
       sym    = NULL;
       sec    = NULL;
+      where  = contents + rel->r_offset;
 
       if (r_symndx < symtab_hdr->sh_info)
        {
@@ -411,9 +227,9 @@ bpf_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
        }
       else
        {
-         bfd_boolean warned ATTRIBUTE_UNUSED;
-         bfd_boolean unresolved_reloc ATTRIBUTE_UNUSED;
-         bfd_boolean ignored ATTRIBUTE_UNUSED;
+         bool warned ATTRIBUTE_UNUSED;
+         bool unresolved_reloc ATTRIBUTE_UNUSED;
+         bool ignored ATTRIBUTE_UNUSED;
 
          RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
                                   r_symndx, symtab_hdr, sym_hashes,
@@ -432,16 +248,14 @@ bpf_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
 
       switch (howto->type)
         {
-        case R_BPF_INSN_DISP16:
-        case R_BPF_INSN_DISP32:
+       case R_BPF_64_32:
           {
-            bfd_signed_vma addend;
-            
             /* Make the relocation PC-relative, and change its unit to
-               64-bit words.  */
-            relocation -= sec_addr (input_section) + rel->r_offset;
-            /* Make it 64-bit words.  */
-            relocation = relocation / 8;
+               64-bit words.  Note we need *signed* arithmetic
+               here.  */
+            relocation = ((bfd_signed_vma) relocation
+                         - (sec_addr (input_section) + rel->r_offset));
+            relocation = (bfd_signed_vma) relocation / 8;
             
             /* Get the addend from the instruction and apply it.  */
             addend = bfd_get (howto->bitsize, input_bfd,
@@ -460,12 +274,49 @@ bpf_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
             r = bfd_reloc_ok;
             break;
           }
+       case R_BPF_64_ABS64:
+       case R_BPF_64_ABS32:
+         {
+           addend = bfd_get (howto->bitsize, input_bfd, where);
+           relocation += addend;
+           bfd_put (howto->bitsize, input_bfd, relocation, where);
+
+           r = bfd_reloc_ok;
+           break;
+         }
+       case R_BPF_64_64:
+          {
+            /*
+                LDDW instructions are 128 bits long, with a 64-bit immediate.
+                The lower 32 bits of the immediate are in the same position
+                as the imm32 field of other instructions.
+                The upper 32 bits of the immediate are stored at the end of
+                the instruction.
+             */
+
+
+            /* Get the addend. The upper and lower 32 bits are split.
+               'where' is the beginning of the 16-byte instruction. */
+            addend = bfd_get_32 (input_bfd, where + 4);
+            addend |= (bfd_get_32 (input_bfd, where + 12) << 32);
+
+            relocation += addend;
+
+            bfd_put_32 (input_bfd, (relocation & 0xFFFFFFFF), where + 4);
+            bfd_put_32 (input_bfd, (relocation >> 32), where + 12);
+            r = bfd_reloc_ok;
+            break;
+          }
         default:
-          r = _bfd_final_link_relocate (howto, input_bfd, input_section,
-                                        contents, rel->r_offset, relocation,
-                                        rel->r_addend);
+         r = bfd_reloc_notsupported;
         }
 
+      if (r == bfd_reloc_ok)
+         r = bfd_check_overflow (howto->complain_on_overflow,
+                                 howto->bitsize,
+                                 howto->rightshift,
+                                 64, relocation);
+
       if (r != bfd_reloc_ok)
        {
          const char * msg = NULL;
@@ -480,7 +331,7 @@ bpf_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
 
            case bfd_reloc_undefined:
              (*info->callbacks->undefined_symbol)
-               (info, name, input_bfd, input_section, rel->r_offset, TRUE);
+               (info, name, input_bfd, input_section, rel->r_offset, true);
              break;
 
            case bfd_reloc_outofrange:
@@ -507,22 +358,103 @@ bpf_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
        }
     }
 
-  return TRUE;
+  return true;
 }
 
 /* Merge backend specific data from an object file to the output
    object file when linking.  */
 
-static bfd_boolean
+static bool
 elf64_bpf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
 {
   /* Check if we have the same endianness.  */
   if (! _bfd_generic_verify_endian_match (ibfd, info))
-    return FALSE;
+    return false;
 
-  return TRUE;
+  return true;
 }
 
+/* A generic howto special function for installing BPF relocations.
+   This function will be called by the assembler (via bfd_install_relocation),
+   and by various get_relocated_section_contents functions.
+   At link time, bpf_elf_relocate_section will resolve the final relocations.
+
+   BPF instructions are always big endian, and this approach avoids problems in
+   bfd_install_relocation.  */
+
+static bfd_reloc_status_type
+bpf_elf_generic_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
+                      void *data, asection *input_section,
+                      bfd *output_bfd ATTRIBUTE_UNUSED,
+                      char **error_message ATTRIBUTE_UNUSED)
+{
+
+  bfd_signed_vma relocation;
+  bfd_reloc_status_type status;
+  bfd_byte *where;
+
+  /* Sanity check that the address is in range.  */
+  bfd_size_type end = bfd_get_section_limit_octets (abfd, input_section);
+  bfd_size_type reloc_size;
+  if (reloc_entry->howto->type == R_BPF_64_64)
+    reloc_size = 16;
+  else
+    reloc_size = (reloc_entry->howto->bitsize
+                 + reloc_entry->howto->bitpos) / 8;
+
+  if (reloc_entry->address > end
+      || end - reloc_entry->address < reloc_size)
+    return bfd_reloc_outofrange;
+
+  /*  Get the symbol value.  */
+  if (bfd_is_com_section (symbol->section))
+    relocation = 0;
+  else
+    relocation = symbol->value;
+
+  if (symbol->flags & BSF_SECTION_SYM)
+    /* Relocation against a section symbol: add in the section base address.  */
+    relocation += BASEADDR (symbol->section);
+
+  relocation += reloc_entry->addend;
+
+  where = (bfd_byte *) data + reloc_entry->address;
+
+  status = bfd_check_overflow (reloc_entry->howto->complain_on_overflow,
+                              reloc_entry->howto->bitsize,
+                              reloc_entry->howto->rightshift, 64, relocation);
+
+  if (status != bfd_reloc_ok)
+    return status;
+
+  /* Now finally install the relocation.  */
+  if (reloc_entry->howto->type == R_BPF_64_64)
+    {
+      /* lddw is a 128-bit (!) instruction that allows loading a 64-bit
+        immediate into a register. the immediate is split in half, with the
+        lower 32 bits in the same position as the imm32 field of other
+        instructions, and the upper 32 bits placed at the very end of the
+        instruction. that is, there are 32 unused bits between them. */
+
+      bfd_put_32 (abfd, (relocation & 0xFFFFFFFF), where + 4);
+      bfd_put_32 (abfd, (relocation >> 32), where + 12);
+    }
+  else
+    {
+      /* For other kinds of relocations, the relocated value simply goes
+        BITPOS bits from the start of the entry. This is always a multiple
+        of 8, i.e. whole bytes.  */
+      bfd_put (reloc_entry->howto->bitsize, abfd, relocation,
+              where + reloc_entry->howto->bitpos / 8);
+    }
+
+  reloc_entry->addend = relocation;
+  reloc_entry->address += input_section->output_offset;
+
+  return bfd_reloc_ok;
+}
+
+
 /* The macros below configure the architecture.  */
 
 #define TARGET_LITTLE_SYM bpf_elf64_le_vec