1/* OpenRISC-specific support for 32-bit ELF. 2 Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc. 3 Contributed by Johan Rydberg, jrydberg@opencores.org 4 5This file is part of BFD, the Binary File Descriptor library. 6 7This program is free software; you can redistribute it and/or modify 8it under the terms of the GNU General Public License as published by 9the Free Software Foundation; either version 2 of the License, or 10(at your option) any later version. 11 12This program is distributed in the hope that it will be useful, 13but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15GNU General Public License for more details. 16 17You should have received a copy of the GNU General Public License 18along with this program; if not, write to the Free Software 19Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 20 21#include "bfd.h" 22#include "sysdep.h" 23#include "libbfd.h" 24#include "elf-bfd.h" 25#include "elf/openrisc.h" 26#include "libiberty.h" 27 28/* Forward declarations. */ 29 30static reloc_howto_type *openrisc_reloc_type_lookup 31 PARAMS ((bfd * , bfd_reloc_code_real_type)); 32static void openrisc_info_to_howto_rela 33 PARAMS ((bfd *, arelent *, Elf_Internal_Rela *)); 34static bfd_boolean openrisc_elf_relocate_section 35 PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, 36 Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)); 37static bfd_reloc_status_type openrisc_final_link_relocate 38 PARAMS ((reloc_howto_type *, bfd *, asection *, bfd_byte *, 39 Elf_Internal_Rela *, bfd_vma)); 40static bfd_boolean openrisc_elf_gc_sweep_hook 41 PARAMS ((bfd *, struct bfd_link_info *, asection *, 42 const Elf_Internal_Rela *)); 43static asection * openrisc_elf_gc_mark_hook 44 PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *, 45 struct elf_link_hash_entry *, Elf_Internal_Sym *)); 46static bfd_boolean openrisc_elf_check_relocs 47 PARAMS ((bfd *, struct bfd_link_info *, asection *, 48 const Elf_Internal_Rela *)); 49static bfd_boolean openrisc_elf_object_p 50 PARAMS ((bfd *)); 51static void openrisc_elf_final_write_processing 52 PARAMS ((bfd *, bfd_boolean)); 53 54 55static reloc_howto_type openrisc_elf_howto_table[] = 56 { 57 /* This reloc does nothing. */ 58 HOWTO (R_OPENRISC_NONE, /* type */ 59 0, /* rightshift */ 60 2, /* size (0 = byte, 1 = short, 2 = long) */ 61 32, /* bitsize */ 62 FALSE, /* pc_relative */ 63 0, /* bitpos */ 64 complain_overflow_bitfield, /* complain_on_overflow */ 65 bfd_elf_generic_reloc, /* special_function */ 66 "R_OPENRISC_NONE", /* name */ 67 FALSE, /* partial_inplace */ 68 0, /* src_mask */ 69 0, /* dst_mask */ 70 FALSE), /* pcrel_offset */ 71 72 /* A PC relative 26 bit relocation, right shifted by 2. */ 73 HOWTO (R_OPENRISC_INSN_REL_26, /* type */ 74 2, /* rightshift */ 75 2, /* size (0 = byte, 1 = short, 2 = long) */ 76 26, /* bitsize */ 77 TRUE, /* pc_relative */ 78 0, /* bitpos */ 79 complain_overflow_signed, /* complain_on_overflow */ 80 bfd_elf_generic_reloc, /* special_function */ 81 "R_OPENRISC_INSN_REL_26", /* name */ 82 FALSE, /* partial_inplace */ 83 0x00000000, /* src_mask */ 84 0x03ffffff, /* dst_mask */ 85 FALSE), /* pcrel_offset */ 86 87 /* A absolute 26 bit relocation, right shifted by 2. */ 88 HOWTO (R_OPENRISC_INSN_ABS_26, /* type */ 89 2, /* rightshift */ 90 2, /* size (0 = byte, 1 = short, 2 = long) */ 91 26, /* bitsize */ 92 FALSE, /* pc_relative */ 93 0, /* bitpos */ 94 complain_overflow_signed, /* complain_on_overflow */ 95 bfd_elf_generic_reloc, /* special_function */ 96 "R_OPENRISC_INSN_ABS_26", /* name */ 97 FALSE, /* partial_inplace */ 98 0x00000000, /* src_mask */ 99 0x03ffffff, /* dst_mask */ 100 FALSE), /* pcrel_offset */ 101 102 HOWTO (R_OPENRISC_LO_16_IN_INSN, /* type */ 103 0, /* rightshift */ 104 1, /* size (0 = byte, 1 = short, 2 = long) */ 105 16, /* bitsize */ 106 FALSE, /* pc_relative */ 107 0, /* bitpos */ 108 complain_overflow_dont, /* complain_on_overflow */ 109 bfd_elf_generic_reloc, /* special_function */ 110 "R_OPENRISC_LO_16_IN_INSN", /* name */ 111 FALSE, /* partial_inplace */ 112 0, /* src_mask */ 113 0x0000ffff, /* dst_mask */ 114 FALSE), /* pcrel_offset */ 115 116 HOWTO (R_OPENRISC_HI_16_IN_INSN, /* type */ 117 16, /* rightshift */ 118 1, /* size (0 = byte, 1 = short, 2 = long) */ 119 16, /* bitsize */ 120 FALSE, /* pc_relative */ 121 0, /* bitpos */ 122 complain_overflow_dont, /* complain_on_overflow */ 123 bfd_elf_generic_reloc, /* special_function */ 124 "R_OPENRISC_HI_16_IN_INSN", /* name */ 125 FALSE, /* partial_inplace */ 126 0, /* src_mask */ 127 0x0000ffff, /* dst_mask */ 128 FALSE), /* pcrel_offset */ 129 130 /* An 8 bit absolute relocation. */ 131 HOWTO (R_OPENRISC_8, /* type */ 132 0, /* rightshift */ 133 0, /* size (0 = byte, 1 = short, 2 = long) */ 134 8, /* bitsize */ 135 FALSE, /* pc_relative */ 136 0, /* bitpos */ 137 complain_overflow_bitfield, /* complain_on_overflow */ 138 bfd_elf_generic_reloc, /* special_function */ 139 "R_OPENRISC_8", /* name */ 140 TRUE, /* partial_inplace */ 141 0x0000, /* src_mask */ 142 0x00ff, /* dst_mask */ 143 FALSE), /* pcrel_offset */ 144 145 /* A 16 bit absolute relocation. */ 146 HOWTO (R_OPENRISC_16, /* type */ 147 0, /* rightshift */ 148 1, /* size (0 = byte, 1 = short, 2 = long) */ 149 16, /* bitsize */ 150 FALSE, /* pc_relative */ 151 0, /* bitpos */ 152 complain_overflow_bitfield, /* complain_on_overflow */ 153 bfd_elf_generic_reloc, /* special_function */ 154 "R_OPENRISC_16", /* name */ 155 TRUE, /* partial_inplace */ 156 0x00000000, /* src_mask */ 157 0x0000ffff, /* dst_mask */ 158 FALSE), /* pcrel_offset */ 159 160 /* A 32 bit absolute relocation. */ 161 HOWTO (R_OPENRISC_32, /* type */ 162 0, /* rightshift */ 163 2, /* size (0 = byte, 1 = short, 2 = long) */ 164 32, /* bitsize */ 165 FALSE, /* pc_relative */ 166 0, /* bitpos */ 167 complain_overflow_bitfield, /* complain_on_overflow */ 168 bfd_elf_generic_reloc, /* special_function */ 169 "R_OPENRISC_32", /* name */ 170 TRUE, /* partial_inplace */ 171 0x00000000, /* src_mask */ 172 0xffffffff, /* dst_mask */ 173 FALSE), /* pcrel_offset */ 174 175 /* GNU extension to record C++ vtable hierarchy */ 176 HOWTO (R_OPENRISC_GNU_VTINHERIT, /* type */ 177 0, /* rightshift */ 178 2, /* size (0 = byte, 1 = short, 2 = long) */ 179 0, /* bitsize */ 180 FALSE, /* pc_relative */ 181 0, /* bitpos */ 182 complain_overflow_dont, /* complain_on_overflow */ 183 NULL, /* special_function */ 184 "R_OPENRISC_GNU_VTINHERIT", /* name */ 185 FALSE, /* partial_inplace */ 186 0, /* src_mask */ 187 0, /* dst_mask */ 188 FALSE), /* pcrel_offset */ 189 190 /* GNU extension to record C++ vtable member usage */ 191 HOWTO (R_OPENRISC_GNU_VTENTRY, /* type */ 192 0, /* rightshift */ 193 2, /* size (0 = byte, 1 = short, 2 = long) */ 194 0, /* bitsize */ 195 FALSE, /* pc_relative */ 196 0, /* bitpos */ 197 complain_overflow_dont, /* complain_on_overflow */ 198 _bfd_elf_rel_vtable_reloc_fn, /* special_function */ 199 "R_OPENRISC_GNU_VTENTRY", /* name */ 200 FALSE, /* partial_inplace */ 201 0, /* src_mask */ 202 0, /* dst_mask */ 203 FALSE), /* pcrel_offset */ 204}; 205 206/* Map BFD reloc types to OpenRISC ELF reloc types. */ 207 208struct openrisc_reloc_map 209 { 210 bfd_reloc_code_real_type bfd_reloc_val; 211 unsigned int openrisc_reloc_val; 212 }; 213 214static const struct openrisc_reloc_map openrisc_reloc_map[] = 215 { 216 { BFD_RELOC_NONE, R_OPENRISC_NONE }, 217 { BFD_RELOC_32, R_OPENRISC_32 }, 218 { BFD_RELOC_16, R_OPENRISC_16 }, 219 { BFD_RELOC_8, R_OPENRISC_8 }, 220 { BFD_RELOC_OPENRISC_REL_26,R_OPENRISC_INSN_REL_26 }, 221 { BFD_RELOC_OPENRISC_ABS_26,R_OPENRISC_INSN_ABS_26 }, 222 { BFD_RELOC_HI16, R_OPENRISC_HI_16_IN_INSN }, 223 { BFD_RELOC_LO16, R_OPENRISC_LO_16_IN_INSN }, 224 { BFD_RELOC_VTABLE_INHERIT, R_OPENRISC_GNU_VTINHERIT }, 225 { BFD_RELOC_VTABLE_ENTRY, R_OPENRISC_GNU_VTENTRY } 226 }; 227 228static reloc_howto_type * 229openrisc_reloc_type_lookup (abfd, code) 230 bfd * abfd ATTRIBUTE_UNUSED; 231 bfd_reloc_code_real_type code; 232{ 233 unsigned int i; 234 235 for (i = ARRAY_SIZE (openrisc_reloc_map); --i;) 236 if (openrisc_reloc_map[i].bfd_reloc_val == code) 237 return & openrisc_elf_howto_table[openrisc_reloc_map[i]. 238 openrisc_reloc_val]; 239 240 return NULL; 241} 242 243/* Set the howto pointer for an OpenRISC ELF reloc. */ 244 245static void 246openrisc_info_to_howto_rela (abfd, cache_ptr, dst) 247 bfd * abfd ATTRIBUTE_UNUSED; 248 arelent * cache_ptr; 249 Elf_Internal_Rela * dst; 250{ 251 unsigned int r_type; 252 253 r_type = ELF32_R_TYPE (dst->r_info); 254 BFD_ASSERT (r_type < (unsigned int) R_OPENRISC_max); 255 cache_ptr->howto = & openrisc_elf_howto_table[r_type]; 256} 257 258/* Perform a single relocation. By default we use the standard BFD 259 routines, but a few relocs, we have to do them ourselves. */ 260 261static bfd_reloc_status_type 262openrisc_final_link_relocate (howto, input_bfd, input_section, contents, rel, 263 relocation) 264 reloc_howto_type *howto; 265 bfd *input_bfd; 266 asection *input_section; 267 bfd_byte *contents; 268 Elf_Internal_Rela *rel; 269 bfd_vma relocation; 270{ 271 bfd_reloc_status_type r = bfd_reloc_ok; 272 273 switch (howto->type) 274 { 275 case R_OPENRISC_LO_16_IN_INSN: 276 relocation &= 0xffff; 277 r = _bfd_final_link_relocate (howto, input_bfd, input_section, 278 contents, rel->r_offset, 279 relocation, rel->r_addend); 280 break; 281 282 default: 283 r = _bfd_final_link_relocate (howto, input_bfd, input_section, 284 contents, rel->r_offset, 285 relocation, rel->r_addend); 286 } 287 288 return r; 289} 290 291/* Relocate an OpenRISC ELF section. 292 293 The RELOCATE_SECTION function is called by the new ELF backend linker 294 to handle the relocations for a section. 295 296 The relocs are always passed as Rela structures; if the section 297 actually uses Rel structures, the r_addend field will always be 298 zero. 299 300 This function is responsible for adjusting the section contents as 301 necessary, and (if using Rela relocs and generating a relocatable 302 output file) adjusting the reloc addend as necessary. 303 304 This function does not have to worry about setting the reloc 305 address or the reloc symbol index. 306 307 LOCAL_SYMS is a pointer to the swapped in local symbols. 308 309 LOCAL_SECTIONS is an array giving the section in the input file 310 corresponding to the st_shndx field of each local symbol. 311 312 The global hash table entry for the global symbols can be found 313 via elf_sym_hashes (input_bfd). 314 315 When generating relocatable output, this function must handle 316 STB_LOCAL/STT_SECTION symbols specially. The output symbol is 317 going to be the section symbol corresponding to the output 318 section, which means that the addend must be adjusted 319 accordingly. */ 320 321static bfd_boolean 322openrisc_elf_relocate_section (output_bfd, info, input_bfd, input_section, 323 contents, relocs, local_syms, local_sections) 324 bfd *output_bfd; 325 struct bfd_link_info *info; 326 bfd *input_bfd; 327 asection *input_section; 328 bfd_byte *contents; 329 Elf_Internal_Rela *relocs; 330 Elf_Internal_Sym *local_syms; 331 asection **local_sections; 332{ 333 Elf_Internal_Shdr *symtab_hdr; 334 struct elf_link_hash_entry **sym_hashes; 335 Elf_Internal_Rela *rel; 336 Elf_Internal_Rela *relend; 337 338 if (info->relocatable) 339 return TRUE; 340 341 symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; 342 sym_hashes = elf_sym_hashes (input_bfd); 343 relend = relocs + input_section->reloc_count; 344 345 for (rel = relocs; rel < relend; rel++) 346 { 347 reloc_howto_type *howto; 348 unsigned long r_symndx; 349 Elf_Internal_Sym *sym; 350 asection *sec; 351 struct elf_link_hash_entry *h; 352 bfd_vma relocation; 353 bfd_reloc_status_type r; 354 const char *name = NULL; 355 int r_type; 356 357 r_type = ELF32_R_TYPE (rel->r_info); 358 r_symndx = ELF32_R_SYM (rel->r_info); 359 360 if (r_type == R_OPENRISC_GNU_VTINHERIT 361 || r_type == R_OPENRISC_GNU_VTENTRY) 362 continue; 363 364 if ((unsigned int) r_type > 365 (sizeof openrisc_elf_howto_table / sizeof (reloc_howto_type))) 366 abort (); 367 368 /* This is a final link. */ 369 howto = openrisc_elf_howto_table + ELF32_R_TYPE (rel->r_info); 370 h = NULL; 371 sym = NULL; 372 sec = NULL; 373 374 if (r_symndx < symtab_hdr->sh_info) 375 { 376 sym = local_syms + r_symndx; 377 sec = local_sections[r_symndx]; 378 relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); 379 380 name = bfd_elf_string_from_elf_section 381 (input_bfd, symtab_hdr->sh_link, sym->st_name); 382 name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; 383 } 384 else 385 { 386 bfd_boolean unresolved_reloc, warned; 387 388 RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, 389 r_symndx, symtab_hdr, sym_hashes, 390 h, sec, relocation, 391 unresolved_reloc, warned); 392 } 393 394 r = openrisc_final_link_relocate (howto, input_bfd, input_section, 395 contents, rel, relocation); 396 397 if (r != bfd_reloc_ok) 398 { 399 const char *msg = (const char *) NULL; 400 401 switch (r) 402 { 403 case bfd_reloc_overflow: 404 r = info->callbacks->reloc_overflow 405 (info, name, howto->name, (bfd_vma) 0, 406 input_bfd, input_section, rel->r_offset); 407 break; 408 409 case bfd_reloc_undefined: 410 r = info->callbacks->undefined_symbol 411 (info, name, input_bfd, input_section, rel->r_offset, TRUE); 412 break; 413 414 case bfd_reloc_outofrange: 415 msg = _("internal error: out of range error"); 416 break; 417 418 case bfd_reloc_notsupported: 419 msg = _("internal error: unsupported relocation error"); 420 break; 421 422 case bfd_reloc_dangerous: 423 msg = _("internal error: dangerous relocation"); 424 break; 425 426 default: 427 msg = _("internal error: unknown error"); 428 break; 429 } 430 431 if (msg) 432 r = info->callbacks->warning 433 (info, msg, name, input_bfd, input_section, rel->r_offset); 434 435 if (!r) 436 return FALSE; 437 } 438 } 439 440 return TRUE; 441} 442 443/* Return the section that should be marked against GC for a given 444 relocation. */ 445 446static asection * 447openrisc_elf_gc_mark_hook (sec, info, rel, h, sym) 448 asection *sec; 449 struct bfd_link_info *info ATTRIBUTE_UNUSED; 450 Elf_Internal_Rela *rel; 451 struct elf_link_hash_entry *h; 452 Elf_Internal_Sym *sym; 453{ 454 if (h != NULL) 455 { 456 switch (ELF32_R_TYPE (rel->r_info)) 457 { 458 case R_OPENRISC_GNU_VTINHERIT: 459 case R_OPENRISC_GNU_VTENTRY: 460 break; 461 462 default: 463 switch (h->root.type) 464 { 465 case bfd_link_hash_defined: 466 case bfd_link_hash_defweak: 467 return h->root.u.def.section; 468 469 case bfd_link_hash_common: 470 return h->root.u.c.p->section; 471 472 default: 473 break; 474 } 475 } 476 } 477 else 478 return bfd_section_from_elf_index (sec->owner, sym->st_shndx); 479 480 return NULL; 481} 482 483/* Update the got entry reference counts for the section being removed. */ 484 485static bfd_boolean 486openrisc_elf_gc_sweep_hook (abfd, info, sec, relocs) 487 bfd *abfd ATTRIBUTE_UNUSED; 488 struct bfd_link_info *info ATTRIBUTE_UNUSED; 489 asection *sec ATTRIBUTE_UNUSED; 490 const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED; 491{ 492 return TRUE; 493} 494 495/* Look through the relocs for a section during the first phase. 496 Since we don't do .gots or .plts, we just need to consider the 497 virtual table relocs for gc. */ 498 499static bfd_boolean 500openrisc_elf_check_relocs (abfd, info, sec, relocs) 501 bfd *abfd; 502 struct bfd_link_info *info; 503 asection *sec; 504 const Elf_Internal_Rela *relocs; 505{ 506 Elf_Internal_Shdr *symtab_hdr; 507 struct elf_link_hash_entry **sym_hashes, **sym_hashes_end; 508 const Elf_Internal_Rela *rel; 509 const Elf_Internal_Rela *rel_end; 510 511 if (info->relocatable) 512 return TRUE; 513 514 symtab_hdr = &elf_tdata (abfd)->symtab_hdr; 515 sym_hashes = elf_sym_hashes (abfd); 516 sym_hashes_end = 517 sym_hashes + symtab_hdr->sh_size / sizeof (Elf32_External_Sym); 518 if (!elf_bad_symtab (abfd)) 519 sym_hashes_end -= symtab_hdr->sh_info; 520 521 rel_end = relocs + sec->reloc_count; 522 for (rel = relocs; rel < rel_end; rel++) 523 { 524 struct elf_link_hash_entry *h; 525 unsigned long r_symndx; 526 527 r_symndx = ELF32_R_SYM (rel->r_info); 528 if (r_symndx < symtab_hdr->sh_info) 529 h = NULL; 530 else 531 h = sym_hashes[r_symndx - symtab_hdr->sh_info]; 532 533 switch (ELF32_R_TYPE (rel->r_info)) 534 { 535 /* This relocation describes the C++ object vtable hierarchy. 536 Reconstruct it for later use during GC. */ 537 case R_OPENRISC_GNU_VTINHERIT: 538 if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) 539 return FALSE; 540 break; 541 542 /* This relocation describes which C++ vtable entries are actually 543 used. Record for later use during GC. */ 544 case R_OPENRISC_GNU_VTENTRY: 545 if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) 546 return FALSE; 547 break; 548 } 549 } 550 551 return TRUE; 552} 553 554/* Set the right machine number. */ 555 556static bfd_boolean 557openrisc_elf_object_p (abfd) 558 bfd *abfd; 559{ 560 switch (elf_elfheader (abfd)->e_flags & 0xf) 561 { 562 default: 563 (void) bfd_default_set_arch_mach (abfd, bfd_arch_openrisc, 0); 564 break; 565 } 566 return TRUE; 567} 568 569/* Store the machine number in the flags field. */ 570 571static void 572openrisc_elf_final_write_processing (abfd, linker) 573 bfd *abfd; 574 bfd_boolean linker ATTRIBUTE_UNUSED; 575{ 576 unsigned long val; 577 578 switch (bfd_get_mach (abfd)) 579 { 580 default: 581 val = 0; 582 break; 583 } 584 585 elf_elfheader (abfd)->e_flags &= ~0xf; 586 elf_elfheader (abfd)->e_flags |= val; 587} 588 589 590#define ELF_ARCH bfd_arch_openrisc 591#define ELF_MACHINE_CODE EM_OPENRISC 592#define ELF_MACHINE_ALT1 EM_OPENRISC_OLD 593#define ELF_MAXPAGESIZE 0x1000 594 595#define TARGET_BIG_SYM bfd_elf32_openrisc_vec 596#define TARGET_BIG_NAME "elf32-openrisc" 597 598#define elf_info_to_howto_rel NULL 599#define elf_info_to_howto openrisc_info_to_howto_rela 600#define elf_backend_relocate_section openrisc_elf_relocate_section 601#define elf_backend_gc_mark_hook openrisc_elf_gc_mark_hook 602#define elf_backend_gc_sweep_hook openrisc_elf_gc_sweep_hook 603#define elf_backend_check_relocs openrisc_elf_check_relocs 604 605#define elf_backend_can_gc_sections 1 606#define elf_backend_rela_normal 1 607 608#define bfd_elf32_bfd_reloc_type_lookup openrisc_reloc_type_lookup 609 610#define elf_backend_object_p openrisc_elf_object_p 611#define elf_backend_final_write_processing openrisc_elf_final_write_processing 612 613#include "elf32-target.h" 614