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 LDDW instruction.  */
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 *
bpf_reloc_type_lookup(bfd * abfd ATTRIBUTE_UNUSED,bfd_reloc_code_real_type code)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 *
bpf_reloc_name_lookup(bfd * abfd ATTRIBUTE_UNUSED,const char * r_name)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
bpf_info_to_howto(bfd * abfd,arelent * bfd_reloc,Elf_Internal_Rela * elf_reloc)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
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)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         default:
464           r = _bfd_final_link_relocate (howto, input_bfd, input_section,
465                                         contents, rel->r_offset, relocation,
466                                         rel->r_addend);
467         }
468 
469       if (r != bfd_reloc_ok)
470 	{
471 	  const char * msg = NULL;
472 
473 	  switch (r)
474 	    {
475 	    case bfd_reloc_overflow:
476 	      (*info->callbacks->reloc_overflow)
477 		(info, (h ? &h->root : NULL), name, howto->name,
478 		 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
479 	      break;
480 
481 	    case bfd_reloc_undefined:
482 	      (*info->callbacks->undefined_symbol)
483 		(info, name, input_bfd, input_section, rel->r_offset, TRUE);
484 	      break;
485 
486 	    case bfd_reloc_outofrange:
487 	      msg = _("internal error: out of range error");
488 	      break;
489 
490 	    case bfd_reloc_notsupported:
491 	      if (sym != NULL) /* Only if it's not an unresolved symbol.  */
492                 msg = _("internal error: relocation not supported");
493 	      break;
494 
495 	    case bfd_reloc_dangerous:
496 	      msg = _("internal error: dangerous relocation");
497 	      break;
498 
499 	    default:
500 	      msg = _("internal error: unknown error");
501 	      break;
502 	    }
503 
504 	  if (msg)
505 	    (*info->callbacks->warning) (info, msg, name, input_bfd,
506 					 input_section, rel->r_offset);
507 	}
508     }
509 
510   return TRUE;
511 }
512 
513 /* Merge backend specific data from an object file to the output
514    object file when linking.  */
515 
516 static bfd_boolean
elf64_bpf_merge_private_bfd_data(bfd * ibfd,struct bfd_link_info * info)517 elf64_bpf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
518 {
519   /* Check if we have the same endianness.  */
520   if (! _bfd_generic_verify_endian_match (ibfd, info))
521     return FALSE;
522 
523   return TRUE;
524 }
525 
526 /* The macros below configure the architecture.  */
527 
528 #define TARGET_LITTLE_SYM bpf_elf64_le_vec
529 #define TARGET_LITTLE_NAME "elf64-bpfle"
530 
531 #define TARGET_BIG_SYM bpf_elf64_be_vec
532 #define TARGET_BIG_NAME "elf64-bpfbe"
533 
534 #define ELF_ARCH bfd_arch_bpf
535 #define ELF_MACHINE_CODE EM_BPF
536 
537 #define ELF_MAXPAGESIZE 0x100000
538 
539 #define elf_info_to_howto_rel bpf_info_to_howto
540 #define elf_info_to_howto bpf_info_to_howto
541 
542 #define elf_backend_may_use_rel_p		1
543 #define elf_backend_may_use_rela_p		0
544 #define elf_backend_default_use_rela_p		0
545 #define elf_backend_relocate_section		bpf_elf_relocate_section
546 
547 #define elf_backend_can_gc_sections		0
548 
549 #define elf_symbol_leading_char			'_'
550 #define bfd_elf64_bfd_reloc_type_lookup		bpf_reloc_type_lookup
551 #define bfd_elf64_bfd_reloc_name_lookup		bpf_reloc_name_lookup
552 
553 #define bfd_elf64_bfd_merge_private_bfd_data elf64_bpf_merge_private_bfd_data
554 
555 #include "elf64-target.h"
556