1 /* Linux bpf specific support for 64-bit ELF
2 Copyright (C) 2019-2020 Free Software Foundation, Inc.
3 Contributed by Oracle Inc.
5 This file is part of BFD, the Binary File Descriptor library.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20 MA 02110-1301, USA. */
27 #include "libiberty.h"
29 /* In case we're on a 32-bit machine, construct a 64-bit "-1" value. */
30 #define MINUS_ONE (~ (bfd_vma) 0)
32 #define BASEADDR(SEC) ((SEC)->output_section->vma + (SEC)->output_offset)
34 /* Relocation tables. */
35 static reloc_howto_type bpf_elf_howto_table
[] =
37 /* This reloc does nothing. */
38 HOWTO (R_BPF_NONE
, /* type */
40 3, /* size (0 = byte, 1 = short, 2 = long) */
42 FALSE
, /* pc_relative */
44 complain_overflow_dont
, /* complain_on_overflow */
45 bfd_elf_generic_reloc
, /* special_function */
46 "R_BPF_NONE", /* name */
47 FALSE
, /* partial_inplace */
50 FALSE
), /* pcrel_offset */
52 /* 64-immediate in LDDW instruction. */
53 HOWTO (R_BPF_INSN_64
, /* type */
55 4, /* size (0 = byte, 1 = short, 2 = long) */
57 FALSE
, /* pc_relative */
59 complain_overflow_signed
, /* complain_on_overflow */
60 bfd_elf_generic_reloc
, /* special_function */
61 "R_BPF_INSN_64", /* name */
62 FALSE
, /* partial_inplace */
64 MINUS_ONE
, /* dst_mask */
65 TRUE
), /* pcrel_offset */
67 /* 32-immediate in LDDW instruction. */
68 HOWTO (R_BPF_INSN_32
, /* type */
70 2, /* size (0 = byte, 1 = short, 2 = long) */
72 FALSE
, /* pc_relative */
74 complain_overflow_signed
, /* complain_on_overflow */
75 bfd_elf_generic_reloc
, /* special_function */
76 "R_BPF_INSN_32", /* name */
77 FALSE
, /* partial_inplace */
79 0xffffffff, /* dst_mask */
80 TRUE
), /* pcrel_offset */
82 /* 16-bit offsets in instructions. */
83 HOWTO (R_BPF_INSN_16
, /* type */
85 1, /* size (0 = byte, 1 = short, 2 = long) */
87 FALSE
, /* pc_relative */
89 complain_overflow_signed
, /* complain_on_overflow */
90 bfd_elf_generic_reloc
, /* special_function */
91 "R_BPF_INSN_16", /* name */
92 FALSE
, /* partial_inplace */
94 0x0000ffff, /* dst_mask */
95 TRUE
), /* pcrel_offset */
97 /* 16-bit PC-relative address in jump instructions. */
98 HOWTO (R_BPF_INSN_DISP16
, /* type */
100 1, /* size (0 = byte, 1 = short, 2 = long) */
102 TRUE
, /* pc_relative */
104 complain_overflow_signed
, /* complain_on_overflow */
105 bfd_elf_generic_reloc
, /* special_function */
106 "R_BPF_INSN_DISP16", /* name */
107 FALSE
, /* partial_inplace */
108 0xffff, /* src_mask */
109 0xffff, /* dst_mask */
110 TRUE
), /* pcrel_offset */
112 HOWTO (R_BPF_DATA_8_PCREL
,
114 0, /* size (0 = byte, 1 = short, 2 = long) */
116 TRUE
, /* pc_relative */
118 complain_overflow_signed
, /* complain_on_overflow */
119 bfd_elf_generic_reloc
, /* special_function */
120 "R_BPF_8_PCREL", /* name */
121 FALSE
, /* partial_inplace */
124 TRUE
), /* pcrel_offset */
126 HOWTO (R_BPF_DATA_16_PCREL
,
128 1, /* size (0 = byte, 1 = short, 2 = long) */
130 TRUE
, /* pc_relative */
132 complain_overflow_signed
, /* complain_on_overflow */
133 bfd_elf_generic_reloc
, /* special_function */
134 "R_BPF_16_PCREL", /* name */
135 FALSE
, /* partial_inplace */
137 0xffff, /* dst_mask */
138 TRUE
), /* pcrel_offset */
140 HOWTO (R_BPF_DATA_32_PCREL
,
142 2, /* size (0 = byte, 1 = short, 2 = long) */
144 TRUE
, /* pc_relative */
146 complain_overflow_signed
, /* complain_on_overflow */
147 bfd_elf_generic_reloc
, /* special_function */
148 "R_BPF_32_PCREL", /* name */
149 FALSE
, /* partial_inplace */
151 0xffffffff, /* dst_mask */
152 TRUE
), /* pcrel_offset */
156 0, /* size (0 = byte, 1 = short, 2 = long) */
158 FALSE
, /* pc_relative */
160 complain_overflow_unsigned
, /* complain_on_overflow */
161 bfd_elf_generic_reloc
, /* special_function */
162 "R_BPF_DATA_8", /* name */
163 FALSE
, /* partial_inplace */
166 FALSE
), /* pcrel_offset */
168 HOWTO (R_BPF_DATA_16
,
170 1, /* size (0 = byte, 1 = short, 2 = long) */
172 FALSE
, /* pc_relative */
174 complain_overflow_unsigned
, /* complain_on_overflow */
175 bfd_elf_generic_reloc
, /* special_function */
176 "R_BPF_DATA_16", /* name */
177 FALSE
, /* partial_inplace */
179 0xffff, /* dst_mask */
180 FALSE
), /* pcrel_offset */
182 /* 32-bit PC-relative address in call instructions. */
183 HOWTO (R_BPF_INSN_DISP32
, /* type */
185 2, /* size (0 = byte, 1 = short, 2 = long) */
187 TRUE
, /* pc_relative */
189 complain_overflow_signed
, /* complain_on_overflow */
190 bfd_elf_generic_reloc
, /* special_function */
191 "R_BPF_INSN_DISP32", /* name */
192 FALSE
, /* partial_inplace */
193 0xffffffff, /* src_mask */
194 0xffffffff, /* dst_mask */
195 TRUE
), /* pcrel_offset */
198 HOWTO (R_BPF_DATA_32
, /* type */
200 2, /* size (0 = byte, 1 = short, 2 = long) */
202 FALSE
, /* pc_relative */
204 complain_overflow_bitfield
, /* complain_on_overflow */
205 bfd_elf_generic_reloc
, /* special_function */
206 "R_BPF_DATA_32", /* name */
207 FALSE
, /* partial_inplace */
209 0xffffffff, /* dst_mask */
210 TRUE
), /* pcrel_offset */
213 HOWTO (R_BPF_DATA_64
, /* type */
215 4, /* size (0 = byte, 1 = short, 2 = long) */
217 FALSE
, /* pc_relative */
219 complain_overflow_bitfield
, /* complain_on_overflow */
220 bfd_elf_generic_reloc
, /* special_function */
221 "R_BPF_DATA_64", /* name */
222 FALSE
, /* partial_inplace */
224 MINUS_ONE
, /* dst_mask */
225 TRUE
), /* pcrel_offset */
227 HOWTO (R_BPF_DATA_64_PCREL
,
229 4, /* size (0 = byte, 1 = short, 2 = long) */
231 TRUE
, /* pc_relative */
233 complain_overflow_signed
, /* complain_on_overflow */
234 bfd_elf_generic_reloc
, /* special_function */
235 "R_BPF_64_PCREL", /* name */
236 FALSE
, /* partial_inplace */
238 MINUS_ONE
, /* dst_mask */
239 TRUE
), /* pcrel_offset */
243 /* Map BFD reloc types to bpf ELF reloc types. */
245 static reloc_howto_type
*
246 bpf_reloc_type_lookup (bfd
* abfd ATTRIBUTE_UNUSED
,
247 bfd_reloc_code_real_type code
)
249 /* Note that the bpf_elf_howto_table is indexed by the R_ constants.
250 Thus, the order that the howto records appear in the table *must*
251 match the order of the relocation types defined in
252 include/elf/bpf.h. */
257 return &bpf_elf_howto_table
[ (int) R_BPF_NONE
];
259 case BFD_RELOC_8_PCREL
:
260 return &bpf_elf_howto_table
[ (int) R_BPF_DATA_8_PCREL
];
261 case BFD_RELOC_16_PCREL
:
262 return &bpf_elf_howto_table
[ (int) R_BPF_DATA_16_PCREL
];
263 case BFD_RELOC_32_PCREL
:
264 return &bpf_elf_howto_table
[ (int) R_BPF_DATA_32_PCREL
];
265 case BFD_RELOC_64_PCREL
:
266 return &bpf_elf_howto_table
[ (int) R_BPF_DATA_64_PCREL
];
269 return &bpf_elf_howto_table
[ (int) R_BPF_DATA_8
];
271 return &bpf_elf_howto_table
[ (int) R_BPF_DATA_16
];
273 return &bpf_elf_howto_table
[ (int) R_BPF_DATA_32
];
275 return &bpf_elf_howto_table
[ (int) R_BPF_DATA_64
];
277 case BFD_RELOC_BPF_64
:
278 return &bpf_elf_howto_table
[ (int) R_BPF_INSN_64
];
279 case BFD_RELOC_BPF_32
:
280 return &bpf_elf_howto_table
[ (int) R_BPF_INSN_32
];
281 case BFD_RELOC_BPF_16
:
282 return &bpf_elf_howto_table
[ (int) R_BPF_INSN_16
];
283 case BFD_RELOC_BPF_DISP16
:
284 return &bpf_elf_howto_table
[ (int) R_BPF_INSN_DISP16
];
285 case BFD_RELOC_BPF_DISP32
:
286 return &bpf_elf_howto_table
[ (int) R_BPF_INSN_DISP32
];
289 /* Pacify gcc -Wall. */
295 /* Map BFD reloc names to bpf ELF reloc names. */
297 static reloc_howto_type
*
298 bpf_reloc_name_lookup (bfd
*abfd ATTRIBUTE_UNUSED
, const char *r_name
)
302 for (i
= 0; i
< ARRAY_SIZE (bpf_elf_howto_table
); i
++)
303 if (bpf_elf_howto_table
[i
].name
!= NULL
304 && strcasecmp (bpf_elf_howto_table
[i
].name
, r_name
) == 0)
305 return &bpf_elf_howto_table
[i
];
310 /* Set the howto pointer for a bpf reloc. */
313 bpf_info_to_howto (bfd
*abfd
, arelent
*bfd_reloc
,
314 Elf_Internal_Rela
*elf_reloc
)
318 r_type
= ELF64_R_TYPE (elf_reloc
->r_info
);
319 if (r_type
>= (unsigned int) R_BPF_max
)
321 /* xgettext:c-format */
322 _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
324 bfd_set_error (bfd_error_bad_value
);
328 bfd_reloc
->howto
= &bpf_elf_howto_table
[r_type
];
332 /* Relocate an eBPF ELF section.
334 The RELOCATE_SECTION function is called by the new ELF backend linker
335 to handle the relocations for a section.
337 The relocs are always passed as Rela structures; if the section
338 actually uses Rel structures, the r_addend field will always be
341 This function is responsible for adjusting the section contents as
342 necessary, and (if using Rela relocs and generating a relocatable
343 output file) adjusting the reloc addend as necessary.
345 This function does not have to worry about setting the reloc
346 address or the reloc symbol index.
348 LOCAL_SYMS is a pointer to the swapped in local symbols.
350 LOCAL_SECTIONS is an array giving the section in the input file
351 corresponding to the st_shndx field of each local symbol.
353 The global hash table entry for the global symbols can be found
354 via elf_sym_hashes (input_bfd).
356 When generating relocatable output, this function must handle
357 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
358 going to be the section symbol corresponding to the output
359 section, which means that the addend must be adjusted
362 #define sec_addr(sec) ((sec)->output_section->vma + (sec)->output_offset)
365 bpf_elf_relocate_section (bfd
*output_bfd ATTRIBUTE_UNUSED
,
366 struct bfd_link_info
*info
,
368 asection
*input_section
,
370 Elf_Internal_Rela
*relocs
,
371 Elf_Internal_Sym
*local_syms
,
372 asection
**local_sections
)
374 Elf_Internal_Shdr
*symtab_hdr
;
375 struct elf_link_hash_entry
**sym_hashes
;
376 Elf_Internal_Rela
*rel
;
377 Elf_Internal_Rela
*relend
;
379 symtab_hdr
= & elf_tdata (input_bfd
)->symtab_hdr
;
380 sym_hashes
= elf_sym_hashes (input_bfd
);
381 relend
= relocs
+ input_section
->reloc_count
;
383 for (rel
= relocs
; rel
< relend
; rel
++)
385 reloc_howto_type
* howto
;
386 unsigned long r_symndx
;
387 Elf_Internal_Sym
* sym
;
389 struct elf_link_hash_entry
* h
;
391 bfd_reloc_status_type r
;
392 const char * name
= NULL
;
393 int r_type ATTRIBUTE_UNUSED
;
395 r_type
= ELF64_R_TYPE (rel
->r_info
);
396 r_symndx
= ELF64_R_SYM (rel
->r_info
);
397 howto
= bpf_elf_howto_table
+ ELF64_R_TYPE (rel
->r_info
);
402 if (r_symndx
< symtab_hdr
->sh_info
)
404 sym
= local_syms
+ r_symndx
;
405 sec
= local_sections
[r_symndx
];
406 relocation
= BASEADDR (sec
) + sym
->st_value
;
408 name
= bfd_elf_string_from_elf_section
409 (input_bfd
, symtab_hdr
->sh_link
, sym
->st_name
);
410 name
= name
== NULL
? bfd_section_name (sec
) : name
;
414 bfd_boolean warned ATTRIBUTE_UNUSED
;
415 bfd_boolean unresolved_reloc ATTRIBUTE_UNUSED
;
416 bfd_boolean ignored ATTRIBUTE_UNUSED
;
418 RELOC_FOR_GLOBAL_SYMBOL (info
, input_bfd
, input_section
, rel
,
419 r_symndx
, symtab_hdr
, sym_hashes
,
421 unresolved_reloc
, warned
, ignored
);
423 name
= h
->root
.root
.string
;
426 if (sec
!= NULL
&& discarded_section (sec
))
427 RELOC_AGAINST_DISCARDED_SECTION (info
, input_bfd
, input_section
,
428 rel
, 1, relend
, howto
, 0, contents
);
430 if (bfd_link_relocatable (info
))
435 case R_BPF_INSN_DISP16
:
436 case R_BPF_INSN_DISP32
:
438 bfd_signed_vma addend
;
440 /* Make the relocation PC-relative, and change its unit to
442 relocation
-= sec_addr (input_section
) + rel
->r_offset
;
443 /* Make it 64-bit words. */
444 relocation
= relocation
/ 8;
446 /* Get the addend from the instruction and apply it. */
447 addend
= bfd_get (howto
->bitsize
, input_bfd
,
448 contents
+ rel
->r_offset
449 + (howto
->bitsize
== 16 ? 2 : 4));
451 if ((addend
& (((~howto
->src_mask
) >> 1) & howto
->src_mask
)) != 0)
452 addend
-= (((~howto
->src_mask
) >> 1) & howto
->src_mask
) << 1;
453 relocation
+= addend
;
455 /* Write out the relocated value. */
456 bfd_put (howto
->bitsize
, input_bfd
, relocation
,
457 contents
+ rel
->r_offset
458 + (howto
->bitsize
== 16 ? 2 : 4));
464 r
= _bfd_final_link_relocate (howto
, input_bfd
, input_section
,
465 contents
, rel
->r_offset
, relocation
,
469 if (r
!= bfd_reloc_ok
)
471 const char * msg
= NULL
;
475 case bfd_reloc_overflow
:
476 (*info
->callbacks
->reloc_overflow
)
477 (info
, (h
? &h
->root
: NULL
), name
, howto
->name
,
478 (bfd_vma
) 0, input_bfd
, input_section
, rel
->r_offset
);
481 case bfd_reloc_undefined
:
482 (*info
->callbacks
->undefined_symbol
)
483 (info
, name
, input_bfd
, input_section
, rel
->r_offset
, TRUE
);
486 case bfd_reloc_outofrange
:
487 msg
= _("internal error: out of range error");
490 case bfd_reloc_notsupported
:
491 if (sym
!= NULL
) /* Only if it's not an unresolved symbol. */
492 msg
= _("internal error: relocation not supported");
495 case bfd_reloc_dangerous
:
496 msg
= _("internal error: dangerous relocation");
500 msg
= _("internal error: unknown error");
505 (*info
->callbacks
->warning
) (info
, msg
, name
, input_bfd
,
506 input_section
, rel
->r_offset
);
513 /* Merge backend specific data from an object file to the output
514 object file when linking. */
517 elf64_bpf_merge_private_bfd_data (bfd
*ibfd
, struct bfd_link_info
*info
)
519 /* Check if we have the same endianness. */
520 if (! _bfd_generic_verify_endian_match (ibfd
, info
))
526 /* The macros below configure the architecture. */
528 #define TARGET_LITTLE_SYM bpf_elf64_le_vec
529 #define TARGET_LITTLE_NAME "elf64-bpfle"
531 #define TARGET_BIG_SYM bpf_elf64_be_vec
532 #define TARGET_BIG_NAME "elf64-bpfbe"
534 #define ELF_ARCH bfd_arch_bpf
535 #define ELF_MACHINE_CODE EM_BPF
537 #define ELF_MAXPAGESIZE 0x100000
539 #define elf_info_to_howto_rel bpf_info_to_howto
540 #define elf_info_to_howto bpf_info_to_howto
542 #define elf_backend_may_use_rel_p 1
543 #define elf_backend_may_use_rela_p 0
544 #define elf_backend_default_use_rela_p 0
545 #define elf_backend_relocate_section bpf_elf_relocate_section
547 #define elf_backend_can_gc_sections 0
549 #define elf_symbol_leading_char '_'
550 #define bfd_elf64_bfd_reloc_type_lookup bpf_reloc_type_lookup
551 #define bfd_elf64_bfd_reloc_name_lookup bpf_reloc_name_lookup
553 #define bfd_elf64_bfd_merge_private_bfd_data elf64_bpf_merge_private_bfd_data
555 #include "elf64-target.h"