1 /* Linux bpf specific support for 64-bit ELF
2 Copyright (C) 2019-2023 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 static bfd_reloc_status_type bpf_elf_generic_reloc
35 (bfd
*, arelent
*, asymbol
*, void *, asection
*, bfd
*, char **);
37 /* Relocation tables. */
38 static reloc_howto_type bpf_elf_howto_table
[] =
40 /* This reloc does nothing. */
41 HOWTO (R_BPF_NONE
, /* type */
45 false, /* pc_relative */
47 complain_overflow_dont
, /* complain_on_overflow */
48 bpf_elf_generic_reloc
, /* special_function */
49 "R_BPF_NONE", /* name */
50 false, /* partial_inplace */
53 false), /* pcrel_offset */
55 /* 64-immediate in LDDW instruction. */
56 HOWTO (R_BPF_INSN_64
, /* type */
60 false, /* pc_relative */
62 complain_overflow_signed
, /* complain_on_overflow */
63 bpf_elf_generic_reloc
, /* special_function */
64 "R_BPF_INSN_64", /* name */
65 true, /* partial_inplace */
66 MINUS_ONE
, /* src_mask */
67 MINUS_ONE
, /* dst_mask */
68 true), /* pcrel_offset */
70 /* 32-immediate in many instructions. */
71 HOWTO (R_BPF_INSN_32
, /* type */
75 false, /* pc_relative */
77 complain_overflow_signed
, /* complain_on_overflow */
78 bpf_elf_generic_reloc
, /* special_function */
79 "R_BPF_INSN_32", /* name */
80 true, /* partial_inplace */
81 0xffffffff, /* src_mask */
82 0xffffffff, /* dst_mask */
83 true), /* pcrel_offset */
85 /* 16-bit offsets in instructions. */
86 HOWTO (R_BPF_INSN_16
, /* type */
90 false, /* pc_relative */
92 complain_overflow_signed
, /* complain_on_overflow */
93 bpf_elf_generic_reloc
, /* special_function */
94 "R_BPF_INSN_16", /* name */
95 true, /* partial_inplace */
96 0x0000ffff, /* src_mask */
97 0x0000ffff, /* dst_mask */
98 true), /* pcrel_offset */
100 /* 16-bit PC-relative address in jump instructions. */
101 HOWTO (R_BPF_INSN_DISP16
, /* type */
105 true, /* pc_relative */
107 complain_overflow_signed
, /* complain_on_overflow */
108 bpf_elf_generic_reloc
, /* special_function */
109 "R_BPF_INSN_DISP16", /* name */
110 true, /* partial_inplace */
111 0xffff, /* src_mask */
112 0xffff, /* dst_mask */
113 true), /* pcrel_offset */
115 HOWTO (R_BPF_DATA_8_PCREL
,
119 true, /* pc_relative */
121 complain_overflow_signed
, /* complain_on_overflow */
122 bpf_elf_generic_reloc
, /* special_function */
123 "R_BPF_8_PCREL", /* name */
124 true, /* partial_inplace */
127 true), /* pcrel_offset */
129 HOWTO (R_BPF_DATA_16_PCREL
,
133 true, /* pc_relative */
135 complain_overflow_signed
, /* complain_on_overflow */
136 bpf_elf_generic_reloc
, /* special_function */
137 "R_BPF_16_PCREL", /* name */
138 false, /* partial_inplace */
139 0xffff, /* src_mask */
140 0xffff, /* dst_mask */
141 true), /* pcrel_offset */
143 HOWTO (R_BPF_DATA_32_PCREL
,
147 true, /* pc_relative */
149 complain_overflow_signed
, /* complain_on_overflow */
150 bpf_elf_generic_reloc
, /* special_function */
151 "R_BPF_32_PCREL", /* name */
152 false, /* partial_inplace */
153 0xffffffff, /* src_mask */
154 0xffffffff, /* dst_mask */
155 true), /* pcrel_offset */
161 false, /* pc_relative */
163 complain_overflow_unsigned
, /* complain_on_overflow */
164 bpf_elf_generic_reloc
, /* special_function */
165 "R_BPF_DATA_8", /* name */
166 true, /* partial_inplace */
169 false), /* pcrel_offset */
171 HOWTO (R_BPF_DATA_16
,
175 false, /* pc_relative */
177 complain_overflow_unsigned
, /* complain_on_overflow */
178 bpf_elf_generic_reloc
, /* special_function */
179 "R_BPF_DATA_16", /* name */
180 false, /* partial_inplace */
181 0xffff, /* src_mask */
182 0xffff, /* dst_mask */
183 false), /* pcrel_offset */
185 /* 32-bit PC-relative address in call instructions. */
186 HOWTO (R_BPF_INSN_DISP32
, /* type */
190 true, /* pc_relative */
192 complain_overflow_signed
, /* complain_on_overflow */
193 bpf_elf_generic_reloc
, /* special_function */
194 "R_BPF_INSN_DISP32", /* name */
195 true, /* partial_inplace */
196 0xffffffff, /* src_mask */
197 0xffffffff, /* dst_mask */
198 true), /* pcrel_offset */
201 HOWTO (R_BPF_DATA_32
, /* type */
205 false, /* pc_relative */
207 complain_overflow_bitfield
, /* complain_on_overflow */
208 bpf_elf_generic_reloc
, /* special_function */
209 "R_BPF_DATA_32", /* name */
210 false, /* partial_inplace */
211 0xffffffff, /* src_mask */
212 0xffffffff, /* dst_mask */
213 true), /* pcrel_offset */
216 HOWTO (R_BPF_DATA_64
, /* type */
220 false, /* pc_relative */
222 complain_overflow_bitfield
, /* complain_on_overflow */
223 bpf_elf_generic_reloc
, /* special_function */
224 "R_BPF_DATA_64", /* name */
225 false, /* partial_inplace */
227 MINUS_ONE
, /* dst_mask */
228 true), /* pcrel_offset */
230 HOWTO (R_BPF_DATA_64_PCREL
,
234 true, /* pc_relative */
236 complain_overflow_signed
, /* complain_on_overflow */
237 bpf_elf_generic_reloc
, /* special_function */
238 "R_BPF_64_PCREL", /* name */
239 false, /* partial_inplace */
240 MINUS_ONE
, /* src_mask */
241 MINUS_ONE
, /* dst_mask */
242 true), /* pcrel_offset */
246 /* Map BFD reloc types to bpf ELF reloc types. */
248 static reloc_howto_type
*
249 bpf_reloc_type_lookup (bfd
* abfd ATTRIBUTE_UNUSED
,
250 bfd_reloc_code_real_type code
)
252 /* Note that the bpf_elf_howto_table is indexed by the R_ constants.
253 Thus, the order that the howto records appear in the table *must*
254 match the order of the relocation types defined in
255 include/elf/bpf.h. */
260 return &bpf_elf_howto_table
[ (int) R_BPF_NONE
];
262 case BFD_RELOC_8_PCREL
:
263 return &bpf_elf_howto_table
[ (int) R_BPF_DATA_8_PCREL
];
264 case BFD_RELOC_16_PCREL
:
265 return &bpf_elf_howto_table
[ (int) R_BPF_DATA_16_PCREL
];
266 case BFD_RELOC_32_PCREL
:
267 return &bpf_elf_howto_table
[ (int) R_BPF_DATA_32_PCREL
];
268 case BFD_RELOC_64_PCREL
:
269 return &bpf_elf_howto_table
[ (int) R_BPF_DATA_64_PCREL
];
272 return &bpf_elf_howto_table
[ (int) R_BPF_DATA_8
];
274 return &bpf_elf_howto_table
[ (int) R_BPF_DATA_16
];
276 return &bpf_elf_howto_table
[ (int) R_BPF_DATA_32
];
278 return &bpf_elf_howto_table
[ (int) R_BPF_DATA_64
];
280 case BFD_RELOC_BPF_64
:
281 return &bpf_elf_howto_table
[ (int) R_BPF_INSN_64
];
282 case BFD_RELOC_BPF_32
:
283 return &bpf_elf_howto_table
[ (int) R_BPF_INSN_32
];
284 case BFD_RELOC_BPF_16
:
285 return &bpf_elf_howto_table
[ (int) R_BPF_INSN_16
];
286 case BFD_RELOC_BPF_DISP16
:
287 return &bpf_elf_howto_table
[ (int) R_BPF_INSN_DISP16
];
288 case BFD_RELOC_BPF_DISP32
:
289 return &bpf_elf_howto_table
[ (int) R_BPF_INSN_DISP32
];
292 /* Pacify gcc -Wall. */
298 /* Map BFD reloc names to bpf ELF reloc names. */
300 static reloc_howto_type
*
301 bpf_reloc_name_lookup (bfd
*abfd ATTRIBUTE_UNUSED
, const char *r_name
)
305 for (i
= 0; i
< ARRAY_SIZE (bpf_elf_howto_table
); i
++)
306 if (bpf_elf_howto_table
[i
].name
!= NULL
307 && strcasecmp (bpf_elf_howto_table
[i
].name
, r_name
) == 0)
308 return &bpf_elf_howto_table
[i
];
313 /* Set the howto pointer for a bpf reloc. */
316 bpf_info_to_howto (bfd
*abfd
, arelent
*bfd_reloc
,
317 Elf_Internal_Rela
*elf_reloc
)
321 r_type
= ELF64_R_TYPE (elf_reloc
->r_info
);
322 if (r_type
>= (unsigned int) R_BPF_max
)
324 /* xgettext:c-format */
325 _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
327 bfd_set_error (bfd_error_bad_value
);
331 bfd_reloc
->howto
= &bpf_elf_howto_table
[r_type
];
335 /* Relocate an eBPF ELF section.
337 The RELOCATE_SECTION function is called by the new ELF backend linker
338 to handle the relocations for a section.
340 The relocs are always passed as Rela structures; if the section
341 actually uses Rel structures, the r_addend field will always be
344 This function is responsible for adjusting the section contents as
345 necessary, and (if using Rela relocs and generating a relocatable
346 output file) adjusting the reloc addend as necessary.
348 This function does not have to worry about setting the reloc
349 address or the reloc symbol index.
351 LOCAL_SYMS is a pointer to the swapped in local symbols.
353 LOCAL_SECTIONS is an array giving the section in the input file
354 corresponding to the st_shndx field of each local symbol.
356 The global hash table entry for the global symbols can be found
357 via elf_sym_hashes (input_bfd).
359 When generating relocatable output, this function must handle
360 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
361 going to be the section symbol corresponding to the output
362 section, which means that the addend must be adjusted
365 #define sec_addr(sec) ((sec)->output_section->vma + (sec)->output_offset)
368 bpf_elf_relocate_section (bfd
*output_bfd ATTRIBUTE_UNUSED
,
369 struct bfd_link_info
*info
,
371 asection
*input_section
,
373 Elf_Internal_Rela
*relocs
,
374 Elf_Internal_Sym
*local_syms
,
375 asection
**local_sections
)
377 Elf_Internal_Shdr
*symtab_hdr
;
378 struct elf_link_hash_entry
**sym_hashes
;
379 Elf_Internal_Rela
*rel
;
380 Elf_Internal_Rela
*relend
;
382 symtab_hdr
= & elf_tdata (input_bfd
)->symtab_hdr
;
383 sym_hashes
= elf_sym_hashes (input_bfd
);
384 relend
= relocs
+ input_section
->reloc_count
;
386 for (rel
= relocs
; rel
< relend
; rel
++)
388 reloc_howto_type
* howto
;
389 unsigned long r_symndx
;
390 Elf_Internal_Sym
* sym
;
392 struct elf_link_hash_entry
* h
;
394 bfd_reloc_status_type r
;
395 const char * name
= NULL
;
396 int r_type ATTRIBUTE_UNUSED
;
397 bfd_signed_vma addend
;
400 r_type
= ELF64_R_TYPE (rel
->r_info
);
401 r_symndx
= ELF64_R_SYM (rel
->r_info
);
402 howto
= bpf_elf_howto_table
+ ELF64_R_TYPE (rel
->r_info
);
406 where
= contents
+ rel
->r_offset
;
408 if (r_symndx
< symtab_hdr
->sh_info
)
410 sym
= local_syms
+ r_symndx
;
411 sec
= local_sections
[r_symndx
];
412 relocation
= BASEADDR (sec
) + sym
->st_value
;
414 name
= bfd_elf_string_from_elf_section
415 (input_bfd
, symtab_hdr
->sh_link
, sym
->st_name
);
416 name
= name
== NULL
? bfd_section_name (sec
) : name
;
420 bool warned ATTRIBUTE_UNUSED
;
421 bool unresolved_reloc ATTRIBUTE_UNUSED
;
422 bool ignored ATTRIBUTE_UNUSED
;
424 RELOC_FOR_GLOBAL_SYMBOL (info
, input_bfd
, input_section
, rel
,
425 r_symndx
, symtab_hdr
, sym_hashes
,
427 unresolved_reloc
, warned
, ignored
);
429 name
= h
->root
.root
.string
;
432 if (sec
!= NULL
&& discarded_section (sec
))
433 RELOC_AGAINST_DISCARDED_SECTION (info
, input_bfd
, input_section
,
434 rel
, 1, relend
, howto
, 0, contents
);
436 if (bfd_link_relocatable (info
))
441 case R_BPF_INSN_DISP16
:
442 case R_BPF_INSN_DISP32
:
444 /* Make the relocation PC-relative, and change its unit to
445 64-bit words. Note we need *signed* arithmetic
447 relocation
= ((bfd_signed_vma
) relocation
448 - (sec_addr (input_section
) + rel
->r_offset
));
449 relocation
= (bfd_signed_vma
) relocation
/ 8;
451 /* Get the addend from the instruction and apply it. */
452 addend
= bfd_get (howto
->bitsize
, input_bfd
,
453 contents
+ rel
->r_offset
454 + (howto
->bitsize
== 16 ? 2 : 4));
456 if ((addend
& (((~howto
->src_mask
) >> 1) & howto
->src_mask
)) != 0)
457 addend
-= (((~howto
->src_mask
) >> 1) & howto
->src_mask
) << 1;
458 relocation
+= addend
;
460 /* Write out the relocated value. */
461 bfd_put (howto
->bitsize
, input_bfd
, relocation
,
462 contents
+ rel
->r_offset
463 + (howto
->bitsize
== 16 ? 2 : 4));
473 addend
= bfd_get (howto
->bitsize
, input_bfd
, where
);
474 relocation
+= addend
;
475 bfd_put (howto
->bitsize
, input_bfd
, relocation
, where
);
483 addend
= bfd_get_16 (input_bfd
, where
+ 2);
484 relocation
+= addend
;
485 bfd_put_16 (input_bfd
, relocation
, where
+ 2);
492 /* Write relocated value */
494 addend
= bfd_get_32 (input_bfd
, where
+ 4);
495 relocation
+= addend
;
496 bfd_put_32 (input_bfd
, relocation
, where
+ 4);
504 LDDW instructions are 128 bits long, with a 64-bit immediate.
505 The lower 32 bits of the immediate are in the same position
506 as the imm32 field of other instructions.
507 The upper 32 bits of the immediate are stored at the end of
512 /* Get the addend. The upper and lower 32 bits are split.
513 'where' is the beginning of the 16-byte instruction. */
514 addend
= bfd_get_32 (input_bfd
, where
+ 4);
515 addend
|= (bfd_get_32 (input_bfd
, where
+ 12) << 32);
517 relocation
+= addend
;
519 bfd_put_32 (input_bfd
, (relocation
& 0xFFFFFFFF), where
+ 4);
520 bfd_put_32 (input_bfd
, (relocation
>> 32), where
+ 12);
525 r
= bfd_reloc_notsupported
;
528 if (r
== bfd_reloc_ok
)
529 r
= bfd_check_overflow (howto
->complain_on_overflow
,
534 if (r
!= bfd_reloc_ok
)
536 const char * msg
= NULL
;
540 case bfd_reloc_overflow
:
541 (*info
->callbacks
->reloc_overflow
)
542 (info
, (h
? &h
->root
: NULL
), name
, howto
->name
,
543 (bfd_vma
) 0, input_bfd
, input_section
, rel
->r_offset
);
546 case bfd_reloc_undefined
:
547 (*info
->callbacks
->undefined_symbol
)
548 (info
, name
, input_bfd
, input_section
, rel
->r_offset
, true);
551 case bfd_reloc_outofrange
:
552 msg
= _("internal error: out of range error");
555 case bfd_reloc_notsupported
:
556 if (sym
!= NULL
) /* Only if it's not an unresolved symbol. */
557 msg
= _("internal error: relocation not supported");
560 case bfd_reloc_dangerous
:
561 msg
= _("internal error: dangerous relocation");
565 msg
= _("internal error: unknown error");
570 (*info
->callbacks
->warning
) (info
, msg
, name
, input_bfd
,
571 input_section
, rel
->r_offset
);
578 /* Merge backend specific data from an object file to the output
579 object file when linking. */
582 elf64_bpf_merge_private_bfd_data (bfd
*ibfd
, struct bfd_link_info
*info
)
584 /* Check if we have the same endianness. */
585 if (! _bfd_generic_verify_endian_match (ibfd
, info
))
591 /* A generic howto special function for installing BPF relocations.
592 This function will be called by the assembler (via bfd_install_relocation),
593 and by various get_relocated_section_contents functions.
594 At link time, bpf_elf_relocate_section will resolve the final relocations.
596 BPF instructions are always big endian, and this approach avoids problems in
597 bfd_install_relocation. */
599 static bfd_reloc_status_type
600 bpf_elf_generic_reloc (bfd
*abfd
, arelent
*reloc_entry
, asymbol
*symbol
,
601 void *data
, asection
*input_section
,
602 bfd
*output_bfd ATTRIBUTE_UNUSED
,
603 char **error_message ATTRIBUTE_UNUSED
)
606 bfd_signed_vma relocation
;
607 bfd_reloc_status_type status
;
610 /* Sanity check that the address is in range. */
611 bfd_size_type end
= bfd_get_section_limit_octets (abfd
, input_section
);
612 bfd_size_type reloc_size
;
613 if (reloc_entry
->howto
->type
== R_BPF_INSN_64
)
616 reloc_size
= (reloc_entry
->howto
->bitsize
617 + reloc_entry
->howto
->bitpos
) / 8;
619 if (reloc_entry
->address
> end
620 || end
- reloc_entry
->address
< reloc_size
)
621 return bfd_reloc_outofrange
;
623 /* Get the symbol value. */
624 if (bfd_is_com_section (symbol
->section
))
627 relocation
= symbol
->value
;
629 if (symbol
->flags
& BSF_SECTION_SYM
)
630 /* Relocation against a section symbol: add in the section base address. */
631 relocation
+= BASEADDR (symbol
->section
);
633 relocation
+= reloc_entry
->addend
;
635 where
= (bfd_byte
*) data
+ reloc_entry
->address
;
637 status
= bfd_check_overflow (reloc_entry
->howto
->complain_on_overflow
,
638 reloc_entry
->howto
->bitsize
,
639 reloc_entry
->howto
->rightshift
, 64, relocation
);
641 if (status
!= bfd_reloc_ok
)
644 /* Now finally install the relocation. */
645 if (reloc_entry
->howto
->type
== R_BPF_INSN_64
)
647 /* lddw is a 128-bit (!) instruction that allows loading a 64-bit
648 immediate into a register. the immediate is split in half, with the
649 lower 32 bits in the same position as the imm32 field of other
650 instructions, and the upper 32 bits placed at the very end of the
651 instruction. that is, there are 32 unused bits between them. */
653 bfd_put_32 (abfd
, (relocation
& 0xFFFFFFFF), where
+ 4);
654 bfd_put_32 (abfd
, (relocation
>> 32), where
+ 12);
658 /* For other kinds of relocations, the relocated value simply goes
659 BITPOS bits from the start of the entry. This is always a multiple
660 of 8, i.e. whole bytes. */
661 bfd_put (reloc_entry
->howto
->bitsize
, abfd
, relocation
,
662 where
+ reloc_entry
->howto
->bitpos
/ 8);
665 reloc_entry
->addend
= relocation
;
666 reloc_entry
->address
+= input_section
->output_offset
;
672 /* The macros below configure the architecture. */
674 #define TARGET_LITTLE_SYM bpf_elf64_le_vec
675 #define TARGET_LITTLE_NAME "elf64-bpfle"
677 #define TARGET_BIG_SYM bpf_elf64_be_vec
678 #define TARGET_BIG_NAME "elf64-bpfbe"
680 #define ELF_ARCH bfd_arch_bpf
681 #define ELF_MACHINE_CODE EM_BPF
683 #define ELF_MAXPAGESIZE 0x100000
685 #define elf_info_to_howto_rel bpf_info_to_howto
686 #define elf_info_to_howto bpf_info_to_howto
688 #define elf_backend_may_use_rel_p 1
689 #define elf_backend_may_use_rela_p 0
690 #define elf_backend_default_use_rela_p 0
691 #define elf_backend_relocate_section bpf_elf_relocate_section
693 #define elf_backend_can_gc_sections 0
695 #define elf_symbol_leading_char '_'
696 #define bfd_elf64_bfd_reloc_type_lookup bpf_reloc_type_lookup
697 #define bfd_elf64_bfd_reloc_name_lookup bpf_reloc_name_lookup
699 #define bfd_elf64_bfd_merge_private_bfd_data elf64_bpf_merge_private_bfd_data
701 #include "elf64-target.h"