]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - bfd/elf64-bpf.c
[PATCH] fix windmc typedef bug
[thirdparty/binutils-gdb.git] / bfd / elf64-bpf.c
1 /* Linux bpf specific support for 64-bit ELF
2 Copyright (C) 2019-2020 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 /* Relocation tables. */
35 static reloc_howto_type bpf_elf_howto_table [] =
36 {
37 /* This reloc does nothing. */
38 HOWTO (R_BPF_NONE, /* type */
39 0, /* rightshift */
40 3, /* size (0 = byte, 1 = short, 2 = long) */
41 0, /* bitsize */
42 FALSE, /* pc_relative */
43 0, /* bitpos */
44 complain_overflow_dont, /* complain_on_overflow */
45 bfd_elf_generic_reloc, /* special_function */
46 "R_BPF_NONE", /* name */
47 FALSE, /* partial_inplace */
48 0, /* src_mask */
49 0, /* dst_mask */
50 FALSE), /* pcrel_offset */
51
52 /* 64-immediate in LDDW instruction. */
53 HOWTO (R_BPF_INSN_64, /* type */
54 0, /* rightshift */
55 4, /* size (0 = byte, 1 = short, 2 = long) */
56 64, /* bitsize */
57 FALSE, /* pc_relative */
58 0, /* bitpos */
59 complain_overflow_signed, /* complain_on_overflow */
60 bfd_elf_generic_reloc, /* special_function */
61 "R_BPF_INSN_64", /* name */
62 FALSE, /* partial_inplace */
63 0, /* src_mask */
64 MINUS_ONE, /* dst_mask */
65 TRUE), /* pcrel_offset */
66
67 /* 32-immediate in many instructions. Note: handled manually. */
68 HOWTO (R_BPF_INSN_32, /* type */
69 0, /* rightshift */
70 2, /* size (0 = byte, 1 = short, 2 = long) */
71 32, /* bitsize */
72 FALSE, /* pc_relative */
73 0, /* bitpos */
74 complain_overflow_signed, /* complain_on_overflow */
75 bfd_elf_generic_reloc, /* special_function */
76 "R_BPF_INSN_32", /* name */
77 FALSE, /* partial_inplace */
78 0, /* src_mask */
79 0xffffffff, /* dst_mask */
80 TRUE), /* pcrel_offset */
81
82 /* 16-bit offsets in instructions. */
83 HOWTO (R_BPF_INSN_16, /* type */
84 0, /* rightshift */
85 1, /* size (0 = byte, 1 = short, 2 = long) */
86 16, /* bitsize */
87 FALSE, /* pc_relative */
88 0, /* bitpos */
89 complain_overflow_signed, /* complain_on_overflow */
90 bfd_elf_generic_reloc, /* special_function */
91 "R_BPF_INSN_16", /* name */
92 FALSE, /* partial_inplace */
93 0, /* src_mask */
94 0x0000ffff, /* dst_mask */
95 TRUE), /* pcrel_offset */
96
97 /* 16-bit PC-relative address in jump instructions. */
98 HOWTO (R_BPF_INSN_DISP16, /* type */
99 0, /* rightshift */
100 1, /* size (0 = byte, 1 = short, 2 = long) */
101 16, /* bitsize */
102 TRUE, /* pc_relative */
103 32, /* bitpos */
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 */
111
112 HOWTO (R_BPF_DATA_8_PCREL,
113 0, /* rightshift */
114 0, /* size (0 = byte, 1 = short, 2 = long) */
115 8, /* bitsize */
116 TRUE, /* pc_relative */
117 0, /* bitpos */
118 complain_overflow_signed, /* complain_on_overflow */
119 bfd_elf_generic_reloc, /* special_function */
120 "R_BPF_8_PCREL", /* name */
121 FALSE, /* partial_inplace */
122 0, /* src_mask */
123 0xff, /* dst_mask */
124 TRUE), /* pcrel_offset */
125
126 HOWTO (R_BPF_DATA_16_PCREL,
127 0, /* rightshift */
128 1, /* size (0 = byte, 1 = short, 2 = long) */
129 16, /* bitsize */
130 TRUE, /* pc_relative */
131 0, /* bitpos */
132 complain_overflow_signed, /* complain_on_overflow */
133 bfd_elf_generic_reloc, /* special_function */
134 "R_BPF_16_PCREL", /* name */
135 FALSE, /* partial_inplace */
136 0, /* src_mask */
137 0xffff, /* dst_mask */
138 TRUE), /* pcrel_offset */
139
140 HOWTO (R_BPF_DATA_32_PCREL,
141 0, /* rightshift */
142 2, /* size (0 = byte, 1 = short, 2 = long) */
143 32, /* bitsize */
144 TRUE, /* pc_relative */
145 0, /* bitpos */
146 complain_overflow_signed, /* complain_on_overflow */
147 bfd_elf_generic_reloc, /* special_function */
148 "R_BPF_32_PCREL", /* name */
149 FALSE, /* partial_inplace */
150 0, /* src_mask */
151 0xffffffff, /* dst_mask */
152 TRUE), /* pcrel_offset */
153
154 HOWTO (R_BPF_DATA_8,
155 0, /* rightshift */
156 0, /* size (0 = byte, 1 = short, 2 = long) */
157 8, /* bitsize */
158 FALSE, /* pc_relative */
159 0, /* bitpos */
160 complain_overflow_unsigned, /* complain_on_overflow */
161 bfd_elf_generic_reloc, /* special_function */
162 "R_BPF_DATA_8", /* name */
163 FALSE, /* partial_inplace */
164 0, /* src_mask */
165 0xff, /* dst_mask */
166 FALSE), /* pcrel_offset */
167
168 HOWTO (R_BPF_DATA_16,
169 0, /* rightshift */
170 1, /* size (0 = byte, 1 = short, 2 = long) */
171 16, /* bitsize */
172 FALSE, /* pc_relative */
173 0, /* bitpos */
174 complain_overflow_unsigned, /* complain_on_overflow */
175 bfd_elf_generic_reloc, /* special_function */
176 "R_BPF_DATA_16", /* name */
177 FALSE, /* partial_inplace */
178 0, /* src_mask */
179 0xffff, /* dst_mask */
180 FALSE), /* pcrel_offset */
181
182 /* 32-bit PC-relative address in call instructions. */
183 HOWTO (R_BPF_INSN_DISP32, /* type */
184 0, /* rightshift */
185 2, /* size (0 = byte, 1 = short, 2 = long) */
186 32, /* bitsize */
187 TRUE, /* pc_relative */
188 0, /* bitpos */
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 */
196
197 /* 32-bit data. */
198 HOWTO (R_BPF_DATA_32, /* type */
199 0, /* rightshift */
200 2, /* size (0 = byte, 1 = short, 2 = long) */
201 32, /* bitsize */
202 FALSE, /* pc_relative */
203 0, /* bitpos */
204 complain_overflow_bitfield, /* complain_on_overflow */
205 bfd_elf_generic_reloc, /* special_function */
206 "R_BPF_DATA_32", /* name */
207 FALSE, /* partial_inplace */
208 0, /* src_mask */
209 0xffffffff, /* dst_mask */
210 TRUE), /* pcrel_offset */
211
212 /* 64-bit data. */
213 HOWTO (R_BPF_DATA_64, /* type */
214 0, /* rightshift */
215 4, /* size (0 = byte, 1 = short, 2 = long) */
216 64, /* bitsize */
217 FALSE, /* pc_relative */
218 0, /* bitpos */
219 complain_overflow_bitfield, /* complain_on_overflow */
220 bfd_elf_generic_reloc, /* special_function */
221 "R_BPF_DATA_64", /* name */
222 FALSE, /* partial_inplace */
223 0, /* src_mask */
224 MINUS_ONE, /* dst_mask */
225 TRUE), /* pcrel_offset */
226
227 HOWTO (R_BPF_DATA_64_PCREL,
228 0, /* rightshift */
229 4, /* size (0 = byte, 1 = short, 2 = long) */
230 64, /* bitsize */
231 TRUE, /* pc_relative */
232 0, /* bitpos */
233 complain_overflow_signed, /* complain_on_overflow */
234 bfd_elf_generic_reloc, /* special_function */
235 "R_BPF_64_PCREL", /* name */
236 FALSE, /* partial_inplace */
237 0, /* src_mask */
238 MINUS_ONE, /* dst_mask */
239 TRUE), /* pcrel_offset */
240 };
241 #undef AHOW
242
243 /* Map BFD reloc types to bpf ELF reloc types. */
244
245 static reloc_howto_type *
246 bpf_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
247 bfd_reloc_code_real_type code)
248 {
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. */
253
254 switch (code)
255 {
256 case BFD_RELOC_NONE:
257 return &bpf_elf_howto_table[ (int) R_BPF_NONE];
258
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];
267
268 case BFD_RELOC_8:
269 return &bpf_elf_howto_table[ (int) R_BPF_DATA_8];
270 case BFD_RELOC_16:
271 return &bpf_elf_howto_table[ (int) R_BPF_DATA_16];
272 case BFD_RELOC_32:
273 return &bpf_elf_howto_table[ (int) R_BPF_DATA_32];
274 case BFD_RELOC_64:
275 return &bpf_elf_howto_table[ (int) R_BPF_DATA_64];
276
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];
287
288 default:
289 /* Pacify gcc -Wall. */
290 return NULL;
291 }
292 return NULL;
293 }
294
295 /* Map BFD reloc names to bpf ELF reloc names. */
296
297 static reloc_howto_type *
298 bpf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
299 {
300 unsigned int i;
301
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];
306
307 return NULL;
308 }
309
310 /* Set the howto pointer for a bpf reloc. */
311
312 static bfd_boolean
313 bpf_info_to_howto (bfd *abfd, arelent *bfd_reloc,
314 Elf_Internal_Rela *elf_reloc)
315 {
316 unsigned int r_type;
317
318 r_type = ELF64_R_TYPE (elf_reloc->r_info);
319 if (r_type >= (unsigned int) R_BPF_max)
320 {
321 /* xgettext:c-format */
322 _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
323 abfd, r_type);
324 bfd_set_error (bfd_error_bad_value);
325 return FALSE;
326 }
327
328 bfd_reloc->howto = &bpf_elf_howto_table [r_type];
329 return TRUE;
330 }
331
332 /* Relocate an eBPF ELF section.
333
334 The RELOCATE_SECTION function is called by the new ELF backend linker
335 to handle the relocations for a section.
336
337 The relocs are always passed as Rela structures; if the section
338 actually uses Rel structures, the r_addend field will always be
339 zero.
340
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.
344
345 This function does not have to worry about setting the reloc
346 address or the reloc symbol index.
347
348 LOCAL_SYMS is a pointer to the swapped in local symbols.
349
350 LOCAL_SECTIONS is an array giving the section in the input file
351 corresponding to the st_shndx field of each local symbol.
352
353 The global hash table entry for the global symbols can be found
354 via elf_sym_hashes (input_bfd).
355
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
360 accordingly. */
361
362 #define sec_addr(sec) ((sec)->output_section->vma + (sec)->output_offset)
363
364 static bfd_boolean
365 bpf_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
366 struct bfd_link_info *info,
367 bfd *input_bfd,
368 asection *input_section,
369 bfd_byte *contents,
370 Elf_Internal_Rela *relocs,
371 Elf_Internal_Sym *local_syms,
372 asection **local_sections)
373 {
374 Elf_Internal_Shdr *symtab_hdr;
375 struct elf_link_hash_entry **sym_hashes;
376 Elf_Internal_Rela *rel;
377 Elf_Internal_Rela *relend;
378
379 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
380 sym_hashes = elf_sym_hashes (input_bfd);
381 relend = relocs + input_section->reloc_count;
382
383 for (rel = relocs; rel < relend; rel ++)
384 {
385 reloc_howto_type * howto;
386 unsigned long r_symndx;
387 Elf_Internal_Sym * sym;
388 asection * sec;
389 struct elf_link_hash_entry * h;
390 bfd_vma relocation;
391 bfd_reloc_status_type r;
392 const char * name = NULL;
393 int r_type ATTRIBUTE_UNUSED;
394
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);
398 h = NULL;
399 sym = NULL;
400 sec = NULL;
401
402 if (r_symndx < symtab_hdr->sh_info)
403 {
404 sym = local_syms + r_symndx;
405 sec = local_sections [r_symndx];
406 relocation = BASEADDR (sec) + sym->st_value;
407
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;
411 }
412 else
413 {
414 bfd_boolean warned ATTRIBUTE_UNUSED;
415 bfd_boolean unresolved_reloc ATTRIBUTE_UNUSED;
416 bfd_boolean ignored ATTRIBUTE_UNUSED;
417
418 RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
419 r_symndx, symtab_hdr, sym_hashes,
420 h, sec, relocation,
421 unresolved_reloc, warned, ignored);
422
423 name = h->root.root.string;
424 }
425
426 if (sec != NULL && discarded_section (sec))
427 RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
428 rel, 1, relend, howto, 0, contents);
429
430 if (bfd_link_relocatable (info))
431 continue;
432
433 switch (howto->type)
434 {
435 case R_BPF_INSN_DISP16:
436 case R_BPF_INSN_DISP32:
437 {
438 bfd_signed_vma addend;
439
440 /* Make the relocation PC-relative, and change its unit to
441 64-bit words. */
442 relocation -= sec_addr (input_section) + rel->r_offset;
443 /* Make it 64-bit words. */
444 relocation = relocation / 8;
445
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));
450
451 if ((addend & (((~howto->src_mask) >> 1) & howto->src_mask)) != 0)
452 addend -= (((~howto->src_mask) >> 1) & howto->src_mask) << 1;
453 relocation += addend;
454
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));
459
460 r = bfd_reloc_ok;
461 break;
462 }
463 case R_BPF_INSN_32:
464 {
465 /* Write relocated value */
466 bfd_put (howto->bitsize, input_bfd, relocation,
467 contents + rel->r_offset + 4);
468
469 r = bfd_reloc_ok;
470 break;
471 }
472 case R_BPF_INSN_64:
473 {
474 /*
475 LDDW instructions are 128 bits long, with a 64-bit immediate.
476 The lower 32 bits of the immediate are in the same position
477 as the imm32 field of other instructions.
478 The upper 32 bits of the immediate are stored at the end of
479 the instruction.
480 */
481 bfd_put (32, input_bfd, (relocation & 0xFFFFFFFF),
482 contents + rel->r_offset + 4);
483 bfd_put (32, input_bfd, (relocation >> 32),
484 contents + rel->r_offset + 12);
485 r = bfd_reloc_ok;
486 break;
487 }
488 default:
489 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
490 contents, rel->r_offset, relocation,
491 rel->r_addend);
492 }
493
494 if (r != bfd_reloc_ok)
495 {
496 const char * msg = NULL;
497
498 switch (r)
499 {
500 case bfd_reloc_overflow:
501 (*info->callbacks->reloc_overflow)
502 (info, (h ? &h->root : NULL), name, howto->name,
503 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
504 break;
505
506 case bfd_reloc_undefined:
507 (*info->callbacks->undefined_symbol)
508 (info, name, input_bfd, input_section, rel->r_offset, TRUE);
509 break;
510
511 case bfd_reloc_outofrange:
512 msg = _("internal error: out of range error");
513 break;
514
515 case bfd_reloc_notsupported:
516 if (sym != NULL) /* Only if it's not an unresolved symbol. */
517 msg = _("internal error: relocation not supported");
518 break;
519
520 case bfd_reloc_dangerous:
521 msg = _("internal error: dangerous relocation");
522 break;
523
524 default:
525 msg = _("internal error: unknown error");
526 break;
527 }
528
529 if (msg)
530 (*info->callbacks->warning) (info, msg, name, input_bfd,
531 input_section, rel->r_offset);
532 }
533 }
534
535 return TRUE;
536 }
537
538 /* Merge backend specific data from an object file to the output
539 object file when linking. */
540
541 static bfd_boolean
542 elf64_bpf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
543 {
544 /* Check if we have the same endianness. */
545 if (! _bfd_generic_verify_endian_match (ibfd, info))
546 return FALSE;
547
548 return TRUE;
549 }
550
551 /* The macros below configure the architecture. */
552
553 #define TARGET_LITTLE_SYM bpf_elf64_le_vec
554 #define TARGET_LITTLE_NAME "elf64-bpfle"
555
556 #define TARGET_BIG_SYM bpf_elf64_be_vec
557 #define TARGET_BIG_NAME "elf64-bpfbe"
558
559 #define ELF_ARCH bfd_arch_bpf
560 #define ELF_MACHINE_CODE EM_BPF
561
562 #define ELF_MAXPAGESIZE 0x100000
563
564 #define elf_info_to_howto_rel bpf_info_to_howto
565 #define elf_info_to_howto bpf_info_to_howto
566
567 #define elf_backend_may_use_rel_p 1
568 #define elf_backend_may_use_rela_p 0
569 #define elf_backend_default_use_rela_p 0
570 #define elf_backend_relocate_section bpf_elf_relocate_section
571
572 #define elf_backend_can_gc_sections 0
573
574 #define elf_symbol_leading_char '_'
575 #define bfd_elf64_bfd_reloc_type_lookup bpf_reloc_type_lookup
576 #define bfd_elf64_bfd_reloc_name_lookup bpf_reloc_name_lookup
577
578 #define bfd_elf64_bfd_merge_private_bfd_data elf64_bpf_merge_private_bfd_data
579
580 #include "elf64-target.h"