1/* D10V-specific support for 32-bit ELF 2 Copyright 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 3 Free Software Foundation, Inc. 4 Contributed by Martin Hunt (hunt@cygnus.com). 5 6 This file is part of BFD, the Binary File Descriptor library. 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 21 MA 02110-1301, USA. */ 22 23#include "bfd.h" 24#include "sysdep.h" 25#include "libbfd.h" 26#include "elf-bfd.h" 27#include "elf/d10v.h" 28 29/* Use REL instead of RELA to save space. */ 30#define USE_REL 1 31 32static reloc_howto_type elf_d10v_howto_table[] = 33{ 34 /* This reloc does nothing. */ 35 HOWTO (R_D10V_NONE, /* Type. */ 36 0, /* Rightshift. */ 37 2, /* Size (0 = byte, 1 = short, 2 = long). */ 38 32, /* Bitsize. */ 39 FALSE, /* PC_relative. */ 40 0, /* Bitpos. */ 41 complain_overflow_dont,/* Complain_on_overflow. */ 42 bfd_elf_generic_reloc, /* Special_function. */ 43 "R_D10V_NONE", /* Name. */ 44 FALSE, /* Partial_inplace. */ 45 0, /* Src_mask. */ 46 0, /* Dst_mask. */ 47 FALSE), /* PCrel_offset. */ 48 49 /* An PC Relative 10-bit relocation, shifted by 2, right container. */ 50 HOWTO (R_D10V_10_PCREL_R, /* Type. */ 51 2, /* Rightshift. */ 52 2, /* Size (0 = byte, 1 = short, 2 = long). */ 53 8, /* Bitsize. */ 54 TRUE, /* PC_relative. */ 55 0, /* Bitpos. */ 56 complain_overflow_signed, /* Complain_on_overflow. */ 57 bfd_elf_generic_reloc, /* Special_function. */ 58 "R_D10V_10_PCREL_R", /* Name. */ 59 FALSE, /* Partial_inplace. */ 60 0xff, /* Src_mask. */ 61 0xff, /* Dst_mask. */ 62 TRUE), /* PCrel_offset. */ 63 64 /* An PC Relative 10-bit relocation, shifted by 2, left container. */ 65 HOWTO (R_D10V_10_PCREL_L, /* Type. */ 66 2, /* Rightshift. */ 67 2, /* Size (0 = byte, 1 = short, 2 = long). */ 68 8, /* Bitsize. */ 69 TRUE, /* PC_relative. */ 70 15, /* Bitpos. */ 71 complain_overflow_signed, /* Complain_on_overflow. */ 72 bfd_elf_generic_reloc, /* Special_function. */ 73 "R_D10V_10_PCREL_L", /* Name. */ 74 FALSE, /* Partial_inplace. */ 75 0x07f8000, /* Src_mask. */ 76 0x07f8000, /* Dst_mask. */ 77 TRUE), /* PCrel_offset. */ 78 79 /* A 16 bit absolute relocation. */ 80 HOWTO (R_D10V_16, /* Type. */ 81 0, /* Rightshift. */ 82 1, /* Size (0 = byte, 1 = short, 2 = long). */ 83 16, /* Bitsize. */ 84 FALSE, /* PC_relative. */ 85 0, /* Bitpos. */ 86 complain_overflow_dont,/* Complain_on_overflow. */ 87 bfd_elf_generic_reloc, /* Special_function. */ 88 "R_D10V_16", /* Name. */ 89 FALSE, /* Partial_inplace. */ 90 0xffff, /* Src_mask. */ 91 0xffff, /* Dst_mask. */ 92 FALSE), /* PCrel_offset. */ 93 94 /* An 18 bit absolute relocation, right shifted 2. */ 95 HOWTO (R_D10V_18, /* Type. */ 96 2, /* Rightshift. */ 97 1, /* Size (0 = byte, 1 = short, 2 = long). */ 98 16, /* Bitsize. */ 99 FALSE, /* PC_relative. */ 100 0, /* Bitpos. */ 101 complain_overflow_dont, /* Complain_on_overflow. */ 102 bfd_elf_generic_reloc, /* Special_function. */ 103 "R_D10V_18", /* Name. */ 104 FALSE, /* Partial_inplace. */ 105 0xffff, /* Src_mask. */ 106 0xffff, /* Dst_mask. */ 107 FALSE), /* PCrel_offset. */ 108 109 /* A relative 18 bit relocation, right shifted by 2. */ 110 HOWTO (R_D10V_18_PCREL, /* Type. */ 111 2, /* Rightshift. */ 112 2, /* Size (0 = byte, 1 = short, 2 = long). */ 113 16, /* Bitsize. */ 114 TRUE, /* PC_relative. */ 115 0, /* Bitpos. */ 116 complain_overflow_signed, /* Complain_on_overflow. */ 117 bfd_elf_generic_reloc, /* Special_function. */ 118 "R_D10V_18_PCREL", /* Name. */ 119 FALSE, /* Partial_inplace. */ 120 0xffff, /* Src_mask. */ 121 0xffff, /* Dst_mask. */ 122 TRUE), /* PCrel_offset. */ 123 124 /* A 32 bit absolute relocation. */ 125 HOWTO (R_D10V_32, /* Type. */ 126 0, /* Rightshift. */ 127 2, /* Size (0 = byte, 1 = short, 2 = long). */ 128 32, /* Bitsize. */ 129 FALSE, /* PC_relative. */ 130 0, /* Bitpos. */ 131 complain_overflow_dont,/* Complain_on_overflow. */ 132 bfd_elf_generic_reloc, /* Special_function. */ 133 "R_D10V_32", /* Name. */ 134 FALSE, /* Partial_inplace. */ 135 0xffffffff, /* Src_mask. */ 136 0xffffffff, /* Dst_mask. */ 137 FALSE), /* PCrel_offset. */ 138 139 /* GNU extension to record C++ vtable hierarchy. */ 140 HOWTO (R_D10V_GNU_VTINHERIT, /* Type. */ 141 0, /* Rightshift. */ 142 2, /* Size (0 = byte, 1 = short, 2 = long). */ 143 0, /* Bitsize. */ 144 FALSE, /* PC_relative. */ 145 0, /* Bitpos. */ 146 complain_overflow_dont,/* Complain_on_overflow. */ 147 NULL, /* Special_function. */ 148 "R_D10V_GNU_VTINHERIT",/* Name. */ 149 FALSE, /* Partial_inplace. */ 150 0, /* Src_mask. */ 151 0, /* Dst_mask. */ 152 FALSE), /* PCrel_offset. */ 153 154 /* GNU extension to record C++ vtable member usage. */ 155 HOWTO (R_D10V_GNU_VTENTRY, /* Type. */ 156 0, /* Rightshift. */ 157 2, /* Size (0 = byte, 1 = short, 2 = long). */ 158 0, /* Bitsize. */ 159 FALSE, /* PC_relative. */ 160 0, /* Bitpos. */ 161 complain_overflow_dont,/* Complain_on_overflow. */ 162 _bfd_elf_rel_vtable_reloc_fn, /* Special_function. */ 163 "R_D10V_GNU_VTENTRY", /* Name. */ 164 FALSE, /* Partial_inplace. */ 165 0, /* Src_mask. */ 166 0, /* Dst_mask. */ 167 FALSE), /* PCrel_offset. */ 168}; 169 170/* Map BFD reloc types to D10V ELF reloc types. */ 171 172struct d10v_reloc_map 173{ 174 bfd_reloc_code_real_type bfd_reloc_val; 175 unsigned char elf_reloc_val; 176}; 177 178static const struct d10v_reloc_map d10v_reloc_map[] = 179{ 180 { BFD_RELOC_NONE, R_D10V_NONE, }, 181 { BFD_RELOC_D10V_10_PCREL_R, R_D10V_10_PCREL_R }, 182 { BFD_RELOC_D10V_10_PCREL_L, R_D10V_10_PCREL_L }, 183 { BFD_RELOC_16, R_D10V_16 }, 184 { BFD_RELOC_D10V_18, R_D10V_18 }, 185 { BFD_RELOC_D10V_18_PCREL, R_D10V_18_PCREL }, 186 { BFD_RELOC_32, R_D10V_32 }, 187 { BFD_RELOC_VTABLE_INHERIT, R_D10V_GNU_VTINHERIT }, 188 { BFD_RELOC_VTABLE_ENTRY, R_D10V_GNU_VTENTRY }, 189}; 190 191static reloc_howto_type * 192bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, 193 bfd_reloc_code_real_type code) 194{ 195 unsigned int i; 196 197 for (i = 0; 198 i < sizeof (d10v_reloc_map) / sizeof (struct d10v_reloc_map); 199 i++) 200 if (d10v_reloc_map[i].bfd_reloc_val == code) 201 return &elf_d10v_howto_table[d10v_reloc_map[i].elf_reloc_val]; 202 203 return NULL; 204} 205 206/* Set the howto pointer for an D10V ELF reloc. */ 207 208static void 209d10v_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, 210 arelent *cache_ptr, 211 Elf_Internal_Rela *dst) 212{ 213 unsigned int r_type; 214 215 r_type = ELF32_R_TYPE (dst->r_info); 216 BFD_ASSERT (r_type < (unsigned int) R_D10V_max); 217 cache_ptr->howto = &elf_d10v_howto_table[r_type]; 218} 219 220static asection * 221elf32_d10v_gc_mark_hook (asection *sec, 222 struct bfd_link_info *info, 223 Elf_Internal_Rela *rel, 224 struct elf_link_hash_entry *h, 225 Elf_Internal_Sym *sym) 226{ 227 if (h != NULL) 228 switch (ELF32_R_TYPE (rel->r_info)) 229 { 230 case R_D10V_GNU_VTINHERIT: 231 case R_D10V_GNU_VTENTRY: 232 return NULL; 233 } 234 235 return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); 236} 237 238/* Look through the relocs for a section during the first phase. 239 Since we don't do .gots or .plts, we just need to consider the 240 virtual table relocs for gc. */ 241 242static bfd_boolean 243elf32_d10v_check_relocs (bfd *abfd, 244 struct bfd_link_info *info, 245 asection *sec, 246 const Elf_Internal_Rela *relocs) 247{ 248 Elf_Internal_Shdr *symtab_hdr; 249 struct elf_link_hash_entry **sym_hashes, **sym_hashes_end; 250 const Elf_Internal_Rela *rel; 251 const Elf_Internal_Rela *rel_end; 252 253 if (info->relocatable) 254 return TRUE; 255 256 symtab_hdr = &elf_tdata (abfd)->symtab_hdr; 257 sym_hashes = elf_sym_hashes (abfd); 258 sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym); 259 if (!elf_bad_symtab (abfd)) 260 sym_hashes_end -= symtab_hdr->sh_info; 261 262 rel_end = relocs + sec->reloc_count; 263 for (rel = relocs; rel < rel_end; rel++) 264 { 265 struct elf_link_hash_entry *h; 266 unsigned long r_symndx; 267 268 r_symndx = ELF32_R_SYM (rel->r_info); 269 if (r_symndx < symtab_hdr->sh_info) 270 h = NULL; 271 else 272 { 273 h = sym_hashes[r_symndx - symtab_hdr->sh_info]; 274 while (h->root.type == bfd_link_hash_indirect 275 || h->root.type == bfd_link_hash_warning) 276 h = (struct elf_link_hash_entry *) h->root.u.i.link; 277 } 278 279 switch (ELF32_R_TYPE (rel->r_info)) 280 { 281 /* This relocation describes the C++ object vtable hierarchy. 282 Reconstruct it for later use during GC. */ 283 case R_D10V_GNU_VTINHERIT: 284 if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) 285 return FALSE; 286 break; 287 288 /* This relocation describes which C++ vtable entries are actually 289 used. Record for later use during GC. */ 290 case R_D10V_GNU_VTENTRY: 291 if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset)) 292 return FALSE; 293 break; 294 } 295 } 296 297 return TRUE; 298} 299 300static bfd_vma 301extract_rel_addend (bfd *abfd, 302 bfd_byte *where, 303 reloc_howto_type *howto) 304{ 305 bfd_vma insn, val; 306 307 switch (howto->size) 308 { 309 case 0: 310 insn = bfd_get_8 (abfd, where); 311 break; 312 case 1: 313 insn = bfd_get_16 (abfd, where); 314 break; 315 case 2: 316 insn = bfd_get_32 (abfd, where); 317 break; 318 default: 319 abort (); 320 } 321 322 val = (insn & howto->dst_mask) >> howto->bitpos << howto->rightshift; 323 /* We should really be testing for signed addends here, but we don't 324 have that info directly in the howto. */ 325 if (howto->pc_relative) 326 { 327 bfd_vma sign; 328 sign = howto->dst_mask & (~howto->dst_mask >> 1 | ~(-(bfd_vma) 1 >> 1)); 329 sign = sign >> howto->bitpos << howto->rightshift; 330 val = (val ^ sign) - sign; 331 } 332 return val; 333} 334 335static void 336insert_rel_addend (bfd *abfd, 337 bfd_byte *where, 338 reloc_howto_type *howto, 339 bfd_vma addend) 340{ 341 bfd_vma insn; 342 343 addend = (addend >> howto->rightshift << howto->bitpos) & howto->dst_mask; 344 insn = ~howto->dst_mask; 345 switch (howto->size) 346 { 347 case 0: 348 insn &= bfd_get_8 (abfd, where); 349 insn |= addend; 350 bfd_put_8 (abfd, insn, where); 351 break; 352 case 1: 353 insn &= bfd_get_16 (abfd, where); 354 insn |= addend; 355 bfd_put_16 (abfd, insn, where); 356 break; 357 case 2: 358 insn &= bfd_get_32 (abfd, where); 359 insn |= addend; 360 bfd_put_32 (abfd, insn, where); 361 break; 362 default: 363 abort (); 364 } 365} 366 367/* Relocate a D10V ELF section. */ 368 369static bfd_boolean 370elf32_d10v_relocate_section (bfd *output_bfd, 371 struct bfd_link_info *info, 372 bfd *input_bfd, 373 asection *input_section, 374 bfd_byte *contents, 375 Elf_Internal_Rela *relocs, 376 Elf_Internal_Sym *local_syms, 377 asection **local_sections) 378{ 379 Elf_Internal_Shdr *symtab_hdr; 380 struct elf_link_hash_entry **sym_hashes; 381 Elf_Internal_Rela *rel, *relend; 382 const char *name; 383 384 symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; 385 sym_hashes = elf_sym_hashes (input_bfd); 386 387 rel = relocs; 388 relend = relocs + input_section->reloc_count; 389 for (; rel < relend; rel++) 390 { 391 int r_type; 392 reloc_howto_type *howto; 393 unsigned long r_symndx; 394 Elf_Internal_Sym *sym; 395 asection *sec; 396 struct elf_link_hash_entry *h; 397 bfd_vma relocation; 398 bfd_reloc_status_type r; 399 400 r_symndx = ELF32_R_SYM (rel->r_info); 401 r_type = ELF32_R_TYPE (rel->r_info); 402 403 if (r_type == R_D10V_GNU_VTENTRY 404 || r_type == R_D10V_GNU_VTINHERIT) 405 continue; 406 407 howto = elf_d10v_howto_table + r_type; 408 409 if (info->relocatable) 410 { 411 bfd_vma val; 412 bfd_byte *where; 413 414 /* This is a relocatable link. We don't have to change 415 anything, unless the reloc is against a section symbol, 416 in which case we have to adjust according to where the 417 section symbol winds up in the output section. */ 418 if (r_symndx >= symtab_hdr->sh_info) 419 continue; 420 421 sym = local_syms + r_symndx; 422 if (ELF_ST_TYPE (sym->st_info) != STT_SECTION) 423 continue; 424 425 sec = local_sections[r_symndx]; 426 val = sec->output_offset; 427 if (val == 0) 428 continue; 429 430 where = contents + rel->r_offset; 431 val += extract_rel_addend (input_bfd, where, howto); 432 insert_rel_addend (input_bfd, where, howto, val); 433 continue; 434 } 435 436 /* This is a final link. */ 437 h = NULL; 438 sym = NULL; 439 sec = NULL; 440 if (r_symndx < symtab_hdr->sh_info) 441 { 442 sym = local_syms + r_symndx; 443 sec = local_sections[r_symndx]; 444 relocation = (sec->output_section->vma 445 + sec->output_offset 446 + sym->st_value); 447 if ((sec->flags & SEC_MERGE) 448 && ELF_ST_TYPE (sym->st_info) == STT_SECTION) 449 { 450 asection *msec; 451 bfd_vma addend; 452 bfd_byte *where = contents + rel->r_offset; 453 454 addend = extract_rel_addend (input_bfd, where, howto); 455 msec = sec; 456 addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend); 457 addend -= relocation; 458 addend += msec->output_section->vma + msec->output_offset; 459 insert_rel_addend (input_bfd, where, howto, addend); 460 } 461 } 462 else 463 { 464 bfd_boolean unresolved_reloc, warned; 465 466 RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, 467 r_symndx, symtab_hdr, sym_hashes, 468 h, sec, relocation, 469 unresolved_reloc, warned); 470 } 471 472 if (r_symndx == 0) 473 { 474 /* r_symndx will be zero only for relocs against symbols from 475 removed linkonce sections, or sections discarded by a linker 476 script. For these relocs, we just want the section contents 477 zeroed. Avoid any special processing. */ 478 _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset); 479 continue; 480 } 481 482 if (h != NULL) 483 name = h->root.root.string; 484 else 485 { 486 name = (bfd_elf_string_from_elf_section 487 (input_bfd, symtab_hdr->sh_link, sym->st_name)); 488 if (name == NULL || *name == '\0') 489 name = bfd_section_name (input_bfd, sec); 490 } 491 492 r = _bfd_final_link_relocate (howto, input_bfd, input_section, 493 contents, rel->r_offset, 494 relocation, (bfd_vma) 0); 495 496 if (r != bfd_reloc_ok) 497 { 498 const char * msg = (const char *) 0; 499 500 switch (r) 501 { 502 case bfd_reloc_overflow: 503 if (!((*info->callbacks->reloc_overflow) 504 (info, (h ? &h->root : NULL), name, howto->name, 505 (bfd_vma) 0, input_bfd, input_section, 506 rel->r_offset))) 507 return FALSE; 508 break; 509 510 case bfd_reloc_undefined: 511 if (!((*info->callbacks->undefined_symbol) 512 (info, name, input_bfd, input_section, 513 rel->r_offset, TRUE))) 514 return FALSE; 515 break; 516 517 case bfd_reloc_outofrange: 518 msg = _("internal error: out of range error"); 519 goto common_error; 520 521 case bfd_reloc_notsupported: 522 msg = _("internal error: unsupported relocation error"); 523 goto common_error; 524 525 case bfd_reloc_dangerous: 526 msg = _("internal error: dangerous error"); 527 goto common_error; 528 529 default: 530 msg = _("internal error: unknown error"); 531 /* fall through */ 532 533 common_error: 534 if (!((*info->callbacks->warning) 535 (info, msg, name, input_bfd, input_section, 536 rel->r_offset))) 537 return FALSE; 538 break; 539 } 540 } 541 } 542 543 return TRUE; 544} 545#define ELF_ARCH bfd_arch_d10v 546#define ELF_MACHINE_CODE EM_D10V 547#define ELF_MACHINE_ALT1 EM_CYGNUS_D10V 548#define ELF_MAXPAGESIZE 0x1000 549 550#define TARGET_BIG_SYM bfd_elf32_d10v_vec 551#define TARGET_BIG_NAME "elf32-d10v" 552 553#define elf_info_to_howto 0 554#define elf_info_to_howto_rel d10v_info_to_howto_rel 555#define elf_backend_object_p 0 556#define elf_backend_final_write_processing 0 557#define elf_backend_gc_mark_hook elf32_d10v_gc_mark_hook 558#define elf_backend_check_relocs elf32_d10v_check_relocs 559#define elf_backend_relocate_section elf32_d10v_relocate_section 560#define elf_backend_can_gc_sections 1 561 562#include "elf32-target.h" 563