1258945Sroberto/* XSTORMY16-specific support for 32-bit ELF. 2258945Sroberto Copyright 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. 3258945Sroberto 4258945SrobertoThis file is part of BFD, the Binary File Descriptor library. 5258945Sroberto 6258945SrobertoThis program is free software; you can redistribute it and/or modify 7258945Srobertoit under the terms of the GNU General Public License as published by 8258945Srobertothe Free Software Foundation; either version 2 of the License, or 9258945Sroberto(at your option) any later version. 10258945Sroberto 11258945SrobertoThis program is distributed in the hope that it will be useful, 12258945Srobertobut WITHOUT ANY WARRANTY; without even the implied warranty of 13258945SrobertoMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14258945SrobertoGNU General Public License for more details. 15258945Sroberto 16258945SrobertoYou should have received a copy of the GNU General Public License 17258945Srobertoalong with this program; if not, write to the Free Software 18280849ScyFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 19258945Sroberto 20258945Sroberto#include "bfd.h" 21258945Sroberto#include "sysdep.h" 22258945Sroberto#include "libbfd.h" 23258945Sroberto#include "elf-bfd.h" 24258945Sroberto#include "elf/xstormy16.h" 25258945Sroberto#include "libiberty.h" 26258945Sroberto 27258945Sroberto/* Forward declarations. */ 28258945Srobertostatic reloc_howto_type * xstormy16_reloc_type_lookup 29258945Sroberto PARAMS ((bfd *abfd, bfd_reloc_code_real_type code)); 30258945Srobertostatic void xstormy16_info_to_howto_rela 31258945Sroberto PARAMS ((bfd *, arelent *, Elf_Internal_Rela *)); 32258945Srobertostatic bfd_reloc_status_type xstormy16_elf_24_reloc 33258945Sroberto PARAMS ((bfd *abfd, arelent *reloc_entry, asymbol *symbol, 34258945Sroberto PTR data, asection *input_section, bfd *output_bfd, 35258945Sroberto char **error_message)); 36258945Srobertostatic bfd_boolean xstormy16_elf_check_relocs 37258945Sroberto PARAMS ((bfd *, struct bfd_link_info *, asection *, 38258945Sroberto const Elf_Internal_Rela *)); 39258945Srobertostatic bfd_boolean xstormy16_relax_plt_check 40258945Sroberto PARAMS ((struct elf_link_hash_entry *, PTR)); 41258945Srobertostatic bfd_boolean xstormy16_relax_plt_realloc 42258945Sroberto PARAMS ((struct elf_link_hash_entry *, PTR)); 43258945Srobertostatic bfd_boolean xstormy16_elf_relax_section 44258945Sroberto PARAMS ((bfd *abfd, asection *sec, struct bfd_link_info *link_info, 45258945Sroberto bfd_boolean *again)); 46258945Srobertostatic bfd_boolean xstormy16_elf_always_size_sections 47258945Sroberto PARAMS ((bfd *, struct bfd_link_info *)); 48258945Srobertostatic bfd_boolean xstormy16_elf_relocate_section 49258945Sroberto PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, 50258945Sroberto Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)); 51258945Srobertostatic bfd_boolean xstormy16_elf_finish_dynamic_sections 52258945Sroberto PARAMS((bfd *, struct bfd_link_info *)); 53258945Srobertostatic bfd_boolean xstormy16_elf_gc_sweep_hook 54258945Sroberto PARAMS ((bfd *, struct bfd_link_info *, asection *, 55258945Sroberto const Elf_Internal_Rela *)); 56258945Srobertostatic asection * xstormy16_elf_gc_mark_hook 57258945Sroberto PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *, 58258945Sroberto struct elf_link_hash_entry *, Elf_Internal_Sym *)); 59258945Sroberto 60258945Srobertostatic reloc_howto_type xstormy16_elf_howto_table [] = 61258945Sroberto{ 62258945Sroberto /* This reloc does nothing. */ 63258945Sroberto HOWTO (R_XSTORMY16_NONE, /* type */ 64258945Sroberto 0, /* rightshift */ 65258945Sroberto 2, /* size (0 = byte, 1 = short, 2 = long) */ 66258945Sroberto 32, /* bitsize */ 67258945Sroberto FALSE, /* pc_relative */ 68258945Sroberto 0, /* bitpos */ 69258945Sroberto complain_overflow_bitfield, /* complain_on_overflow */ 70258945Sroberto bfd_elf_generic_reloc, /* special_function */ 71258945Sroberto "R_XSTORMY16_NONE", /* name */ 72258945Sroberto FALSE, /* partial_inplace */ 73258945Sroberto 0, /* src_mask */ 74258945Sroberto 0, /* dst_mask */ 75258945Sroberto FALSE), /* pcrel_offset */ 76258945Sroberto 77258945Sroberto /* A 32 bit absolute relocation. */ 78258945Sroberto HOWTO (R_XSTORMY16_32, /* type */ 79258945Sroberto 0, /* rightshift */ 80258945Sroberto 2, /* size (0 = byte, 1 = short, 2 = long) */ 81258945Sroberto 32, /* bitsize */ 82258945Sroberto FALSE, /* pc_relative */ 83258945Sroberto 0, /* bitpos */ 84258945Sroberto complain_overflow_dont, /* complain_on_overflow */ 85258945Sroberto bfd_elf_generic_reloc, /* special_function */ 86258945Sroberto "R_XSTORMY16_32", /* name */ 87258945Sroberto FALSE, /* partial_inplace */ 88258945Sroberto 0, /* src_mask */ 89258945Sroberto 0xffffffff, /* dst_mask */ 90258945Sroberto FALSE), /* pcrel_offset */ 91258945Sroberto 92258945Sroberto /* A 16 bit absolute relocation. */ 93258945Sroberto HOWTO (R_XSTORMY16_16, /* type */ 94258945Sroberto 0, /* rightshift */ 95258945Sroberto 1, /* size (0 = byte, 1 = short, 2 = long) */ 96258945Sroberto 16, /* bitsize */ 97258945Sroberto FALSE, /* pc_relative */ 98258945Sroberto 0, /* bitpos */ 99258945Sroberto complain_overflow_bitfield, /* complain_on_overflow */ 100258945Sroberto bfd_elf_generic_reloc, /* special_function */ 101258945Sroberto "R_XSTORMY16_16", /* name */ 102258945Sroberto FALSE, /* partial_inplace */ 103258945Sroberto 0, /* src_mask */ 104258945Sroberto 0xffff, /* dst_mask */ 105258945Sroberto FALSE), /* pcrel_offset */ 106258945Sroberto 107258945Sroberto /* An 8 bit absolute relocation. */ 108258945Sroberto HOWTO (R_XSTORMY16_8, /* type */ 109258945Sroberto 0, /* rightshift */ 110258945Sroberto 0, /* size (0 = byte, 1 = short, 2 = long) */ 111258945Sroberto 8, /* bitsize */ 112258945Sroberto FALSE, /* pc_relative */ 113258945Sroberto 0, /* bitpos */ 114258945Sroberto complain_overflow_unsigned, /* complain_on_overflow */ 115258945Sroberto bfd_elf_generic_reloc, /* special_function */ 116258945Sroberto "R_XSTORMY16_8", /* name */ 117258945Sroberto FALSE, /* partial_inplace */ 118258945Sroberto 0, /* src_mask */ 119258945Sroberto 0xff, /* dst_mask */ 120258945Sroberto FALSE), /* pcrel_offset */ 121258945Sroberto 122258945Sroberto /* A 32 bit pc-relative relocation. */ 123258945Sroberto HOWTO (R_XSTORMY16_PC32, /* type */ 124258945Sroberto 0, /* rightshift */ 125258945Sroberto 2, /* size (0 = byte, 1 = short, 2 = long) */ 126258945Sroberto 32, /* bitsize */ 127258945Sroberto TRUE, /* pc_relative */ 128258945Sroberto 0, /* bitpos */ 129258945Sroberto complain_overflow_dont, /* complain_on_overflow */ 130258945Sroberto bfd_elf_generic_reloc, /* special_function */ 131258945Sroberto "R_XSTORMY16_PC32", /* name */ 132258945Sroberto FALSE, /* partial_inplace */ 133258945Sroberto 0, /* src_mask */ 134258945Sroberto 0xffffffff, /* dst_mask */ 135258945Sroberto TRUE), /* pcrel_offset */ 136258945Sroberto 137258945Sroberto /* A 16 bit pc-relative relocation. */ 138258945Sroberto HOWTO (R_XSTORMY16_PC16, /* type */ 139258945Sroberto 0, /* rightshift */ 140258945Sroberto 1, /* size (0 = byte, 1 = short, 2 = long) */ 141258945Sroberto 16, /* bitsize */ 142258945Sroberto TRUE, /* pc_relative */ 143258945Sroberto 0, /* bitpos */ 144258945Sroberto complain_overflow_signed, /* complain_on_overflow */ 145258945Sroberto bfd_elf_generic_reloc, /* special_function */ 146258945Sroberto "R_XSTORMY16_PC16", /* name */ 147258945Sroberto FALSE, /* partial_inplace */ 148258945Sroberto 0, /* src_mask */ 149258945Sroberto 0xffffffff, /* dst_mask */ 150258945Sroberto TRUE), /* pcrel_offset */ 151258945Sroberto 152258945Sroberto /* An 8 bit pc-relative relocation. */ 153258945Sroberto HOWTO (R_XSTORMY16_PC8, /* type */ 154258945Sroberto 0, /* rightshift */ 155258945Sroberto 0, /* size (0 = byte, 1 = short, 2 = long) */ 156258945Sroberto 8, /* bitsize */ 157258945Sroberto TRUE, /* pc_relative */ 158258945Sroberto 0, /* bitpos */ 159258945Sroberto complain_overflow_signed, /* complain_on_overflow */ 160258945Sroberto bfd_elf_generic_reloc, /* special_function */ 161258945Sroberto "R_XSTORMY16_PC8", /* name */ 162258945Sroberto FALSE, /* partial_inplace */ 163258945Sroberto 0, /* src_mask */ 164258945Sroberto 0xffffffff, /* dst_mask */ 165258945Sroberto TRUE), /* pcrel_offset */ 166258945Sroberto 167258945Sroberto /* A 12-bit pc-relative relocation suitable for the branch instructions. */ 168258945Sroberto HOWTO (R_XSTORMY16_REL_12, /* type */ 169258945Sroberto 1, /* rightshift */ 170258945Sroberto 1, /* size (0 = byte, 1 = short, 2 = long) */ 171258945Sroberto 11, /* bitsize */ 172258945Sroberto TRUE, /* pc_relative */ 173258945Sroberto 1, /* bitpos */ 174258945Sroberto complain_overflow_signed, /* complain_on_overflow */ 175258945Sroberto bfd_elf_generic_reloc, /* special_function */ 176258945Sroberto "R_XSTORMY16_REL_12", /* name */ 177258945Sroberto FALSE, /* partial_inplace */ 178258945Sroberto 0, /* src_mask */ 179258945Sroberto 0x0ffe, /* dst_mask */ 180258945Sroberto TRUE), /* pcrel_offset */ 181258945Sroberto 182258945Sroberto /* A 24-bit absolute relocation suitable for the jump instructions. */ 183258945Sroberto HOWTO (R_XSTORMY16_24, /* type */ 184258945Sroberto 0, /* rightshift */ 185258945Sroberto 2, /* size (0 = byte, 1 = short, 2 = long) */ 186258945Sroberto 24, /* bitsize */ 187258945Sroberto FALSE, /* pc_relative */ 188258945Sroberto 0, /* bitpos */ 189258945Sroberto complain_overflow_unsigned, /* complain_on_overflow */ 190258945Sroberto xstormy16_elf_24_reloc, /* special_function */ 191258945Sroberto "R_XSTORMY16_24", /* name */ 192258945Sroberto TRUE, /* partial_inplace */ 193258945Sroberto 0, /* src_mask */ 194258945Sroberto 0xffff00ff, /* dst_mask */ 195258945Sroberto TRUE), /* pcrel_offset */ 196258945Sroberto 197258945Sroberto /* A 16 bit absolute relocation to a function pointer. */ 198258945Sroberto HOWTO (R_XSTORMY16_FPTR16, /* type */ 199258945Sroberto 0, /* rightshift */ 200258945Sroberto 1, /* size (0 = byte, 1 = short, 2 = long) */ 201258945Sroberto 16, /* bitsize */ 202258945Sroberto FALSE, /* pc_relative */ 203258945Sroberto 0, /* bitpos */ 204258945Sroberto complain_overflow_bitfield, /* complain_on_overflow */ 205258945Sroberto bfd_elf_generic_reloc, /* special_function */ 206258945Sroberto "R_XSTORMY16_FPTR16", /* name */ 207258945Sroberto FALSE, /* partial_inplace */ 208258945Sroberto 0, /* src_mask */ 209258945Sroberto 0xffffffff, /* dst_mask */ 210258945Sroberto FALSE), /* pcrel_offset */ 211258945Sroberto 212258945Sroberto /* Low order 16 bit value of a high memory address. */ 213258945Sroberto HOWTO (R_XSTORMY16_LO16, /* type */ 214258945Sroberto 0, /* rightshift */ 215258945Sroberto 1, /* size (0 = byte, 1 = short, 2 = long) */ 216258945Sroberto 16, /* bitsize */ 217258945Sroberto FALSE, /* pc_relative */ 218258945Sroberto 0, /* bitpos */ 219258945Sroberto complain_overflow_dont, /* complain_on_overflow */ 220258945Sroberto bfd_elf_generic_reloc, /* special_function */ 221258945Sroberto "R_XSTORMY16_LO16", /* name */ 222258945Sroberto FALSE, /* partial_inplace */ 223258945Sroberto 0, /* src_mask */ 224258945Sroberto 0xffff, /* dst_mask */ 225258945Sroberto FALSE), /* pcrel_offset */ 226258945Sroberto 227258945Sroberto /* High order 16 bit value of a high memory address. */ 228258945Sroberto HOWTO (R_XSTORMY16_HI16, /* type */ 229258945Sroberto 16, /* rightshift */ 230258945Sroberto 1, /* size (0 = byte, 1 = short, 2 = long) */ 231258945Sroberto 16, /* bitsize */ 232258945Sroberto FALSE, /* pc_relative */ 233258945Sroberto 0, /* bitpos */ 234258945Sroberto complain_overflow_dont, /* complain_on_overflow */ 235258945Sroberto bfd_elf_generic_reloc, /* special_function */ 236258945Sroberto "R_XSTORMY16_HI16", /* name */ 237258945Sroberto FALSE, /* partial_inplace */ 238258945Sroberto 0, /* src_mask */ 239258945Sroberto 0xffff, /* dst_mask */ 240258945Sroberto FALSE), /* pcrel_offset */ 241258945Sroberto 242258945Sroberto /* A 12 bit absolute relocation. */ 243258945Sroberto HOWTO (R_XSTORMY16_12, /* type */ 244258945Sroberto 0, /* rightshift */ 245258945Sroberto 1, /* size (0 = byte, 1 = short, 2 = long) */ 246258945Sroberto 12, /* bitsize */ 247258945Sroberto FALSE, /* pc_relative */ 248258945Sroberto 0, /* bitpos */ 249258945Sroberto complain_overflow_signed, /* complain_on_overflow */ 250258945Sroberto bfd_elf_generic_reloc, /* special_function */ 251258945Sroberto "R_XSTORMY16_12", /* name */ 252258945Sroberto FALSE, /* partial_inplace */ 253258945Sroberto 0x0000, /* src_mask */ 254258945Sroberto 0x0fff, /* dst_mask */ 255258945Sroberto FALSE), /* pcrel_offset */ 256258945Sroberto}; 257258945Sroberto 258258945Srobertostatic reloc_howto_type xstormy16_elf_howto_table2 [] = 259258945Sroberto{ 260258945Sroberto /* GNU extension to record C++ vtable hierarchy */ 261258945Sroberto HOWTO (R_XSTORMY16_GNU_VTINHERIT, /* type */ 262258945Sroberto 0, /* rightshift */ 263258945Sroberto 2, /* size (0 = byte, 1 = short, 2 = long) */ 264258945Sroberto 0, /* bitsize */ 265258945Sroberto FALSE, /* pc_relative */ 266258945Sroberto 0, /* bitpos */ 267258945Sroberto complain_overflow_dont, /* complain_on_overflow */ 268258945Sroberto NULL, /* special_function */ 269258945Sroberto "R_XSTORMY16_GNU_VTINHERIT", /* name */ 270258945Sroberto FALSE, /* partial_inplace */ 271258945Sroberto 0, /* src_mask */ 272258945Sroberto 0, /* dst_mask */ 273258945Sroberto FALSE), /* pcrel_offset */ 274258945Sroberto 275258945Sroberto /* GNU extension to record C++ vtable member usage */ 276258945Sroberto HOWTO (R_XSTORMY16_GNU_VTENTRY, /* type */ 277258945Sroberto 0, /* rightshift */ 278258945Sroberto 2, /* size (0 = byte, 1 = short, 2 = long) */ 279258945Sroberto 0, /* bitsize */ 280258945Sroberto FALSE, /* pc_relative */ 281258945Sroberto 0, /* bitpos */ 282258945Sroberto complain_overflow_dont, /* complain_on_overflow */ 283258945Sroberto _bfd_elf_rel_vtable_reloc_fn, /* special_function */ 284258945Sroberto "R_XSTORMY16_GNU_VTENTRY", /* name */ 285258945Sroberto FALSE, /* partial_inplace */ 286258945Sroberto 0, /* src_mask */ 287258945Sroberto 0, /* dst_mask */ 288258945Sroberto FALSE), /* pcrel_offset */ 289258945Sroberto 290258945Sroberto}; 291258945Sroberto 292258945Sroberto/* Map BFD reloc types to XSTORMY16 ELF reloc types. */ 293258945Sroberto 294258945Srobertotypedef struct xstormy16_reloc_map 295258945Sroberto{ 296258945Sroberto bfd_reloc_code_real_type bfd_reloc_val; 297258945Sroberto unsigned int xstormy16_reloc_val; 298258945Sroberto reloc_howto_type * table; 299258945Sroberto} reloc_map; 300258945Sroberto 301258945Srobertostatic const reloc_map xstormy16_reloc_map [] = 302258945Sroberto{ 303258945Sroberto { BFD_RELOC_NONE, R_XSTORMY16_NONE, xstormy16_elf_howto_table }, 304258945Sroberto { BFD_RELOC_32, R_XSTORMY16_32, xstormy16_elf_howto_table }, 305258945Sroberto { BFD_RELOC_16, R_XSTORMY16_16, xstormy16_elf_howto_table }, 306258945Sroberto { BFD_RELOC_8, R_XSTORMY16_8, xstormy16_elf_howto_table }, 307258945Sroberto { BFD_RELOC_32_PCREL, R_XSTORMY16_PC32, xstormy16_elf_howto_table }, 308258945Sroberto { BFD_RELOC_16_PCREL, R_XSTORMY16_PC16, xstormy16_elf_howto_table }, 309258945Sroberto { BFD_RELOC_8_PCREL, R_XSTORMY16_PC8, xstormy16_elf_howto_table }, 310258945Sroberto { BFD_RELOC_XSTORMY16_REL_12, R_XSTORMY16_REL_12, xstormy16_elf_howto_table }, 311258945Sroberto { BFD_RELOC_XSTORMY16_24, R_XSTORMY16_24, xstormy16_elf_howto_table }, 312258945Sroberto { BFD_RELOC_XSTORMY16_FPTR16, R_XSTORMY16_FPTR16, xstormy16_elf_howto_table }, 313258945Sroberto { BFD_RELOC_LO16, R_XSTORMY16_LO16, xstormy16_elf_howto_table }, 314258945Sroberto { BFD_RELOC_HI16, R_XSTORMY16_HI16, xstormy16_elf_howto_table }, 315258945Sroberto { BFD_RELOC_XSTORMY16_12, R_XSTORMY16_12, xstormy16_elf_howto_table }, 316258945Sroberto { BFD_RELOC_VTABLE_INHERIT, R_XSTORMY16_GNU_VTINHERIT, xstormy16_elf_howto_table2 }, 317258945Sroberto { BFD_RELOC_VTABLE_ENTRY, R_XSTORMY16_GNU_VTENTRY, xstormy16_elf_howto_table2 }, 318258945Sroberto}; 319258945Sroberto 320258945Srobertostatic reloc_howto_type * 321258945Srobertoxstormy16_reloc_type_lookup (abfd, code) 322258945Sroberto bfd * abfd ATTRIBUTE_UNUSED; 323258945Sroberto bfd_reloc_code_real_type code; 324258945Sroberto{ 325258945Sroberto unsigned int i; 326258945Sroberto 327258945Sroberto for (i = ARRAY_SIZE (xstormy16_reloc_map); --i;) 328258945Sroberto { 329258945Sroberto const reloc_map * entry; 330258945Sroberto 331258945Sroberto entry = xstormy16_reloc_map + i; 332258945Sroberto 333258945Sroberto if (entry->bfd_reloc_val == code) 334258945Sroberto return entry->table + (entry->xstormy16_reloc_val 335 - entry->table[0].type); 336 } 337 338 return NULL; 339} 340 341/* Set the howto pointer for an XSTORMY16 ELF reloc. */ 342 343static void 344xstormy16_info_to_howto_rela (abfd, cache_ptr, dst) 345 bfd * abfd ATTRIBUTE_UNUSED; 346 arelent * cache_ptr; 347 Elf_Internal_Rela * dst; 348{ 349 unsigned int r_type = ELF32_R_TYPE (dst->r_info); 350 351 if (r_type <= (unsigned int) R_XSTORMY16_12) 352 cache_ptr->howto = &xstormy16_elf_howto_table [r_type]; 353 else if (r_type - R_XSTORMY16_GNU_VTINHERIT 354 <= (unsigned int) R_XSTORMY16_GNU_VTENTRY) 355 cache_ptr->howto 356 = &xstormy16_elf_howto_table2 [r_type - R_XSTORMY16_GNU_VTINHERIT]; 357 else 358 abort (); 359} 360 361/* Handle the R_XSTORMY16_24 reloc, which has an odd bit arrangement. */ 362 363static bfd_reloc_status_type 364xstormy16_elf_24_reloc (abfd, reloc_entry, symbol, data, input_section, 365 output_bfd, error_message) 366 bfd *abfd; 367 arelent *reloc_entry; 368 asymbol *symbol; 369 PTR data; 370 asection *input_section; 371 bfd *output_bfd; 372 char **error_message ATTRIBUTE_UNUSED; 373{ 374 bfd_vma relocation, x; 375 376 if (output_bfd != NULL) 377 { 378 reloc_entry->address += input_section->output_offset; 379 return bfd_reloc_ok; 380 } 381 382 if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) 383 return bfd_reloc_outofrange; 384 385 if (bfd_is_com_section (symbol->section)) 386 relocation = 0; 387 else 388 relocation = symbol->value; 389 390 relocation += symbol->section->output_section->vma; 391 relocation += symbol->section->output_offset; 392 relocation += reloc_entry->addend; 393 394 x = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); 395 x &= 0x0000ff00; 396 x |= relocation & 0xff; 397 x |= (relocation << 8) & 0xffff0000; 398 bfd_put_32 (abfd, x, (bfd_byte *) data + reloc_entry->address); 399 400 if (relocation & ~ (bfd_vma) 0xffffff) 401 return bfd_reloc_overflow; 402 403 return bfd_reloc_ok; 404} 405 406/* We support 16-bit pointers to code above 64k by generating a thunk 407 below 64k containing a JMPF instruction to the final address. We 408 cannot, unfortunately, minimize the number of thunks unless the 409 -relax switch is given, as otherwise we have no idea where the 410 sections will fall in the address space. */ 411 412static bfd_boolean 413xstormy16_elf_check_relocs (abfd, info, sec, relocs) 414 bfd *abfd; 415 struct bfd_link_info *info; 416 asection *sec; 417 const Elf_Internal_Rela *relocs; 418{ 419 const Elf_Internal_Rela *rel, *relend; 420 struct elf_link_hash_entry **sym_hashes; 421 Elf_Internal_Shdr *symtab_hdr; 422 bfd_vma *local_plt_offsets; 423 asection *splt; 424 bfd *dynobj; 425 426 if (info->relocatable) 427 return TRUE; 428 429 symtab_hdr = &elf_tdata(abfd)->symtab_hdr; 430 sym_hashes = elf_sym_hashes (abfd); 431 local_plt_offsets = elf_local_got_offsets (abfd); 432 splt = NULL; 433 dynobj = elf_hash_table(info)->dynobj; 434 435 relend = relocs + sec->reloc_count; 436 for (rel = relocs; rel < relend; ++rel) 437 { 438 unsigned long r_symndx; 439 struct elf_link_hash_entry *h; 440 bfd_vma *offset; 441 442 r_symndx = ELF32_R_SYM (rel->r_info); 443 if (r_symndx < symtab_hdr->sh_info) 444 h = NULL; 445 else 446 { 447 h = sym_hashes[r_symndx - symtab_hdr->sh_info]; 448 while (h->root.type == bfd_link_hash_indirect 449 || h->root.type == bfd_link_hash_warning) 450 h = (struct elf_link_hash_entry *) h->root.u.i.link; 451 } 452 453 switch (ELF32_R_TYPE (rel->r_info)) 454 { 455 /* This relocation describes a 16-bit pointer to a function. 456 We may need to allocate a thunk in low memory; reserve memory 457 for it now. */ 458 case R_XSTORMY16_FPTR16: 459 if (rel->r_addend != 0) 460 { 461 (*info->callbacks->warning) 462 (info, _("non-zero addend in @fptr reloc"), 0, 463 abfd, 0, 0); 464 } 465 466 if (dynobj == NULL) 467 elf_hash_table (info)->dynobj = dynobj = abfd; 468 if (splt == NULL) 469 { 470 splt = bfd_get_section_by_name (dynobj, ".plt"); 471 if (splt == NULL) 472 { 473 splt = bfd_make_section (dynobj, ".plt"); 474 if (splt == NULL 475 || ! bfd_set_section_flags (dynobj, splt, 476 (SEC_ALLOC 477 | SEC_LOAD 478 | SEC_HAS_CONTENTS 479 | SEC_IN_MEMORY 480 | SEC_LINKER_CREATED 481 | SEC_READONLY 482 | SEC_CODE)) 483 || ! bfd_set_section_alignment (dynobj, splt, 1)) 484 return FALSE; 485 } 486 } 487 488 if (h != NULL) 489 offset = &h->plt.offset; 490 else 491 { 492 if (local_plt_offsets == NULL) 493 { 494 size_t size; 495 unsigned int i; 496 497 size = symtab_hdr->sh_info * sizeof (bfd_vma); 498 local_plt_offsets = (bfd_vma *) bfd_alloc (abfd, size); 499 if (local_plt_offsets == NULL) 500 return FALSE; 501 elf_local_got_offsets (abfd) = local_plt_offsets; 502 503 for (i = 0; i < symtab_hdr->sh_info; i++) 504 local_plt_offsets[i] = (bfd_vma) -1; 505 } 506 offset = &local_plt_offsets[r_symndx]; 507 } 508 509 if (*offset == (bfd_vma) -1) 510 { 511 *offset = splt->size; 512 splt->size += 4; 513 } 514 break; 515 516 /* This relocation describes the C++ object vtable hierarchy. 517 Reconstruct it for later use during GC. */ 518 case R_XSTORMY16_GNU_VTINHERIT: 519 if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) 520 return FALSE; 521 break; 522 523 /* This relocation describes which C++ vtable entries are actually 524 used. Record for later use during GC. */ 525 case R_XSTORMY16_GNU_VTENTRY: 526 if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) 527 return FALSE; 528 break; 529 } 530 } 531 532 return TRUE; 533} 534 535/* A subroutine of xstormy16_elf_relax_section. If the global symbol H 536 is within the low 64k, remove any entry for it in the plt. */ 537 538struct relax_plt_data 539{ 540 asection *splt; 541 bfd_boolean *again; 542}; 543 544static bfd_boolean 545xstormy16_relax_plt_check (h, xdata) 546 struct elf_link_hash_entry *h; 547 PTR xdata; 548{ 549 struct relax_plt_data *data = (struct relax_plt_data *) xdata; 550 551 if (h->root.type == bfd_link_hash_warning) 552 h = (struct elf_link_hash_entry *) h->root.u.i.link; 553 554 if (h->plt.offset != (bfd_vma) -1) 555 { 556 bfd_vma address; 557 558 if (h->root.type == bfd_link_hash_undefined 559 || h->root.type == bfd_link_hash_undefweak) 560 address = 0; 561 else 562 address = (h->root.u.def.section->output_section->vma 563 + h->root.u.def.section->output_offset 564 + h->root.u.def.value); 565 566 if (address <= 0xffff) 567 { 568 h->plt.offset = -1; 569 data->splt->size -= 4; 570 *data->again = TRUE; 571 } 572 } 573 574 return TRUE; 575} 576 577/* A subroutine of xstormy16_elf_relax_section. If the global symbol H 578 previously had a plt entry, give it a new entry offset. */ 579 580static bfd_boolean 581xstormy16_relax_plt_realloc (h, xdata) 582 struct elf_link_hash_entry *h; 583 PTR xdata; 584{ 585 bfd_vma *entry = (bfd_vma *) xdata; 586 587 if (h->root.type == bfd_link_hash_warning) 588 h = (struct elf_link_hash_entry *) h->root.u.i.link; 589 590 if (h->plt.offset != (bfd_vma) -1) 591 { 592 h->plt.offset = *entry; 593 *entry += 4; 594 } 595 596 return TRUE; 597} 598 599static bfd_boolean 600xstormy16_elf_relax_section (dynobj, splt, info, again) 601 bfd *dynobj; 602 asection *splt; 603 struct bfd_link_info *info; 604 bfd_boolean *again; 605{ 606 struct relax_plt_data relax_plt_data; 607 bfd *ibfd; 608 609 /* Assume nothing changes. */ 610 *again = FALSE; 611 612 if (info->relocatable) 613 return TRUE; 614 615 /* We only relax the .plt section at the moment. */ 616 if (dynobj != elf_hash_table (info)->dynobj 617 || strcmp (splt->name, ".plt") != 0) 618 return TRUE; 619 620 /* Quick check for an empty plt. */ 621 if (splt->size == 0) 622 return TRUE; 623 624 /* Map across all global symbols; see which ones happen to 625 fall in the low 64k. */ 626 relax_plt_data.splt = splt; 627 relax_plt_data.again = again; 628 elf_link_hash_traverse (elf_hash_table (info), xstormy16_relax_plt_check, 629 &relax_plt_data); 630 631 /* Likewise for local symbols, though that's somewhat less convenient 632 as we have to walk the list of input bfds and swap in symbol data. */ 633 for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next) 634 { 635 bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd); 636 Elf_Internal_Shdr *symtab_hdr; 637 Elf_Internal_Sym *isymbuf = NULL; 638 unsigned int idx; 639 640 if (! local_plt_offsets) 641 continue; 642 643 symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; 644 if (symtab_hdr->sh_info != 0) 645 { 646 isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; 647 if (isymbuf == NULL) 648 isymbuf = bfd_elf_get_elf_syms (ibfd, symtab_hdr, 649 symtab_hdr->sh_info, 0, 650 NULL, NULL, NULL); 651 if (isymbuf == NULL) 652 return FALSE; 653 } 654 655 for (idx = 0; idx < symtab_hdr->sh_info; ++idx) 656 { 657 Elf_Internal_Sym *isym; 658 asection *tsec; 659 bfd_vma address; 660 661 if (local_plt_offsets[idx] == (bfd_vma) -1) 662 continue; 663 664 isym = &isymbuf[idx]; 665 if (isym->st_shndx == SHN_UNDEF) 666 continue; 667 else if (isym->st_shndx == SHN_ABS) 668 tsec = bfd_abs_section_ptr; 669 else if (isym->st_shndx == SHN_COMMON) 670 tsec = bfd_com_section_ptr; 671 else 672 tsec = bfd_section_from_elf_index (ibfd, isym->st_shndx); 673 674 address = (tsec->output_section->vma 675 + tsec->output_offset 676 + isym->st_value); 677 if (address <= 0xffff) 678 { 679 local_plt_offsets[idx] = -1; 680 splt->size -= 4; 681 *again = TRUE; 682 } 683 } 684 685 if (isymbuf != NULL 686 && symtab_hdr->contents != (unsigned char *) isymbuf) 687 { 688 if (! info->keep_memory) 689 free (isymbuf); 690 else 691 { 692 /* Cache the symbols for elf_link_input_bfd. */ 693 symtab_hdr->contents = (unsigned char *) isymbuf; 694 } 695 } 696 } 697 698 /* If we changed anything, walk the symbols again to reallocate 699 .plt entry addresses. */ 700 if (*again && splt->size > 0) 701 { 702 bfd_vma entry = 0; 703 704 elf_link_hash_traverse (elf_hash_table (info), 705 xstormy16_relax_plt_realloc, &entry); 706 707 for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next) 708 { 709 bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd); 710 unsigned int nlocals = elf_tdata (ibfd)->symtab_hdr.sh_info; 711 unsigned int idx; 712 713 if (! local_plt_offsets) 714 continue; 715 716 for (idx = 0; idx < nlocals; ++idx) 717 if (local_plt_offsets[idx] != (bfd_vma) -1) 718 { 719 local_plt_offsets[idx] = entry; 720 entry += 4; 721 } 722 } 723 } 724 725 return TRUE; 726} 727 728static bfd_boolean 729xstormy16_elf_always_size_sections (output_bfd, info) 730 bfd *output_bfd ATTRIBUTE_UNUSED; 731 struct bfd_link_info *info; 732{ 733 bfd *dynobj; 734 asection *splt; 735 736 if (info->relocatable) 737 return TRUE; 738 739 dynobj = elf_hash_table (info)->dynobj; 740 if (dynobj == NULL) 741 return TRUE; 742 743 splt = bfd_get_section_by_name (dynobj, ".plt"); 744 BFD_ASSERT (splt != NULL); 745 746 splt->contents = (bfd_byte *) bfd_zalloc (dynobj, splt->size); 747 if (splt->contents == NULL) 748 return FALSE; 749 750 return TRUE; 751} 752 753/* Relocate an XSTORMY16 ELF section. 754 755 The RELOCATE_SECTION function is called by the new ELF backend linker 756 to handle the relocations for a section. 757 758 The relocs are always passed as Rela structures; if the section 759 actually uses Rel structures, the r_addend field will always be 760 zero. 761 762 This function is responsible for adjusting the section contents as 763 necessary, and (if using Rela relocs and generating a relocatable 764 output file) adjusting the reloc addend as necessary. 765 766 This function does not have to worry about setting the reloc 767 address or the reloc symbol index. 768 769 LOCAL_SYMS is a pointer to the swapped in local symbols. 770 771 LOCAL_SECTIONS is an array giving the section in the input file 772 corresponding to the st_shndx field of each local symbol. 773 774 The global hash table entry for the global symbols can be found 775 via elf_sym_hashes (input_bfd). 776 777 When generating relocatable output, this function must handle 778 STB_LOCAL/STT_SECTION symbols specially. The output symbol is 779 going to be the section symbol corresponding to the output 780 section, which means that the addend must be adjusted 781 accordingly. */ 782 783static bfd_boolean 784xstormy16_elf_relocate_section (output_bfd, info, input_bfd, input_section, 785 contents, relocs, local_syms, local_sections) 786 bfd * output_bfd ATTRIBUTE_UNUSED; 787 struct bfd_link_info * info; 788 bfd * input_bfd; 789 asection * input_section; 790 bfd_byte * contents; 791 Elf_Internal_Rela * relocs; 792 Elf_Internal_Sym * local_syms; 793 asection ** local_sections; 794{ 795 Elf_Internal_Shdr * symtab_hdr; 796 struct elf_link_hash_entry ** sym_hashes; 797 Elf_Internal_Rela * rel; 798 Elf_Internal_Rela * relend; 799 bfd *dynobj; 800 asection *splt; 801 802 if (info->relocatable) 803 return TRUE; 804 805 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; 806 sym_hashes = elf_sym_hashes (input_bfd); 807 relend = relocs + input_section->reloc_count; 808 809 dynobj = elf_hash_table (info)->dynobj; 810 splt = NULL; 811 if (dynobj != NULL) 812 splt = bfd_get_section_by_name (dynobj, ".plt"); 813 814 for (rel = relocs; rel < relend; rel ++) 815 { 816 reloc_howto_type * howto; 817 unsigned long r_symndx; 818 Elf_Internal_Sym * sym; 819 asection * sec; 820 struct elf_link_hash_entry * h; 821 bfd_vma relocation; 822 bfd_reloc_status_type r; 823 const char * name = NULL; 824 int r_type; 825 826 r_type = ELF32_R_TYPE (rel->r_info); 827 828 if ( r_type == R_XSTORMY16_GNU_VTINHERIT 829 || r_type == R_XSTORMY16_GNU_VTENTRY) 830 continue; 831 832 r_symndx = ELF32_R_SYM (rel->r_info); 833 howto = xstormy16_elf_howto_table + ELF32_R_TYPE (rel->r_info); 834 h = NULL; 835 sym = NULL; 836 sec = NULL; 837 838 if (r_symndx < symtab_hdr->sh_info) 839 { 840 sym = local_syms + r_symndx; 841 sec = local_sections [r_symndx]; 842 relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); 843 } 844 else 845 { 846 bfd_boolean unresolved_reloc, warned; 847 848 RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, 849 r_symndx, symtab_hdr, sym_hashes, 850 h, sec, relocation, 851 unresolved_reloc, warned); 852 } 853 854 if (h != NULL) 855 name = h->root.root.string; 856 else 857 { 858 name = (bfd_elf_string_from_elf_section 859 (input_bfd, symtab_hdr->sh_link, sym->st_name)); 860 if (name == NULL || *name == '\0') 861 name = bfd_section_name (input_bfd, sec); 862 } 863 864 switch (ELF32_R_TYPE (rel->r_info)) 865 { 866 case R_XSTORMY16_24: 867 { 868 bfd_vma reloc = relocation + rel->r_addend; 869 unsigned int x; 870 871 x = bfd_get_32 (input_bfd, contents + rel->r_offset); 872 x &= 0x0000ff00; 873 x |= reloc & 0xff; 874 x |= (reloc << 8) & 0xffff0000; 875 bfd_put_32 (input_bfd, x, contents + rel->r_offset); 876 877 if (reloc & ~0xffffff) 878 r = bfd_reloc_overflow; 879 else 880 r = bfd_reloc_ok; 881 break; 882 } 883 884 case R_XSTORMY16_FPTR16: 885 { 886 bfd_vma *plt_offset; 887 888 if (h != NULL) 889 plt_offset = &h->plt.offset; 890 else 891 plt_offset = elf_local_got_offsets (input_bfd) + r_symndx; 892 893 if (relocation <= 0xffff) 894 { 895 /* If the symbol is in range for a 16-bit address, we should 896 have deallocated the plt entry in relax_section. */ 897 BFD_ASSERT (*plt_offset == (bfd_vma) -1); 898 } 899 else 900 { 901 /* If the symbol is out of range for a 16-bit address, 902 we must have allocated a plt entry. */ 903 BFD_ASSERT (*plt_offset != (bfd_vma) -1); 904 905 /* If this is the first time we've processed this symbol, 906 fill in the plt entry with the correct symbol address. */ 907 if ((*plt_offset & 1) == 0) 908 { 909 unsigned int x; 910 911 x = 0x00000200; /* jmpf */ 912 x |= relocation & 0xff; 913 x |= (relocation << 8) & 0xffff0000; 914 bfd_put_32 (input_bfd, x, splt->contents + *plt_offset); 915 *plt_offset |= 1; 916 } 917 918 relocation = (splt->output_section->vma 919 + splt->output_offset 920 + (*plt_offset & -2)); 921 } 922 r = _bfd_final_link_relocate (howto, input_bfd, input_section, 923 contents, rel->r_offset, 924 relocation, 0); 925 break; 926 } 927 928 default: 929 r = _bfd_final_link_relocate (howto, input_bfd, input_section, 930 contents, rel->r_offset, 931 relocation, rel->r_addend); 932 break; 933 } 934 935 if (r != bfd_reloc_ok) 936 { 937 const char * msg = (const char *) NULL; 938 939 switch (r) 940 { 941 case bfd_reloc_overflow: 942 r = info->callbacks->reloc_overflow 943 (info, name, howto->name, (bfd_vma) 0, 944 input_bfd, input_section, rel->r_offset); 945 break; 946 947 case bfd_reloc_undefined: 948 r = info->callbacks->undefined_symbol 949 (info, name, input_bfd, input_section, rel->r_offset, 950 TRUE); 951 break; 952 953 case bfd_reloc_outofrange: 954 msg = _("internal error: out of range error"); 955 break; 956 957 case bfd_reloc_notsupported: 958 msg = _("internal error: unsupported relocation error"); 959 break; 960 961 case bfd_reloc_dangerous: 962 msg = _("internal error: dangerous relocation"); 963 break; 964 965 default: 966 msg = _("internal error: unknown error"); 967 break; 968 } 969 970 if (msg) 971 r = info->callbacks->warning 972 (info, msg, name, input_bfd, input_section, rel->r_offset); 973 974 if (! r) 975 return FALSE; 976 } 977 } 978 979 return TRUE; 980} 981 982/* This must exist if dynobj is ever set. */ 983 984static bfd_boolean 985xstormy16_elf_finish_dynamic_sections (abfd, info) 986 bfd *abfd ATTRIBUTE_UNUSED; 987 struct bfd_link_info *info; 988{ 989 bfd *dynobj; 990 asection *splt; 991 992 /* As an extra sanity check, verify that all plt entries have 993 been filled in. */ 994 995 if ((dynobj = elf_hash_table (info)->dynobj) != NULL 996 && (splt = bfd_get_section_by_name (dynobj, ".plt")) != NULL) 997 { 998 bfd_byte *contents = splt->contents; 999 unsigned int i, size = splt->size; 1000 for (i = 0; i < size; i += 4) 1001 { 1002 unsigned int x = bfd_get_32 (dynobj, contents + i); 1003 BFD_ASSERT (x != 0); 1004 } 1005 } 1006 1007 return TRUE; 1008} 1009 1010/* Return the section that should be marked against GC for a given 1011 relocation. */ 1012 1013static asection * 1014xstormy16_elf_gc_mark_hook (sec, info, rel, h, sym) 1015 asection * sec; 1016 struct bfd_link_info * info ATTRIBUTE_UNUSED; 1017 Elf_Internal_Rela * rel; 1018 struct elf_link_hash_entry * h; 1019 Elf_Internal_Sym * sym; 1020{ 1021 if (h != NULL) 1022 { 1023 switch (ELF32_R_TYPE (rel->r_info)) 1024 { 1025 case R_XSTORMY16_GNU_VTINHERIT: 1026 case R_XSTORMY16_GNU_VTENTRY: 1027 break; 1028 1029 default: 1030 switch (h->root.type) 1031 { 1032 case bfd_link_hash_defined: 1033 case bfd_link_hash_defweak: 1034 return h->root.u.def.section; 1035 1036 case bfd_link_hash_common: 1037 return h->root.u.c.p->section; 1038 1039 default: 1040 break; 1041 } 1042 } 1043 } 1044 else 1045 return bfd_section_from_elf_index (sec->owner, sym->st_shndx); 1046 1047 return NULL; 1048} 1049 1050/* Update the got entry reference counts for the section being removed. */ 1051 1052static bfd_boolean 1053xstormy16_elf_gc_sweep_hook (abfd, info, sec, relocs) 1054 bfd * abfd ATTRIBUTE_UNUSED; 1055 struct bfd_link_info * info ATTRIBUTE_UNUSED; 1056 asection * sec ATTRIBUTE_UNUSED; 1057 const Elf_Internal_Rela * relocs ATTRIBUTE_UNUSED; 1058{ 1059 return TRUE; 1060} 1061 1062#define ELF_ARCH bfd_arch_xstormy16 1063#define ELF_MACHINE_CODE EM_XSTORMY16 1064#define ELF_MAXPAGESIZE 0x100 1065 1066#define TARGET_LITTLE_SYM bfd_elf32_xstormy16_vec 1067#define TARGET_LITTLE_NAME "elf32-xstormy16" 1068 1069#define elf_info_to_howto_rel NULL 1070#define elf_info_to_howto xstormy16_info_to_howto_rela 1071#define elf_backend_relocate_section xstormy16_elf_relocate_section 1072#define elf_backend_gc_mark_hook xstormy16_elf_gc_mark_hook 1073#define elf_backend_gc_sweep_hook xstormy16_elf_gc_sweep_hook 1074#define elf_backend_check_relocs xstormy16_elf_check_relocs 1075#define elf_backend_always_size_sections \ 1076 xstormy16_elf_always_size_sections 1077#define elf_backend_finish_dynamic_sections \ 1078 xstormy16_elf_finish_dynamic_sections 1079 1080#define elf_backend_can_gc_sections 1 1081#define elf_backend_rela_normal 1 1082 1083#define bfd_elf32_bfd_reloc_type_lookup xstormy16_reloc_type_lookup 1084#define bfd_elf32_bfd_relax_section xstormy16_elf_relax_section 1085 1086#include "elf32-target.h" 1087