]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - bfd/elf64-bpf.c
23ede4e5d96be5f0daac821986a20051ea92012b
[thirdparty/binutils-gdb.git] / bfd / elf64-bpf.c
1 /* Linux bpf specific support for 64-bit ELF
2 Copyright (C) 2019-2023 Free Software Foundation, Inc.
3 Contributed by Oracle Inc.
4
5 This file is part of BFD, the Binary File Descriptor library.
6
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.
11
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.
16
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. */
21
22 #include "sysdep.h"
23 #include "bfd.h"
24 #include "libbfd.h"
25 #include "elf-bfd.h"
26 #include "elf/bpf.h"
27 #include "libiberty.h"
28
29 /* In case we're on a 32-bit machine, construct a 64-bit "-1" value. */
30 #define MINUS_ONE (~ (bfd_vma) 0)
31
32 #define BASEADDR(SEC) ((SEC)->output_section->vma + (SEC)->output_offset)
33
34 static bfd_reloc_status_type bpf_elf_generic_reloc
35 (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
36
37 #undef BPF_HOWTO
38 #define BPF_HOWTO(type, right, size, bits, pcrel, left, ovf, func, name, \
39 inplace, src_mask, dst_mask, pcrel_off) \
40 type##_IDX,
41 enum bpf_reloc_index {
42 R_BPF_INVALID_IDX = -1,
43 #include "bpf-reloc.def"
44 R_BPF_SIZE
45 };
46 #undef BPF_HOWTO
47
48 /* Relocation tables. */
49 #define BPF_HOWTO(...) HOWTO(__VA_ARGS__),
50 static reloc_howto_type bpf_elf_howto_table [] =
51 {
52 #include "bpf-reloc.def"
53 };
54 #undef AHOW
55 #undef BPF_HOWTO
56
57 #define BPF_HOWTO(type, right, size, bits, pcrel, left, ovf, func, name, \
58 inplace, src_mask, dst_mask, pcrel_off) \
59 case type: { return type##_IDX; }
60 static enum bpf_reloc_index
61 bpf_index_for_rtype(unsigned int r_type)
62 {
63 switch(r_type) {
64 #include "bpf-reloc.def"
65 default:
66 /* Unreachable code. */
67 BFD_ASSERT(0);
68 return -1;
69 };
70 }
71
72 /* Map BFD reloc types to bpf ELF reloc types. */
73
74 static reloc_howto_type *
75 bpf_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
76 bfd_reloc_code_real_type code)
77 {
78 switch (code)
79 {
80 case BFD_RELOC_NONE:
81 return &bpf_elf_howto_table[ (int) R_BPF_NONE_IDX];
82
83 case BFD_RELOC_32:
84 return &bpf_elf_howto_table[ (int) R_BPF_64_ABS32_IDX];
85 case BFD_RELOC_64:
86 return &bpf_elf_howto_table[ (int) R_BPF_64_ABS64_IDX];
87
88 case BFD_RELOC_BPF_64:
89 return &bpf_elf_howto_table[ (int) R_BPF_64_64_IDX];
90 case BFD_RELOC_BPF_DISP32:
91 return &bpf_elf_howto_table[ (int) R_BPF_64_32_IDX];
92 case BFD_RELOC_BPF_DISP16:
93 return &bpf_elf_howto_table[ (int) R_BPF_GNU_64_16_IDX];
94
95 default:
96 /* Pacify gcc -Wall. */
97 return NULL;
98 }
99 return NULL;
100 }
101
102 /* Map BFD reloc names to bpf ELF reloc names. */
103
104 static reloc_howto_type *
105 bpf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
106 {
107 unsigned int i;
108
109 for (i = 0; i < R_BPF_SIZE; i++)
110 if (bpf_elf_howto_table[i].name != NULL
111 && strcasecmp (bpf_elf_howto_table[i].name, r_name) == 0)
112 return &bpf_elf_howto_table[i];
113
114 return NULL;
115 }
116
117 /* Set the howto pointer for a bpf reloc. */
118
119 static bool
120 bpf_info_to_howto (bfd *abfd, arelent *bfd_reloc,
121 Elf_Internal_Rela *elf_reloc)
122 {
123 unsigned int r_type;
124 unsigned int i;
125 r_type = ELF64_R_TYPE (elf_reloc->r_info);
126
127 i = bpf_index_for_rtype(r_type);
128 if (i == (unsigned int) -1)
129 {
130 /* xgettext:c-format */
131 _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
132 abfd, r_type);
133 bfd_set_error (bfd_error_bad_value);
134 return false;
135 }
136
137 bfd_reloc->howto = &bpf_elf_howto_table [i];
138 return true;
139 }
140
141 /* Relocate an eBPF ELF section.
142
143 The RELOCATE_SECTION function is called by the new ELF backend linker
144 to handle the relocations for a section.
145
146 The relocs are always passed as Rela structures; if the section
147 actually uses Rel structures, the r_addend field will always be
148 zero.
149
150 This function is responsible for adjusting the section contents as
151 necessary, and (if using Rela relocs and generating a relocatable
152 output file) adjusting the reloc addend as necessary.
153
154 This function does not have to worry about setting the reloc
155 address or the reloc symbol index.
156
157 LOCAL_SYMS is a pointer to the swapped in local symbols.
158
159 LOCAL_SECTIONS is an array giving the section in the input file
160 corresponding to the st_shndx field of each local symbol.
161
162 The global hash table entry for the global symbols can be found
163 via elf_sym_hashes (input_bfd).
164
165 When generating relocatable output, this function must handle
166 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
167 going to be the section symbol corresponding to the output
168 section, which means that the addend must be adjusted
169 accordingly. */
170
171 #define sec_addr(sec) ((sec)->output_section->vma + (sec)->output_offset)
172
173 static int
174 bpf_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
175 struct bfd_link_info *info,
176 bfd *input_bfd,
177 asection *input_section,
178 bfd_byte *contents,
179 Elf_Internal_Rela *relocs,
180 Elf_Internal_Sym *local_syms,
181 asection **local_sections)
182 {
183 Elf_Internal_Shdr *symtab_hdr;
184 struct elf_link_hash_entry **sym_hashes;
185 Elf_Internal_Rela *rel;
186 Elf_Internal_Rela *relend;
187
188 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
189 sym_hashes = elf_sym_hashes (input_bfd);
190 relend = relocs + input_section->reloc_count;
191
192 for (rel = relocs; rel < relend; rel ++)
193 {
194 reloc_howto_type * howto;
195 unsigned int howto_index;
196 unsigned long r_symndx;
197 Elf_Internal_Sym * sym;
198 asection * sec;
199 struct elf_link_hash_entry * h;
200 bfd_vma relocation;
201 bfd_reloc_status_type r;
202 const char * name = NULL;
203 int r_type ATTRIBUTE_UNUSED;
204 bfd_signed_vma addend;
205 bfd_byte * where;
206
207 r_type = ELF64_R_TYPE (rel->r_info);
208 r_symndx = ELF64_R_SYM (rel->r_info);
209
210 howto_index = bpf_index_for_rtype (ELF64_R_TYPE (rel->r_info));
211 howto = &bpf_elf_howto_table[howto_index];
212 h = NULL;
213 sym = NULL;
214 sec = NULL;
215 where = contents + rel->r_offset;
216
217 if (r_symndx < symtab_hdr->sh_info)
218 {
219 sym = local_syms + r_symndx;
220 sec = local_sections [r_symndx];
221 relocation = BASEADDR (sec) + sym->st_value;
222
223 name = bfd_elf_string_from_elf_section
224 (input_bfd, symtab_hdr->sh_link, sym->st_name);
225 name = name == NULL ? bfd_section_name (sec) : name;
226 }
227 else
228 {
229 bool warned ATTRIBUTE_UNUSED;
230 bool unresolved_reloc ATTRIBUTE_UNUSED;
231 bool ignored ATTRIBUTE_UNUSED;
232
233 RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
234 r_symndx, symtab_hdr, sym_hashes,
235 h, sec, relocation,
236 unresolved_reloc, warned, ignored);
237
238 name = h->root.root.string;
239 }
240
241 if (sec != NULL && discarded_section (sec))
242 RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
243 rel, 1, relend, howto, 0, contents);
244
245 if (bfd_link_relocatable (info))
246 continue;
247
248 switch (howto->type)
249 {
250 case R_BPF_64_32:
251 {
252 /* Make the relocation PC-relative, and change its unit to
253 64-bit words. Note we need *signed* arithmetic
254 here. */
255 relocation = ((bfd_signed_vma) relocation
256 - (sec_addr (input_section) + rel->r_offset));
257 relocation = (bfd_signed_vma) relocation / 8;
258
259 /* Get the addend from the instruction and apply it. */
260 addend = bfd_get (howto->bitsize, input_bfd,
261 contents + rel->r_offset
262 + (howto->bitsize == 16 ? 2 : 4));
263
264 if ((addend & (((~howto->src_mask) >> 1) & howto->src_mask)) != 0)
265 addend -= (((~howto->src_mask) >> 1) & howto->src_mask) << 1;
266 relocation += addend;
267
268 /* Write out the relocated value. */
269 bfd_put (howto->bitsize, input_bfd, relocation,
270 contents + rel->r_offset
271 + (howto->bitsize == 16 ? 2 : 4));
272
273 r = bfd_reloc_ok;
274 break;
275 }
276 case R_BPF_64_ABS64:
277 case R_BPF_64_ABS32:
278 {
279 addend = bfd_get (howto->bitsize, input_bfd, where);
280 relocation += addend;
281 bfd_put (howto->bitsize, input_bfd, relocation, where);
282
283 r = bfd_reloc_ok;
284 break;
285 }
286 case R_BPF_64_64:
287 {
288 /*
289 LDDW instructions are 128 bits long, with a 64-bit immediate.
290 The lower 32 bits of the immediate are in the same position
291 as the imm32 field of other instructions.
292 The upper 32 bits of the immediate are stored at the end of
293 the instruction.
294 */
295
296
297 /* Get the addend. The upper and lower 32 bits are split.
298 'where' is the beginning of the 16-byte instruction. */
299 addend = bfd_get_32 (input_bfd, where + 4);
300 addend |= (bfd_get_32 (input_bfd, where + 12) << 32);
301
302 relocation += addend;
303
304 bfd_put_32 (input_bfd, (relocation & 0xFFFFFFFF), where + 4);
305 bfd_put_32 (input_bfd, (relocation >> 32), where + 12);
306 r = bfd_reloc_ok;
307 break;
308 }
309 default:
310 r = bfd_reloc_notsupported;
311 }
312
313 if (r == bfd_reloc_ok)
314 r = bfd_check_overflow (howto->complain_on_overflow,
315 howto->bitsize,
316 howto->rightshift,
317 64, relocation);
318
319 if (r != bfd_reloc_ok)
320 {
321 const char * msg = NULL;
322
323 switch (r)
324 {
325 case bfd_reloc_overflow:
326 (*info->callbacks->reloc_overflow)
327 (info, (h ? &h->root : NULL), name, howto->name,
328 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
329 break;
330
331 case bfd_reloc_undefined:
332 (*info->callbacks->undefined_symbol)
333 (info, name, input_bfd, input_section, rel->r_offset, true);
334 break;
335
336 case bfd_reloc_outofrange:
337 msg = _("internal error: out of range error");
338 break;
339
340 case bfd_reloc_notsupported:
341 if (sym != NULL) /* Only if it's not an unresolved symbol. */
342 msg = _("internal error: relocation not supported");
343 break;
344
345 case bfd_reloc_dangerous:
346 msg = _("internal error: dangerous relocation");
347 break;
348
349 default:
350 msg = _("internal error: unknown error");
351 break;
352 }
353
354 if (msg)
355 (*info->callbacks->warning) (info, msg, name, input_bfd,
356 input_section, rel->r_offset);
357 }
358 }
359
360 return true;
361 }
362
363 /* Merge backend specific data from an object file to the output
364 object file when linking. */
365
366 static bool
367 elf64_bpf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
368 {
369 /* Check if we have the same endianness. */
370 if (! _bfd_generic_verify_endian_match (ibfd, info))
371 return false;
372
373 return true;
374 }
375
376 /* A generic howto special function for installing BPF relocations.
377 This function will be called by the assembler (via bfd_install_relocation),
378 and by various get_relocated_section_contents functions.
379 At link time, bpf_elf_relocate_section will resolve the final relocations.
380
381 BPF instructions are always big endian, and this approach avoids problems in
382 bfd_install_relocation. */
383
384 static bfd_reloc_status_type
385 bpf_elf_generic_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
386 void *data, asection *input_section,
387 bfd *output_bfd ATTRIBUTE_UNUSED,
388 char **error_message ATTRIBUTE_UNUSED)
389 {
390
391 bfd_signed_vma relocation;
392 bfd_reloc_status_type status;
393 bfd_byte *where;
394
395 /* Sanity check that the address is in range. */
396 bfd_size_type end = bfd_get_section_limit_octets (abfd, input_section);
397 bfd_size_type reloc_size;
398 if (reloc_entry->howto->type == R_BPF_64_64)
399 reloc_size = 16;
400 else
401 reloc_size = (reloc_entry->howto->bitsize
402 + reloc_entry->howto->bitpos) / 8;
403
404 if (reloc_entry->address > end
405 || end - reloc_entry->address < reloc_size)
406 return bfd_reloc_outofrange;
407
408 /* Get the symbol value. */
409 if (bfd_is_com_section (symbol->section))
410 relocation = 0;
411 else
412 relocation = symbol->value;
413
414 if (symbol->flags & BSF_SECTION_SYM)
415 /* Relocation against a section symbol: add in the section base address. */
416 relocation += BASEADDR (symbol->section);
417
418 relocation += reloc_entry->addend;
419
420 where = (bfd_byte *) data + reloc_entry->address;
421
422 status = bfd_check_overflow (reloc_entry->howto->complain_on_overflow,
423 reloc_entry->howto->bitsize,
424 reloc_entry->howto->rightshift, 64, relocation);
425
426 if (status != bfd_reloc_ok)
427 return status;
428
429 /* Now finally install the relocation. */
430 if (reloc_entry->howto->type == R_BPF_64_64)
431 {
432 /* lddw is a 128-bit (!) instruction that allows loading a 64-bit
433 immediate into a register. the immediate is split in half, with the
434 lower 32 bits in the same position as the imm32 field of other
435 instructions, and the upper 32 bits placed at the very end of the
436 instruction. that is, there are 32 unused bits between them. */
437
438 bfd_put_32 (abfd, (relocation & 0xFFFFFFFF), where + 4);
439 bfd_put_32 (abfd, (relocation >> 32), where + 12);
440 }
441 else
442 {
443 /* For other kinds of relocations, the relocated value simply goes
444 BITPOS bits from the start of the entry. This is always a multiple
445 of 8, i.e. whole bytes. */
446 bfd_put (reloc_entry->howto->bitsize, abfd, relocation,
447 where + reloc_entry->howto->bitpos / 8);
448 }
449
450 reloc_entry->addend = relocation;
451 reloc_entry->address += input_section->output_offset;
452
453 return bfd_reloc_ok;
454 }
455
456
457 /* The macros below configure the architecture. */
458
459 #define TARGET_LITTLE_SYM bpf_elf64_le_vec
460 #define TARGET_LITTLE_NAME "elf64-bpfle"
461
462 #define TARGET_BIG_SYM bpf_elf64_be_vec
463 #define TARGET_BIG_NAME "elf64-bpfbe"
464
465 #define ELF_ARCH bfd_arch_bpf
466 #define ELF_MACHINE_CODE EM_BPF
467
468 #define ELF_MAXPAGESIZE 0x100000
469
470 #define elf_info_to_howto_rel bpf_info_to_howto
471 #define elf_info_to_howto bpf_info_to_howto
472
473 #define elf_backend_may_use_rel_p 1
474 #define elf_backend_may_use_rela_p 0
475 #define elf_backend_default_use_rela_p 0
476 #define elf_backend_relocate_section bpf_elf_relocate_section
477
478 #define elf_backend_can_gc_sections 0
479
480 #define elf_symbol_leading_char '_'
481 #define bfd_elf64_bfd_reloc_type_lookup bpf_reloc_type_lookup
482 #define bfd_elf64_bfd_reloc_name_lookup bpf_reloc_name_lookup
483
484 #define bfd_elf64_bfd_merge_private_bfd_data elf64_bpf_merge_private_bfd_data
485
486 #include "elf64-target.h"