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