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 * 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 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 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