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