1214571Sdim/* SPU specific support for 32-bit ELF 2214571Sdim 3214571Sdim Copyright 2006, 2007 Free Software Foundation, Inc. 4214571Sdim 5214571Sdim This file is part of BFD, the Binary File Descriptor library. 6214571Sdim 7214571Sdim This program is free software; you can redistribute it and/or modify 8214571Sdim it under the terms of the GNU General Public License as published by 9214571Sdim the Free Software Foundation; either version 2 of the License, or 10214571Sdim (at your option) any later version. 11214571Sdim 12214571Sdim This program is distributed in the hope that it will be useful, 13214571Sdim but WITHOUT ANY WARRANTY; without even the implied warranty of 14214571Sdim MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15214571Sdim GNU General Public License for more details. 16214571Sdim 17214571Sdim You should have received a copy of the GNU General Public License along 18214571Sdim with this program; if not, write to the Free Software Foundation, Inc., 19214571Sdim 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 20214571Sdim 21214571Sdim#include "sysdep.h" 22214571Sdim#include "bfd.h" 23214571Sdim#include "bfdlink.h" 24214571Sdim#include "libbfd.h" 25214571Sdim#include "elf-bfd.h" 26214571Sdim#include "elf/spu.h" 27214571Sdim#include "elf32-spu.h" 28214571Sdim 29214571Sdim/* We use RELA style relocs. Don't define USE_REL. */ 30214571Sdim 31214571Sdimstatic bfd_reloc_status_type spu_elf_rel9 (bfd *, arelent *, asymbol *, 32214571Sdim void *, asection *, 33214571Sdim bfd *, char **); 34214571Sdim 35214571Sdim/* Values of type 'enum elf_spu_reloc_type' are used to index this 36214571Sdim array, so it must be declared in the order of that type. */ 37214571Sdim 38214571Sdimstatic reloc_howto_type elf_howto_table[] = { 39214571Sdim HOWTO (R_SPU_NONE, 0, 0, 0, FALSE, 0, complain_overflow_dont, 40214571Sdim bfd_elf_generic_reloc, "SPU_NONE", 41214571Sdim FALSE, 0, 0x00000000, FALSE), 42214571Sdim HOWTO (R_SPU_ADDR10, 4, 2, 10, FALSE, 14, complain_overflow_bitfield, 43214571Sdim bfd_elf_generic_reloc, "SPU_ADDR10", 44214571Sdim FALSE, 0, 0x00ffc000, FALSE), 45214571Sdim HOWTO (R_SPU_ADDR16, 2, 2, 16, FALSE, 7, complain_overflow_bitfield, 46214571Sdim bfd_elf_generic_reloc, "SPU_ADDR16", 47214571Sdim FALSE, 0, 0x007fff80, FALSE), 48214571Sdim HOWTO (R_SPU_ADDR16_HI, 16, 2, 16, FALSE, 7, complain_overflow_bitfield, 49214571Sdim bfd_elf_generic_reloc, "SPU_ADDR16_HI", 50214571Sdim FALSE, 0, 0x007fff80, FALSE), 51214571Sdim HOWTO (R_SPU_ADDR16_LO, 0, 2, 16, FALSE, 7, complain_overflow_dont, 52214571Sdim bfd_elf_generic_reloc, "SPU_ADDR16_LO", 53214571Sdim FALSE, 0, 0x007fff80, FALSE), 54214571Sdim HOWTO (R_SPU_ADDR18, 0, 2, 18, FALSE, 7, complain_overflow_bitfield, 55214571Sdim bfd_elf_generic_reloc, "SPU_ADDR18", 56214571Sdim FALSE, 0, 0x01ffff80, FALSE), 57214571Sdim HOWTO (R_SPU_ADDR32, 0, 2, 32, FALSE, 0, complain_overflow_dont, 58214571Sdim bfd_elf_generic_reloc, "SPU_ADDR32", 59214571Sdim FALSE, 0, 0xffffffff, FALSE), 60214571Sdim HOWTO (R_SPU_REL16, 2, 2, 16, TRUE, 7, complain_overflow_bitfield, 61214571Sdim bfd_elf_generic_reloc, "SPU_REL16", 62214571Sdim FALSE, 0, 0x007fff80, TRUE), 63214571Sdim HOWTO (R_SPU_ADDR7, 0, 2, 7, FALSE, 14, complain_overflow_dont, 64214571Sdim bfd_elf_generic_reloc, "SPU_ADDR7", 65214571Sdim FALSE, 0, 0x001fc000, FALSE), 66214571Sdim HOWTO (R_SPU_REL9, 2, 2, 9, TRUE, 0, complain_overflow_signed, 67214571Sdim spu_elf_rel9, "SPU_REL9", 68214571Sdim FALSE, 0, 0x0180007f, TRUE), 69214571Sdim HOWTO (R_SPU_REL9I, 2, 2, 9, TRUE, 0, complain_overflow_signed, 70214571Sdim spu_elf_rel9, "SPU_REL9I", 71214571Sdim FALSE, 0, 0x0000c07f, TRUE), 72214571Sdim HOWTO (R_SPU_ADDR10I, 0, 2, 10, FALSE, 14, complain_overflow_signed, 73214571Sdim bfd_elf_generic_reloc, "SPU_ADDR10I", 74214571Sdim FALSE, 0, 0x00ffc000, FALSE), 75214571Sdim HOWTO (R_SPU_ADDR16I, 0, 2, 16, FALSE, 7, complain_overflow_signed, 76214571Sdim bfd_elf_generic_reloc, "SPU_ADDR16I", 77214571Sdim FALSE, 0, 0x007fff80, FALSE), 78214571Sdim HOWTO (R_SPU_REL32, 0, 2, 32, TRUE, 0, complain_overflow_dont, 79214571Sdim bfd_elf_generic_reloc, "SPU_REL32", 80214571Sdim FALSE, 0, 0xffffffff, TRUE), 81214571Sdim HOWTO (R_SPU_ADDR16X, 0, 2, 16, FALSE, 7, complain_overflow_bitfield, 82214571Sdim bfd_elf_generic_reloc, "SPU_ADDR16X", 83214571Sdim FALSE, 0, 0x007fff80, FALSE), 84214571Sdim HOWTO (R_SPU_PPU32, 0, 2, 32, FALSE, 0, complain_overflow_dont, 85214571Sdim bfd_elf_generic_reloc, "SPU_PPU32", 86214571Sdim FALSE, 0, 0xffffffff, FALSE), 87214571Sdim HOWTO (R_SPU_PPU64, 0, 4, 64, FALSE, 0, complain_overflow_dont, 88214571Sdim bfd_elf_generic_reloc, "SPU_PPU64", 89214571Sdim FALSE, 0, -1, FALSE), 90214571Sdim}; 91214571Sdim 92214571Sdimstatic struct bfd_elf_special_section const spu_elf_special_sections[] = { 93214571Sdim { ".toe", 4, 0, SHT_NOBITS, SHF_ALLOC }, 94214571Sdim { NULL, 0, 0, 0, 0 } 95214571Sdim}; 96214571Sdim 97214571Sdimstatic enum elf_spu_reloc_type 98214571Sdimspu_elf_bfd_to_reloc_type (bfd_reloc_code_real_type code) 99214571Sdim{ 100214571Sdim switch (code) 101214571Sdim { 102214571Sdim default: 103214571Sdim return R_SPU_NONE; 104214571Sdim case BFD_RELOC_SPU_IMM10W: 105214571Sdim return R_SPU_ADDR10; 106214571Sdim case BFD_RELOC_SPU_IMM16W: 107214571Sdim return R_SPU_ADDR16; 108214571Sdim case BFD_RELOC_SPU_LO16: 109214571Sdim return R_SPU_ADDR16_LO; 110214571Sdim case BFD_RELOC_SPU_HI16: 111214571Sdim return R_SPU_ADDR16_HI; 112214571Sdim case BFD_RELOC_SPU_IMM18: 113214571Sdim return R_SPU_ADDR18; 114214571Sdim case BFD_RELOC_SPU_PCREL16: 115214571Sdim return R_SPU_REL16; 116214571Sdim case BFD_RELOC_SPU_IMM7: 117214571Sdim return R_SPU_ADDR7; 118214571Sdim case BFD_RELOC_SPU_IMM8: 119214571Sdim return R_SPU_NONE; 120214571Sdim case BFD_RELOC_SPU_PCREL9a: 121214571Sdim return R_SPU_REL9; 122214571Sdim case BFD_RELOC_SPU_PCREL9b: 123214571Sdim return R_SPU_REL9I; 124214571Sdim case BFD_RELOC_SPU_IMM10: 125214571Sdim return R_SPU_ADDR10I; 126214571Sdim case BFD_RELOC_SPU_IMM16: 127214571Sdim return R_SPU_ADDR16I; 128214571Sdim case BFD_RELOC_32: 129214571Sdim return R_SPU_ADDR32; 130214571Sdim case BFD_RELOC_32_PCREL: 131214571Sdim return R_SPU_REL32; 132214571Sdim case BFD_RELOC_SPU_PPU32: 133214571Sdim return R_SPU_PPU32; 134214571Sdim case BFD_RELOC_SPU_PPU64: 135214571Sdim return R_SPU_PPU64; 136214571Sdim } 137214571Sdim} 138214571Sdim 139214571Sdimstatic void 140214571Sdimspu_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, 141214571Sdim arelent *cache_ptr, 142214571Sdim Elf_Internal_Rela *dst) 143214571Sdim{ 144214571Sdim enum elf_spu_reloc_type r_type; 145214571Sdim 146214571Sdim r_type = (enum elf_spu_reloc_type) ELF32_R_TYPE (dst->r_info); 147214571Sdim BFD_ASSERT (r_type < R_SPU_max); 148214571Sdim cache_ptr->howto = &elf_howto_table[(int) r_type]; 149214571Sdim} 150214571Sdim 151214571Sdimstatic reloc_howto_type * 152214571Sdimspu_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, 153214571Sdim bfd_reloc_code_real_type code) 154214571Sdim{ 155214571Sdim enum elf_spu_reloc_type r_type = spu_elf_bfd_to_reloc_type (code); 156214571Sdim 157214571Sdim if (r_type == R_SPU_NONE) 158214571Sdim return NULL; 159214571Sdim 160214571Sdim return elf_howto_table + r_type; 161214571Sdim} 162214571Sdim 163214571Sdimstatic reloc_howto_type * 164214571Sdimspu_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, 165214571Sdim const char *r_name) 166214571Sdim{ 167214571Sdim unsigned int i; 168214571Sdim 169214571Sdim for (i = 0; i < sizeof (elf_howto_table) / sizeof (elf_howto_table[0]); i++) 170214571Sdim if (elf_howto_table[i].name != NULL 171214571Sdim && strcasecmp (elf_howto_table[i].name, r_name) == 0) 172214571Sdim return &elf_howto_table[i]; 173214571Sdim 174214571Sdim return NULL; 175214571Sdim} 176214571Sdim 177214571Sdim/* Apply R_SPU_REL9 and R_SPU_REL9I relocs. */ 178214571Sdim 179214571Sdimstatic bfd_reloc_status_type 180214571Sdimspu_elf_rel9 (bfd *abfd, arelent *reloc_entry, asymbol *symbol, 181214571Sdim void *data, asection *input_section, 182214571Sdim bfd *output_bfd, char **error_message) 183214571Sdim{ 184214571Sdim bfd_size_type octets; 185214571Sdim bfd_vma val; 186214571Sdim long insn; 187214571Sdim 188214571Sdim /* If this is a relocatable link (output_bfd test tells us), just 189214571Sdim call the generic function. Any adjustment will be done at final 190214571Sdim link time. */ 191214571Sdim if (output_bfd != NULL) 192214571Sdim return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, 193214571Sdim input_section, output_bfd, error_message); 194214571Sdim 195214571Sdim if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) 196214571Sdim return bfd_reloc_outofrange; 197214571Sdim octets = reloc_entry->address * bfd_octets_per_byte (abfd); 198214571Sdim 199214571Sdim /* Get symbol value. */ 200214571Sdim val = 0; 201214571Sdim if (!bfd_is_com_section (symbol->section)) 202214571Sdim val = symbol->value; 203214571Sdim if (symbol->section->output_section) 204214571Sdim val += symbol->section->output_section->vma; 205214571Sdim 206214571Sdim val += reloc_entry->addend; 207214571Sdim 208214571Sdim /* Make it pc-relative. */ 209214571Sdim val -= input_section->output_section->vma + input_section->output_offset; 210214571Sdim 211214571Sdim val >>= 2; 212214571Sdim if (val + 256 >= 512) 213214571Sdim return bfd_reloc_overflow; 214214571Sdim 215214571Sdim insn = bfd_get_32 (abfd, (bfd_byte *) data + octets); 216214571Sdim 217214571Sdim /* Move two high bits of value to REL9I and REL9 position. 218214571Sdim The mask will take care of selecting the right field. */ 219214571Sdim val = (val & 0x7f) | ((val & 0x180) << 7) | ((val & 0x180) << 16); 220214571Sdim insn &= ~reloc_entry->howto->dst_mask; 221214571Sdim insn |= val & reloc_entry->howto->dst_mask; 222214571Sdim bfd_put_32 (abfd, insn, (bfd_byte *) data + octets); 223214571Sdim return bfd_reloc_ok; 224214571Sdim} 225214571Sdim 226214571Sdimstatic bfd_boolean 227214571Sdimspu_elf_new_section_hook (bfd *abfd, asection *sec) 228214571Sdim{ 229214571Sdim if (!sec->used_by_bfd) 230214571Sdim { 231214571Sdim struct _spu_elf_section_data *sdata; 232214571Sdim 233214571Sdim sdata = bfd_zalloc (abfd, sizeof (*sdata)); 234214571Sdim if (sdata == NULL) 235214571Sdim return FALSE; 236214571Sdim sec->used_by_bfd = sdata; 237214571Sdim } 238214571Sdim 239214571Sdim return _bfd_elf_new_section_hook (abfd, sec); 240214571Sdim} 241214571Sdim 242214571Sdim/* Specially mark defined symbols named _EAR_* with BSF_KEEP so that 243214571Sdim strip --strip-unneeded will not remove them. */ 244214571Sdim 245214571Sdimstatic void 246214571Sdimspu_elf_backend_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, asymbol *sym) 247214571Sdim{ 248214571Sdim if (sym->name != NULL 249214571Sdim && sym->section != bfd_abs_section_ptr 250214571Sdim && strncmp (sym->name, "_EAR_", 5) == 0) 251214571Sdim sym->flags |= BSF_KEEP; 252214571Sdim} 253214571Sdim 254214571Sdim/* SPU ELF linker hash table. */ 255214571Sdim 256214571Sdimstruct spu_link_hash_table 257214571Sdim{ 258214571Sdim struct elf_link_hash_table elf; 259214571Sdim 260214571Sdim /* The stub hash table. */ 261214571Sdim struct bfd_hash_table stub_hash_table; 262214571Sdim 263214571Sdim /* Shortcuts to overlay sections. */ 264214571Sdim asection *stub; 265214571Sdim asection *ovtab; 266214571Sdim 267214571Sdim struct elf_link_hash_entry *ovly_load; 268214571Sdim 269214571Sdim /* An array of two output sections per overlay region, chosen such that 270214571Sdim the first section vma is the overlay buffer vma (ie. the section has 271214571Sdim the lowest vma in the group that occupy the region), and the second 272214571Sdim section vma+size specifies the end of the region. We keep pointers 273214571Sdim to sections like this because section vmas may change when laying 274214571Sdim them out. */ 275214571Sdim asection **ovl_region; 276214571Sdim 277214571Sdim /* Number of overlay buffers. */ 278214571Sdim unsigned int num_buf; 279214571Sdim 280214571Sdim /* Total number of overlays. */ 281214571Sdim unsigned int num_overlays; 282214571Sdim 283214571Sdim /* Set if we should emit symbols for stubs. */ 284214571Sdim unsigned int emit_stub_syms:1; 285214571Sdim 286214571Sdim /* Set if we want stubs on calls out of overlay regions to 287214571Sdim non-overlay regions. */ 288214571Sdim unsigned int non_overlay_stubs : 1; 289214571Sdim 290214571Sdim /* Set on error. */ 291214571Sdim unsigned int stub_overflow : 1; 292214571Sdim 293214571Sdim /* Set if stack size analysis should be done. */ 294214571Sdim unsigned int stack_analysis : 1; 295214571Sdim 296214571Sdim /* Set if __stack_* syms will be emitted. */ 297214571Sdim unsigned int emit_stack_syms : 1; 298214571Sdim}; 299214571Sdim 300214571Sdim#define spu_hash_table(p) \ 301214571Sdim ((struct spu_link_hash_table *) ((p)->hash)) 302214571Sdim 303214571Sdimstruct spu_stub_hash_entry 304214571Sdim{ 305214571Sdim struct bfd_hash_entry root; 306214571Sdim 307214571Sdim /* Destination of this stub. */ 308214571Sdim asection *target_section; 309214571Sdim bfd_vma target_off; 310214571Sdim 311214571Sdim /* Offset of entry in stub section. */ 312214571Sdim bfd_vma off; 313214571Sdim 314214571Sdim /* Offset from this stub to stub that loads the overlay index. */ 315214571Sdim bfd_vma delta; 316214571Sdim}; 317214571Sdim 318214571Sdim/* Create an entry in a spu stub hash table. */ 319214571Sdim 320214571Sdimstatic struct bfd_hash_entry * 321214571Sdimstub_hash_newfunc (struct bfd_hash_entry *entry, 322214571Sdim struct bfd_hash_table *table, 323214571Sdim const char *string) 324214571Sdim{ 325214571Sdim /* Allocate the structure if it has not already been allocated by a 326214571Sdim subclass. */ 327214571Sdim if (entry == NULL) 328214571Sdim { 329214571Sdim entry = bfd_hash_allocate (table, sizeof (struct spu_stub_hash_entry)); 330214571Sdim if (entry == NULL) 331214571Sdim return entry; 332214571Sdim } 333214571Sdim 334214571Sdim /* Call the allocation method of the superclass. */ 335214571Sdim entry = bfd_hash_newfunc (entry, table, string); 336214571Sdim if (entry != NULL) 337214571Sdim { 338214571Sdim struct spu_stub_hash_entry *sh = (struct spu_stub_hash_entry *) entry; 339214571Sdim 340214571Sdim sh->target_section = NULL; 341214571Sdim sh->target_off = 0; 342214571Sdim sh->off = 0; 343214571Sdim sh->delta = 0; 344214571Sdim } 345214571Sdim 346214571Sdim return entry; 347214571Sdim} 348214571Sdim 349214571Sdim/* Create a spu ELF linker hash table. */ 350214571Sdim 351214571Sdimstatic struct bfd_link_hash_table * 352214571Sdimspu_elf_link_hash_table_create (bfd *abfd) 353214571Sdim{ 354214571Sdim struct spu_link_hash_table *htab; 355214571Sdim 356214571Sdim htab = bfd_malloc (sizeof (*htab)); 357214571Sdim if (htab == NULL) 358214571Sdim return NULL; 359214571Sdim 360214571Sdim if (!_bfd_elf_link_hash_table_init (&htab->elf, abfd, 361214571Sdim _bfd_elf_link_hash_newfunc, 362214571Sdim sizeof (struct elf_link_hash_entry))) 363214571Sdim { 364214571Sdim free (htab); 365214571Sdim return NULL; 366214571Sdim } 367214571Sdim 368214571Sdim /* Init the stub hash table too. */ 369214571Sdim if (!bfd_hash_table_init (&htab->stub_hash_table, stub_hash_newfunc, 370214571Sdim sizeof (struct spu_stub_hash_entry))) 371214571Sdim return NULL; 372214571Sdim 373214571Sdim memset (&htab->stub, 0, 374214571Sdim sizeof (*htab) - offsetof (struct spu_link_hash_table, stub)); 375214571Sdim 376214571Sdim return &htab->elf.root; 377214571Sdim} 378214571Sdim 379214571Sdim/* Free the derived linker hash table. */ 380214571Sdim 381214571Sdimstatic void 382214571Sdimspu_elf_link_hash_table_free (struct bfd_link_hash_table *hash) 383214571Sdim{ 384214571Sdim struct spu_link_hash_table *ret = (struct spu_link_hash_table *) hash; 385214571Sdim 386214571Sdim bfd_hash_table_free (&ret->stub_hash_table); 387214571Sdim _bfd_generic_link_hash_table_free (hash); 388214571Sdim} 389214571Sdim 390214571Sdim/* Find the symbol for the given R_SYMNDX in IBFD and set *HP and *SYMP 391214571Sdim to (hash, NULL) for global symbols, and (NULL, sym) for locals. Set 392214571Sdim *SYMSECP to the symbol's section. *LOCSYMSP caches local syms. */ 393214571Sdim 394214571Sdimstatic bfd_boolean 395214571Sdimget_sym_h (struct elf_link_hash_entry **hp, 396214571Sdim Elf_Internal_Sym **symp, 397214571Sdim asection **symsecp, 398214571Sdim Elf_Internal_Sym **locsymsp, 399214571Sdim unsigned long r_symndx, 400214571Sdim bfd *ibfd) 401214571Sdim{ 402214571Sdim Elf_Internal_Shdr *symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; 403214571Sdim 404214571Sdim if (r_symndx >= symtab_hdr->sh_info) 405214571Sdim { 406214571Sdim struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd); 407214571Sdim struct elf_link_hash_entry *h; 408214571Sdim 409214571Sdim h = sym_hashes[r_symndx - symtab_hdr->sh_info]; 410214571Sdim while (h->root.type == bfd_link_hash_indirect 411214571Sdim || h->root.type == bfd_link_hash_warning) 412214571Sdim h = (struct elf_link_hash_entry *) h->root.u.i.link; 413214571Sdim 414214571Sdim if (hp != NULL) 415214571Sdim *hp = h; 416214571Sdim 417214571Sdim if (symp != NULL) 418214571Sdim *symp = NULL; 419214571Sdim 420214571Sdim if (symsecp != NULL) 421214571Sdim { 422214571Sdim asection *symsec = NULL; 423214571Sdim if (h->root.type == bfd_link_hash_defined 424214571Sdim || h->root.type == bfd_link_hash_defweak) 425214571Sdim symsec = h->root.u.def.section; 426214571Sdim *symsecp = symsec; 427214571Sdim } 428214571Sdim } 429214571Sdim else 430214571Sdim { 431214571Sdim Elf_Internal_Sym *sym; 432214571Sdim Elf_Internal_Sym *locsyms = *locsymsp; 433214571Sdim 434214571Sdim if (locsyms == NULL) 435214571Sdim { 436214571Sdim locsyms = (Elf_Internal_Sym *) symtab_hdr->contents; 437214571Sdim if (locsyms == NULL) 438214571Sdim { 439214571Sdim size_t symcount = symtab_hdr->sh_info; 440214571Sdim 441214571Sdim /* If we are reading symbols into the contents, then 442214571Sdim read the global syms too. This is done to cache 443214571Sdim syms for later stack analysis. */ 444214571Sdim if ((unsigned char **) locsymsp == &symtab_hdr->contents) 445214571Sdim symcount = symtab_hdr->sh_size / symtab_hdr->sh_entsize; 446214571Sdim locsyms = bfd_elf_get_elf_syms (ibfd, symtab_hdr, symcount, 0, 447214571Sdim NULL, NULL, NULL); 448214571Sdim } 449214571Sdim if (locsyms == NULL) 450214571Sdim return FALSE; 451214571Sdim *locsymsp = locsyms; 452214571Sdim } 453214571Sdim sym = locsyms + r_symndx; 454214571Sdim 455214571Sdim if (hp != NULL) 456214571Sdim *hp = NULL; 457214571Sdim 458214571Sdim if (symp != NULL) 459214571Sdim *symp = sym; 460214571Sdim 461214571Sdim if (symsecp != NULL) 462214571Sdim { 463214571Sdim asection *symsec = NULL; 464214571Sdim if ((sym->st_shndx != SHN_UNDEF 465214571Sdim && sym->st_shndx < SHN_LORESERVE) 466214571Sdim || sym->st_shndx > SHN_HIRESERVE) 467214571Sdim symsec = bfd_section_from_elf_index (ibfd, sym->st_shndx); 468214571Sdim *symsecp = symsec; 469214571Sdim } 470214571Sdim } 471214571Sdim 472214571Sdim return TRUE; 473214571Sdim} 474214571Sdim 475214571Sdim/* Build a name for an entry in the stub hash table. We can't use a 476214571Sdim local symbol name because ld -r might generate duplicate local symbols. */ 477214571Sdim 478214571Sdimstatic char * 479214571Sdimspu_stub_name (const asection *sym_sec, 480214571Sdim const struct elf_link_hash_entry *h, 481214571Sdim const Elf_Internal_Rela *rel) 482214571Sdim{ 483214571Sdim char *stub_name; 484214571Sdim bfd_size_type len; 485214571Sdim 486214571Sdim if (h) 487214571Sdim { 488214571Sdim len = strlen (h->root.root.string) + 1 + 8 + 1; 489214571Sdim stub_name = bfd_malloc (len); 490214571Sdim if (stub_name == NULL) 491214571Sdim return stub_name; 492214571Sdim 493214571Sdim sprintf (stub_name, "%s+%x", 494214571Sdim h->root.root.string, 495214571Sdim (int) rel->r_addend & 0xffffffff); 496214571Sdim len -= 8; 497214571Sdim } 498214571Sdim else 499214571Sdim { 500214571Sdim len = 8 + 1 + 8 + 1 + 8 + 1; 501214571Sdim stub_name = bfd_malloc (len); 502214571Sdim if (stub_name == NULL) 503214571Sdim return stub_name; 504214571Sdim 505214571Sdim sprintf (stub_name, "%x:%x+%x", 506214571Sdim sym_sec->id & 0xffffffff, 507214571Sdim (int) ELF32_R_SYM (rel->r_info) & 0xffffffff, 508214571Sdim (int) rel->r_addend & 0xffffffff); 509214571Sdim len = strlen (stub_name); 510214571Sdim } 511214571Sdim 512214571Sdim if (stub_name[len - 2] == '+' 513214571Sdim && stub_name[len - 1] == '0' 514214571Sdim && stub_name[len] == 0) 515214571Sdim stub_name[len - 2] = 0; 516214571Sdim 517214571Sdim return stub_name; 518214571Sdim} 519214571Sdim 520214571Sdim/* Create the note section if not already present. This is done early so 521214571Sdim that the linker maps the sections to the right place in the output. */ 522214571Sdim 523214571Sdimbfd_boolean 524214571Sdimspu_elf_create_sections (bfd *output_bfd, 525214571Sdim struct bfd_link_info *info, 526214571Sdim int stack_analysis, 527214571Sdim int emit_stack_syms) 528214571Sdim{ 529214571Sdim bfd *ibfd; 530214571Sdim struct spu_link_hash_table *htab = spu_hash_table (info); 531214571Sdim 532214571Sdim /* Stash some options away where we can get at them later. */ 533214571Sdim htab->stack_analysis = stack_analysis; 534214571Sdim htab->emit_stack_syms = emit_stack_syms; 535214571Sdim 536214571Sdim for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) 537214571Sdim if (bfd_get_section_by_name (ibfd, SPU_PTNOTE_SPUNAME) != NULL) 538214571Sdim break; 539214571Sdim 540214571Sdim if (ibfd == NULL) 541214571Sdim { 542214571Sdim /* Make SPU_PTNOTE_SPUNAME section. */ 543214571Sdim asection *s; 544214571Sdim size_t name_len; 545214571Sdim size_t size; 546214571Sdim bfd_byte *data; 547214571Sdim flagword flags; 548214571Sdim 549214571Sdim ibfd = info->input_bfds; 550214571Sdim flags = SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS | SEC_IN_MEMORY; 551214571Sdim s = bfd_make_section_anyway_with_flags (ibfd, SPU_PTNOTE_SPUNAME, flags); 552214571Sdim if (s == NULL 553214571Sdim || !bfd_set_section_alignment (ibfd, s, 4)) 554214571Sdim return FALSE; 555214571Sdim 556214571Sdim name_len = strlen (bfd_get_filename (output_bfd)) + 1; 557214571Sdim size = 12 + ((sizeof (SPU_PLUGIN_NAME) + 3) & -4); 558214571Sdim size += (name_len + 3) & -4; 559214571Sdim 560214571Sdim if (!bfd_set_section_size (ibfd, s, size)) 561214571Sdim return FALSE; 562214571Sdim 563214571Sdim data = bfd_zalloc (ibfd, size); 564214571Sdim if (data == NULL) 565214571Sdim return FALSE; 566214571Sdim 567214571Sdim bfd_put_32 (ibfd, sizeof (SPU_PLUGIN_NAME), data + 0); 568214571Sdim bfd_put_32 (ibfd, name_len, data + 4); 569214571Sdim bfd_put_32 (ibfd, 1, data + 8); 570214571Sdim memcpy (data + 12, SPU_PLUGIN_NAME, sizeof (SPU_PLUGIN_NAME)); 571214571Sdim memcpy (data + 12 + ((sizeof (SPU_PLUGIN_NAME) + 3) & -4), 572214571Sdim bfd_get_filename (output_bfd), name_len); 573214571Sdim s->contents = data; 574214571Sdim } 575214571Sdim 576214571Sdim return TRUE; 577214571Sdim} 578214571Sdim 579214571Sdim/* qsort predicate to sort sections by vma. */ 580214571Sdim 581214571Sdimstatic int 582214571Sdimsort_sections (const void *a, const void *b) 583214571Sdim{ 584214571Sdim const asection *const *s1 = a; 585214571Sdim const asection *const *s2 = b; 586214571Sdim bfd_signed_vma delta = (*s1)->vma - (*s2)->vma; 587214571Sdim 588214571Sdim if (delta != 0) 589214571Sdim return delta < 0 ? -1 : 1; 590214571Sdim 591214571Sdim return (*s1)->index - (*s2)->index; 592214571Sdim} 593214571Sdim 594214571Sdim/* Identify overlays in the output bfd, and number them. */ 595214571Sdim 596214571Sdimbfd_boolean 597214571Sdimspu_elf_find_overlays (bfd *output_bfd, struct bfd_link_info *info) 598214571Sdim{ 599214571Sdim struct spu_link_hash_table *htab = spu_hash_table (info); 600214571Sdim asection **alloc_sec; 601214571Sdim unsigned int i, n, ovl_index, num_buf; 602214571Sdim asection *s; 603214571Sdim bfd_vma ovl_end; 604214571Sdim 605214571Sdim if (output_bfd->section_count < 2) 606214571Sdim return FALSE; 607214571Sdim 608214571Sdim alloc_sec = bfd_malloc (output_bfd->section_count * sizeof (*alloc_sec)); 609214571Sdim if (alloc_sec == NULL) 610214571Sdim return FALSE; 611214571Sdim 612214571Sdim /* Pick out all the alloced sections. */ 613214571Sdim for (n = 0, s = output_bfd->sections; s != NULL; s = s->next) 614214571Sdim if ((s->flags & SEC_ALLOC) != 0 615214571Sdim && (s->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) != SEC_THREAD_LOCAL 616214571Sdim && s->size != 0) 617214571Sdim alloc_sec[n++] = s; 618214571Sdim 619214571Sdim if (n == 0) 620214571Sdim { 621214571Sdim free (alloc_sec); 622214571Sdim return FALSE; 623214571Sdim } 624214571Sdim 625214571Sdim /* Sort them by vma. */ 626214571Sdim qsort (alloc_sec, n, sizeof (*alloc_sec), sort_sections); 627214571Sdim 628214571Sdim /* Look for overlapping vmas. Any with overlap must be overlays. 629214571Sdim Count them. Also count the number of overlay regions and for 630214571Sdim each region save a section from that region with the lowest vma 631214571Sdim and another section with the highest end vma. */ 632214571Sdim ovl_end = alloc_sec[0]->vma + alloc_sec[0]->size; 633214571Sdim for (ovl_index = 0, num_buf = 0, i = 1; i < n; i++) 634214571Sdim { 635214571Sdim s = alloc_sec[i]; 636214571Sdim if (s->vma < ovl_end) 637214571Sdim { 638214571Sdim asection *s0 = alloc_sec[i - 1]; 639214571Sdim 640214571Sdim if (spu_elf_section_data (s0)->ovl_index == 0) 641214571Sdim { 642214571Sdim spu_elf_section_data (s0)->ovl_index = ++ovl_index; 643214571Sdim alloc_sec[num_buf * 2] = s0; 644214571Sdim alloc_sec[num_buf * 2 + 1] = s0; 645214571Sdim num_buf++; 646214571Sdim } 647214571Sdim spu_elf_section_data (s)->ovl_index = ++ovl_index; 648214571Sdim if (ovl_end < s->vma + s->size) 649214571Sdim { 650214571Sdim ovl_end = s->vma + s->size; 651214571Sdim alloc_sec[num_buf * 2 - 1] = s; 652214571Sdim } 653214571Sdim } 654214571Sdim else 655214571Sdim ovl_end = s->vma + s->size; 656214571Sdim } 657214571Sdim 658214571Sdim htab->num_overlays = ovl_index; 659214571Sdim htab->num_buf = num_buf; 660214571Sdim if (ovl_index == 0) 661214571Sdim { 662214571Sdim free (alloc_sec); 663214571Sdim return FALSE; 664214571Sdim } 665214571Sdim 666214571Sdim alloc_sec = bfd_realloc (alloc_sec, num_buf * 2 * sizeof (*alloc_sec)); 667214571Sdim if (alloc_sec == NULL) 668214571Sdim return FALSE; 669214571Sdim 670214571Sdim htab->ovl_region = alloc_sec; 671214571Sdim return TRUE; 672214571Sdim} 673214571Sdim 674214571Sdim/* One of these per stub. */ 675214571Sdim#define SIZEOF_STUB1 8 676214571Sdim#define ILA_79 0x4200004f /* ila $79,function_address */ 677214571Sdim#define BR 0x32000000 /* br stub2 */ 678214571Sdim 679214571Sdim/* One of these per overlay. */ 680214571Sdim#define SIZEOF_STUB2 8 681214571Sdim#define ILA_78 0x4200004e /* ila $78,overlay_number */ 682214571Sdim /* br __ovly_load */ 683214571Sdim#define NOP 0x40200000 684214571Sdim 685214571Sdim/* Return true for all relative and absolute branch instructions. 686214571Sdim bra 00110000 0.. 687214571Sdim brasl 00110001 0.. 688214571Sdim br 00110010 0.. 689214571Sdim brsl 00110011 0.. 690214571Sdim brz 00100000 0.. 691214571Sdim brnz 00100001 0.. 692214571Sdim brhz 00100010 0.. 693214571Sdim brhnz 00100011 0.. */ 694214571Sdim 695214571Sdimstatic bfd_boolean 696214571Sdimis_branch (const unsigned char *insn) 697214571Sdim{ 698214571Sdim return (insn[0] & 0xec) == 0x20 && (insn[1] & 0x80) == 0; 699214571Sdim} 700214571Sdim 701214571Sdim/* Return true for branch hint instructions. 702214571Sdim hbra 0001000.. 703214571Sdim hbrr 0001001.. */ 704214571Sdim 705214571Sdimstatic bfd_boolean 706214571Sdimis_hint (const unsigned char *insn) 707214571Sdim{ 708214571Sdim return (insn[0] & 0xfc) == 0x10; 709214571Sdim} 710214571Sdim 711214571Sdim/* Return TRUE if this reloc symbol should possibly go via an overlay stub. */ 712214571Sdim 713214571Sdimstatic bfd_boolean 714214571Sdimneeds_ovl_stub (const char *sym_name, 715214571Sdim asection *sym_sec, 716214571Sdim asection *input_section, 717214571Sdim struct spu_link_hash_table *htab, 718214571Sdim bfd_boolean is_branch) 719214571Sdim{ 720214571Sdim if (htab->num_overlays == 0) 721214571Sdim return FALSE; 722214571Sdim 723214571Sdim if (sym_sec == NULL 724214571Sdim || sym_sec->output_section == NULL 725214571Sdim || spu_elf_section_data (sym_sec->output_section) == NULL) 726214571Sdim return FALSE; 727214571Sdim 728214571Sdim /* setjmp always goes via an overlay stub, because then the return 729214571Sdim and hence the longjmp goes via __ovly_return. That magically 730214571Sdim makes setjmp/longjmp between overlays work. */ 731214571Sdim if (strncmp (sym_name, "setjmp", 6) == 0 732214571Sdim && (sym_name[6] == '\0' || sym_name[6] == '@')) 733214571Sdim return TRUE; 734214571Sdim 735214571Sdim /* Usually, symbols in non-overlay sections don't need stubs. */ 736214571Sdim if (spu_elf_section_data (sym_sec->output_section)->ovl_index == 0 737214571Sdim && !htab->non_overlay_stubs) 738214571Sdim return FALSE; 739214571Sdim 740214571Sdim /* A reference from some other section to a symbol in an overlay 741214571Sdim section needs a stub. */ 742214571Sdim if (spu_elf_section_data (sym_sec->output_section)->ovl_index 743214571Sdim != spu_elf_section_data (input_section->output_section)->ovl_index) 744214571Sdim return TRUE; 745214571Sdim 746214571Sdim /* If this insn isn't a branch then we are possibly taking the 747214571Sdim address of a function and passing it out somehow. */ 748214571Sdim return !is_branch; 749214571Sdim} 750214571Sdim 751214571Sdimstruct stubarr { 752214571Sdim struct bfd_hash_table *stub_hash_table; 753214571Sdim struct spu_stub_hash_entry **sh; 754214571Sdim unsigned int count; 755214571Sdim int err; 756214571Sdim}; 757214571Sdim 758214571Sdim/* Called via elf_link_hash_traverse to allocate stubs for any _SPUEAR_ 759214571Sdim symbols. */ 760214571Sdim 761214571Sdimstatic bfd_boolean 762214571Sdimallocate_spuear_stubs (struct elf_link_hash_entry *h, void *inf) 763214571Sdim{ 764214571Sdim /* Symbols starting with _SPUEAR_ need a stub because they may be 765214571Sdim invoked by the PPU. */ 766214571Sdim if ((h->root.type == bfd_link_hash_defined 767214571Sdim || h->root.type == bfd_link_hash_defweak) 768214571Sdim && h->def_regular 769214571Sdim && strncmp (h->root.root.string, "_SPUEAR_", 8) == 0) 770214571Sdim { 771214571Sdim struct stubarr *stubs = inf; 772214571Sdim static Elf_Internal_Rela zero_rel; 773214571Sdim char *stub_name = spu_stub_name (h->root.u.def.section, h, &zero_rel); 774214571Sdim struct spu_stub_hash_entry *sh; 775214571Sdim 776214571Sdim if (stub_name == NULL) 777214571Sdim { 778214571Sdim stubs->err = 1; 779214571Sdim return FALSE; 780214571Sdim } 781214571Sdim 782214571Sdim sh = (struct spu_stub_hash_entry *) 783214571Sdim bfd_hash_lookup (stubs->stub_hash_table, stub_name, TRUE, FALSE); 784214571Sdim if (sh == NULL) 785214571Sdim { 786214571Sdim free (stub_name); 787214571Sdim return FALSE; 788214571Sdim } 789214571Sdim 790214571Sdim /* If this entry isn't new, we already have a stub. */ 791214571Sdim if (sh->target_section != NULL) 792214571Sdim { 793214571Sdim free (stub_name); 794214571Sdim return TRUE; 795214571Sdim } 796214571Sdim 797214571Sdim sh->target_section = h->root.u.def.section; 798214571Sdim sh->target_off = h->root.u.def.value; 799214571Sdim stubs->count += 1; 800214571Sdim } 801214571Sdim 802214571Sdim return TRUE; 803214571Sdim} 804214571Sdim 805214571Sdim/* Called via bfd_hash_traverse to set up pointers to all symbols 806214571Sdim in the stub hash table. */ 807214571Sdim 808214571Sdimstatic bfd_boolean 809214571Sdimpopulate_stubs (struct bfd_hash_entry *bh, void *inf) 810214571Sdim{ 811214571Sdim struct stubarr *stubs = inf; 812214571Sdim 813214571Sdim stubs->sh[--stubs->count] = (struct spu_stub_hash_entry *) bh; 814214571Sdim return TRUE; 815214571Sdim} 816214571Sdim 817214571Sdim/* qsort predicate to sort stubs by overlay number. */ 818214571Sdim 819214571Sdimstatic int 820214571Sdimsort_stubs (const void *a, const void *b) 821214571Sdim{ 822214571Sdim const struct spu_stub_hash_entry *const *sa = a; 823214571Sdim const struct spu_stub_hash_entry *const *sb = b; 824214571Sdim int i; 825214571Sdim bfd_signed_vma d; 826214571Sdim 827214571Sdim i = spu_elf_section_data ((*sa)->target_section->output_section)->ovl_index; 828214571Sdim i -= spu_elf_section_data ((*sb)->target_section->output_section)->ovl_index; 829214571Sdim if (i != 0) 830214571Sdim return i; 831214571Sdim 832214571Sdim d = ((*sa)->target_section->output_section->vma 833214571Sdim + (*sa)->target_section->output_offset 834214571Sdim + (*sa)->target_off 835214571Sdim - (*sb)->target_section->output_section->vma 836214571Sdim - (*sb)->target_section->output_offset 837214571Sdim - (*sb)->target_off); 838214571Sdim if (d != 0) 839214571Sdim return d < 0 ? -1 : 1; 840214571Sdim 841214571Sdim /* Two functions at the same address. Aliases perhaps. */ 842214571Sdim i = strcmp ((*sb)->root.string, (*sa)->root.string); 843214571Sdim BFD_ASSERT (i != 0); 844214571Sdim return i; 845214571Sdim} 846214571Sdim 847214571Sdim/* Allocate space for overlay call and return stubs. */ 848214571Sdim 849214571Sdimbfd_boolean 850214571Sdimspu_elf_size_stubs (bfd *output_bfd, 851214571Sdim struct bfd_link_info *info, 852214571Sdim int non_overlay_stubs, 853214571Sdim int stack_analysis, 854214571Sdim asection **stub, 855214571Sdim asection **ovtab, 856214571Sdim asection **toe) 857214571Sdim{ 858214571Sdim struct spu_link_hash_table *htab = spu_hash_table (info); 859214571Sdim bfd *ibfd; 860214571Sdim struct stubarr stubs; 861214571Sdim unsigned i, group; 862214571Sdim flagword flags; 863214571Sdim 864214571Sdim htab->non_overlay_stubs = non_overlay_stubs; 865214571Sdim stubs.stub_hash_table = &htab->stub_hash_table; 866214571Sdim stubs.count = 0; 867214571Sdim stubs.err = 0; 868214571Sdim for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) 869214571Sdim { 870214571Sdim extern const bfd_target bfd_elf32_spu_vec; 871214571Sdim Elf_Internal_Shdr *symtab_hdr; 872214571Sdim asection *section; 873214571Sdim Elf_Internal_Sym *local_syms = NULL; 874214571Sdim void *psyms; 875214571Sdim 876214571Sdim if (ibfd->xvec != &bfd_elf32_spu_vec) 877214571Sdim continue; 878214571Sdim 879214571Sdim /* We'll need the symbol table in a second. */ 880214571Sdim symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; 881214571Sdim if (symtab_hdr->sh_info == 0) 882214571Sdim continue; 883214571Sdim 884214571Sdim /* Arrange to read and keep global syms for later stack analysis. */ 885214571Sdim psyms = &local_syms; 886214571Sdim if (stack_analysis) 887214571Sdim psyms = &symtab_hdr->contents; 888214571Sdim 889214571Sdim /* Walk over each section attached to the input bfd. */ 890214571Sdim for (section = ibfd->sections; section != NULL; section = section->next) 891214571Sdim { 892214571Sdim Elf_Internal_Rela *internal_relocs, *irelaend, *irela; 893214571Sdim 894214571Sdim /* If there aren't any relocs, then there's nothing more to do. */ 895214571Sdim if ((section->flags & SEC_RELOC) == 0 896214571Sdim || (section->flags & SEC_ALLOC) == 0 897214571Sdim || (section->flags & SEC_LOAD) == 0 898214571Sdim || section->reloc_count == 0) 899214571Sdim continue; 900214571Sdim 901214571Sdim /* If this section is a link-once section that will be 902214571Sdim discarded, then don't create any stubs. */ 903214571Sdim if (section->output_section == NULL 904214571Sdim || section->output_section->owner != output_bfd) 905214571Sdim continue; 906214571Sdim 907214571Sdim /* Get the relocs. */ 908214571Sdim internal_relocs 909214571Sdim = _bfd_elf_link_read_relocs (ibfd, section, NULL, NULL, 910214571Sdim info->keep_memory); 911214571Sdim if (internal_relocs == NULL) 912214571Sdim goto error_ret_free_local; 913214571Sdim 914214571Sdim /* Now examine each relocation. */ 915214571Sdim irela = internal_relocs; 916214571Sdim irelaend = irela + section->reloc_count; 917214571Sdim for (; irela < irelaend; irela++) 918214571Sdim { 919214571Sdim enum elf_spu_reloc_type r_type; 920214571Sdim unsigned int r_indx; 921214571Sdim asection *sym_sec; 922214571Sdim Elf_Internal_Sym *sym; 923214571Sdim struct elf_link_hash_entry *h; 924214571Sdim const char *sym_name; 925214571Sdim char *stub_name; 926214571Sdim struct spu_stub_hash_entry *sh; 927214571Sdim unsigned int sym_type; 928214571Sdim enum _insn_type { non_branch, branch, call } insn_type; 929214571Sdim 930214571Sdim r_type = ELF32_R_TYPE (irela->r_info); 931214571Sdim r_indx = ELF32_R_SYM (irela->r_info); 932214571Sdim 933214571Sdim if (r_type >= R_SPU_max) 934214571Sdim { 935214571Sdim bfd_set_error (bfd_error_bad_value); 936214571Sdim goto error_ret_free_internal; 937214571Sdim } 938214571Sdim 939214571Sdim /* Determine the reloc target section. */ 940214571Sdim if (!get_sym_h (&h, &sym, &sym_sec, psyms, r_indx, ibfd)) 941214571Sdim goto error_ret_free_internal; 942214571Sdim 943214571Sdim if (sym_sec == NULL 944214571Sdim || sym_sec->output_section == NULL 945214571Sdim || sym_sec->output_section->owner != output_bfd) 946214571Sdim continue; 947214571Sdim 948214571Sdim /* Ensure no stubs for user supplied overlay manager syms. */ 949214571Sdim if (h != NULL 950214571Sdim && (strcmp (h->root.root.string, "__ovly_load") == 0 951214571Sdim || strcmp (h->root.root.string, "__ovly_return") == 0)) 952214571Sdim continue; 953214571Sdim 954214571Sdim insn_type = non_branch; 955214571Sdim if (r_type == R_SPU_REL16 956214571Sdim || r_type == R_SPU_ADDR16) 957214571Sdim { 958214571Sdim unsigned char insn[4]; 959214571Sdim 960214571Sdim if (!bfd_get_section_contents (ibfd, section, insn, 961214571Sdim irela->r_offset, 4)) 962214571Sdim goto error_ret_free_internal; 963214571Sdim 964214571Sdim if (is_branch (insn) || is_hint (insn)) 965214571Sdim { 966214571Sdim insn_type = branch; 967214571Sdim if ((insn[0] & 0xfd) == 0x31) 968214571Sdim insn_type = call; 969214571Sdim } 970214571Sdim } 971214571Sdim 972214571Sdim /* We are only interested in function symbols. */ 973214571Sdim if (h != NULL) 974214571Sdim { 975214571Sdim sym_type = h->type; 976214571Sdim sym_name = h->root.root.string; 977214571Sdim } 978214571Sdim else 979214571Sdim { 980214571Sdim sym_type = ELF_ST_TYPE (sym->st_info); 981214571Sdim sym_name = bfd_elf_sym_name (sym_sec->owner, 982214571Sdim symtab_hdr, 983214571Sdim sym, 984214571Sdim sym_sec); 985214571Sdim } 986214571Sdim if (sym_type != STT_FUNC) 987214571Sdim { 988214571Sdim /* It's common for people to write assembly and forget 989214571Sdim to give function symbols the right type. Handle 990214571Sdim calls to such symbols, but warn so that (hopefully) 991214571Sdim people will fix their code. We need the symbol 992214571Sdim type to be correct to distinguish function pointer 993214571Sdim initialisation from other pointer initialisation. */ 994214571Sdim if (insn_type == call) 995214571Sdim (*_bfd_error_handler) (_("warning: call to non-function" 996214571Sdim " symbol %s defined in %B"), 997214571Sdim sym_sec->owner, sym_name); 998214571Sdim else 999214571Sdim continue; 1000214571Sdim } 1001214571Sdim 1002214571Sdim if (!needs_ovl_stub (sym_name, sym_sec, section, htab, 1003214571Sdim insn_type != non_branch)) 1004214571Sdim continue; 1005214571Sdim 1006214571Sdim stub_name = spu_stub_name (sym_sec, h, irela); 1007214571Sdim if (stub_name == NULL) 1008214571Sdim goto error_ret_free_internal; 1009214571Sdim 1010214571Sdim sh = (struct spu_stub_hash_entry *) 1011214571Sdim bfd_hash_lookup (&htab->stub_hash_table, stub_name, 1012214571Sdim TRUE, FALSE); 1013214571Sdim if (sh == NULL) 1014214571Sdim { 1015214571Sdim free (stub_name); 1016214571Sdim error_ret_free_internal: 1017214571Sdim if (elf_section_data (section)->relocs != internal_relocs) 1018214571Sdim free (internal_relocs); 1019214571Sdim error_ret_free_local: 1020214571Sdim if (local_syms != NULL 1021214571Sdim && (symtab_hdr->contents 1022214571Sdim != (unsigned char *) local_syms)) 1023214571Sdim free (local_syms); 1024214571Sdim return FALSE; 1025214571Sdim } 1026214571Sdim 1027214571Sdim /* If this entry isn't new, we already have a stub. */ 1028214571Sdim if (sh->target_section != NULL) 1029214571Sdim { 1030214571Sdim free (stub_name); 1031214571Sdim continue; 1032214571Sdim } 1033214571Sdim 1034214571Sdim sh->target_section = sym_sec; 1035214571Sdim if (h != NULL) 1036214571Sdim sh->target_off = h->root.u.def.value; 1037214571Sdim else 1038214571Sdim sh->target_off = sym->st_value; 1039214571Sdim sh->target_off += irela->r_addend; 1040214571Sdim 1041214571Sdim stubs.count += 1; 1042214571Sdim } 1043214571Sdim 1044214571Sdim /* We're done with the internal relocs, free them. */ 1045214571Sdim if (elf_section_data (section)->relocs != internal_relocs) 1046214571Sdim free (internal_relocs); 1047214571Sdim } 1048214571Sdim 1049214571Sdim if (local_syms != NULL 1050214571Sdim && symtab_hdr->contents != (unsigned char *) local_syms) 1051214571Sdim { 1052214571Sdim if (!info->keep_memory) 1053214571Sdim free (local_syms); 1054214571Sdim else 1055214571Sdim symtab_hdr->contents = (unsigned char *) local_syms; 1056214571Sdim } 1057214571Sdim } 1058214571Sdim 1059214571Sdim elf_link_hash_traverse (&htab->elf, allocate_spuear_stubs, &stubs); 1060214571Sdim if (stubs.err) 1061214571Sdim return FALSE; 1062214571Sdim 1063214571Sdim *stub = NULL; 1064214571Sdim if (stubs.count == 0) 1065214571Sdim return TRUE; 1066214571Sdim 1067214571Sdim ibfd = info->input_bfds; 1068214571Sdim flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY 1069214571Sdim | SEC_HAS_CONTENTS | SEC_IN_MEMORY); 1070214571Sdim htab->stub = bfd_make_section_anyway_with_flags (ibfd, ".stub", flags); 1071214571Sdim *stub = htab->stub; 1072214571Sdim if (htab->stub == NULL 1073214571Sdim || !bfd_set_section_alignment (ibfd, htab->stub, 2)) 1074214571Sdim return FALSE; 1075214571Sdim 1076214571Sdim flags = (SEC_ALLOC | SEC_LOAD 1077214571Sdim | SEC_HAS_CONTENTS | SEC_IN_MEMORY); 1078214571Sdim htab->ovtab = bfd_make_section_anyway_with_flags (ibfd, ".ovtab", flags); 1079214571Sdim *ovtab = htab->ovtab; 1080214571Sdim if (htab->ovtab == NULL 1081214571Sdim || !bfd_set_section_alignment (ibfd, htab->stub, 4)) 1082214571Sdim return FALSE; 1083214571Sdim 1084214571Sdim *toe = bfd_make_section_anyway_with_flags (ibfd, ".toe", SEC_ALLOC); 1085214571Sdim if (*toe == NULL 1086214571Sdim || !bfd_set_section_alignment (ibfd, *toe, 4)) 1087214571Sdim return FALSE; 1088214571Sdim (*toe)->size = 16; 1089214571Sdim 1090214571Sdim /* Retrieve all the stubs and sort. */ 1091214571Sdim stubs.sh = bfd_malloc (stubs.count * sizeof (*stubs.sh)); 1092214571Sdim if (stubs.sh == NULL) 1093214571Sdim return FALSE; 1094214571Sdim i = stubs.count; 1095214571Sdim bfd_hash_traverse (&htab->stub_hash_table, populate_stubs, &stubs); 1096214571Sdim BFD_ASSERT (stubs.count == 0); 1097214571Sdim 1098214571Sdim stubs.count = i; 1099214571Sdim qsort (stubs.sh, stubs.count, sizeof (*stubs.sh), sort_stubs); 1100214571Sdim 1101214571Sdim /* Now that the stubs are sorted, place them in the stub section. 1102214571Sdim Stubs are grouped per overlay 1103214571Sdim . ila $79,func1 1104214571Sdim . br 1f 1105214571Sdim . ila $79,func2 1106214571Sdim . br 1f 1107214571Sdim . 1108214571Sdim . 1109214571Sdim . ila $79,funcn 1110214571Sdim . nop 1111214571Sdim . 1: 1112214571Sdim . ila $78,ovl_index 1113214571Sdim . br __ovly_load */ 1114214571Sdim 1115214571Sdim group = 0; 1116214571Sdim for (i = 0; i < stubs.count; i++) 1117214571Sdim { 1118214571Sdim if (spu_elf_section_data (stubs.sh[group]->target_section 1119214571Sdim ->output_section)->ovl_index 1120214571Sdim != spu_elf_section_data (stubs.sh[i]->target_section 1121214571Sdim ->output_section)->ovl_index) 1122214571Sdim { 1123214571Sdim htab->stub->size += SIZEOF_STUB2; 1124214571Sdim for (; group != i; group++) 1125214571Sdim stubs.sh[group]->delta 1126214571Sdim = stubs.sh[i - 1]->off - stubs.sh[group]->off; 1127214571Sdim } 1128214571Sdim if (group == i 1129214571Sdim || ((stubs.sh[i - 1]->target_section->output_section->vma 1130214571Sdim + stubs.sh[i - 1]->target_section->output_offset 1131214571Sdim + stubs.sh[i - 1]->target_off) 1132214571Sdim != (stubs.sh[i]->target_section->output_section->vma 1133214571Sdim + stubs.sh[i]->target_section->output_offset 1134214571Sdim + stubs.sh[i]->target_off))) 1135214571Sdim { 1136214571Sdim stubs.sh[i]->off = htab->stub->size; 1137214571Sdim htab->stub->size += SIZEOF_STUB1; 1138214571Sdim } 1139214571Sdim else 1140214571Sdim stubs.sh[i]->off = stubs.sh[i - 1]->off; 1141214571Sdim } 1142214571Sdim if (group != i) 1143214571Sdim htab->stub->size += SIZEOF_STUB2; 1144214571Sdim for (; group != i; group++) 1145214571Sdim stubs.sh[group]->delta = stubs.sh[i - 1]->off - stubs.sh[group]->off; 1146214571Sdim 1147214571Sdim /* htab->ovtab consists of two arrays. 1148214571Sdim . struct { 1149214571Sdim . u32 vma; 1150214571Sdim . u32 size; 1151214571Sdim . u32 file_off; 1152214571Sdim . u32 buf; 1153214571Sdim . } _ovly_table[]; 1154214571Sdim . 1155214571Sdim . struct { 1156214571Sdim . u32 mapped; 1157214571Sdim . } _ovly_buf_table[]; */ 1158214571Sdim 1159214571Sdim htab->ovtab->alignment_power = 4; 1160214571Sdim htab->ovtab->size = htab->num_overlays * 16 + htab->num_buf * 4; 1161214571Sdim 1162214571Sdim return TRUE; 1163214571Sdim} 1164214571Sdim 1165214571Sdim/* Functions to handle embedded spu_ovl.o object. */ 1166214571Sdim 1167214571Sdimstatic void * 1168214571Sdimovl_mgr_open (struct bfd *nbfd ATTRIBUTE_UNUSED, void *stream) 1169214571Sdim{ 1170214571Sdim return stream; 1171214571Sdim} 1172214571Sdim 1173214571Sdimstatic file_ptr 1174214571Sdimovl_mgr_pread (struct bfd *abfd ATTRIBUTE_UNUSED, 1175214571Sdim void *stream, 1176214571Sdim void *buf, 1177214571Sdim file_ptr nbytes, 1178214571Sdim file_ptr offset) 1179214571Sdim{ 1180214571Sdim struct _ovl_stream *os; 1181214571Sdim size_t count; 1182214571Sdim size_t max; 1183214571Sdim 1184214571Sdim os = (struct _ovl_stream *) stream; 1185214571Sdim max = (const char *) os->end - (const char *) os->start; 1186214571Sdim 1187214571Sdim if ((ufile_ptr) offset >= max) 1188214571Sdim return 0; 1189214571Sdim 1190214571Sdim count = nbytes; 1191214571Sdim if (count > max - offset) 1192214571Sdim count = max - offset; 1193214571Sdim 1194214571Sdim memcpy (buf, (const char *) os->start + offset, count); 1195214571Sdim return count; 1196214571Sdim} 1197214571Sdim 1198214571Sdimbfd_boolean 1199214571Sdimspu_elf_open_builtin_lib (bfd **ovl_bfd, const struct _ovl_stream *stream) 1200214571Sdim{ 1201214571Sdim *ovl_bfd = bfd_openr_iovec ("builtin ovl_mgr", 1202214571Sdim "elf32-spu", 1203214571Sdim ovl_mgr_open, 1204214571Sdim (void *) stream, 1205214571Sdim ovl_mgr_pread, 1206214571Sdim NULL, 1207214571Sdim NULL); 1208214571Sdim return *ovl_bfd != NULL; 1209214571Sdim} 1210214571Sdim 1211214571Sdim/* Fill in the ila and br for a stub. On the last stub for a group, 1212214571Sdim write the stub that sets the overlay number too. */ 1213214571Sdim 1214214571Sdimstatic bfd_boolean 1215214571Sdimwrite_one_stub (struct bfd_hash_entry *bh, void *inf) 1216214571Sdim{ 1217214571Sdim struct spu_stub_hash_entry *ent = (struct spu_stub_hash_entry *) bh; 1218214571Sdim struct spu_link_hash_table *htab = inf; 1219214571Sdim asection *sec = htab->stub; 1220214571Sdim asection *s = ent->target_section; 1221214571Sdim unsigned int ovl; 1222214571Sdim bfd_vma val; 1223214571Sdim 1224214571Sdim val = ent->target_off + s->output_offset + s->output_section->vma; 1225214571Sdim bfd_put_32 (sec->owner, ILA_79 + ((val << 7) & 0x01ffff80), 1226214571Sdim sec->contents + ent->off); 1227214571Sdim val = ent->delta + 4; 1228214571Sdim bfd_put_32 (sec->owner, BR + ((val << 5) & 0x007fff80), 1229214571Sdim sec->contents + ent->off + 4); 1230214571Sdim 1231214571Sdim /* If this is the last stub of this group, write stub2. */ 1232214571Sdim if (ent->delta == 0) 1233214571Sdim { 1234214571Sdim bfd_put_32 (sec->owner, NOP, 1235214571Sdim sec->contents + ent->off + 4); 1236214571Sdim 1237214571Sdim ovl = spu_elf_section_data (s->output_section)->ovl_index; 1238214571Sdim bfd_put_32 (sec->owner, ILA_78 + ((ovl << 7) & 0x01ffff80), 1239214571Sdim sec->contents + ent->off + 8); 1240214571Sdim 1241214571Sdim val = (htab->ovly_load->root.u.def.section->output_section->vma 1242214571Sdim + htab->ovly_load->root.u.def.section->output_offset 1243214571Sdim + htab->ovly_load->root.u.def.value 1244214571Sdim - (sec->output_section->vma 1245214571Sdim + sec->output_offset 1246214571Sdim + ent->off + 12)); 1247214571Sdim 1248214571Sdim if (val + 0x20000 >= 0x40000) 1249214571Sdim htab->stub_overflow = TRUE; 1250214571Sdim 1251214571Sdim bfd_put_32 (sec->owner, BR + ((val << 5) & 0x007fff80), 1252214571Sdim sec->contents + ent->off + 12); 1253214571Sdim } 1254214571Sdim 1255214571Sdim if (htab->emit_stub_syms) 1256214571Sdim { 1257214571Sdim struct elf_link_hash_entry *h; 1258214571Sdim size_t len1, len2; 1259214571Sdim char *name; 1260214571Sdim 1261214571Sdim len1 = sizeof ("00000000.ovl_call.") - 1; 1262214571Sdim len2 = strlen (ent->root.string); 1263214571Sdim name = bfd_malloc (len1 + len2 + 1); 1264214571Sdim if (name == NULL) 1265214571Sdim return FALSE; 1266214571Sdim memcpy (name, "00000000.ovl_call.", len1); 1267214571Sdim memcpy (name + len1, ent->root.string, len2 + 1); 1268214571Sdim h = elf_link_hash_lookup (&htab->elf, name, TRUE, TRUE, FALSE); 1269214571Sdim free (name); 1270214571Sdim if (h == NULL) 1271214571Sdim return FALSE; 1272214571Sdim if (h->root.type == bfd_link_hash_new) 1273214571Sdim { 1274214571Sdim h->root.type = bfd_link_hash_defined; 1275214571Sdim h->root.u.def.section = sec; 1276214571Sdim h->root.u.def.value = ent->off; 1277214571Sdim h->size = (ent->delta == 0 1278214571Sdim ? SIZEOF_STUB1 + SIZEOF_STUB2 : SIZEOF_STUB1); 1279214571Sdim h->type = STT_FUNC; 1280214571Sdim h->ref_regular = 1; 1281214571Sdim h->def_regular = 1; 1282214571Sdim h->ref_regular_nonweak = 1; 1283214571Sdim h->forced_local = 1; 1284214571Sdim h->non_elf = 0; 1285214571Sdim } 1286214571Sdim } 1287214571Sdim 1288214571Sdim return TRUE; 1289214571Sdim} 1290214571Sdim 1291214571Sdim/* Define an STT_OBJECT symbol. */ 1292214571Sdim 1293214571Sdimstatic struct elf_link_hash_entry * 1294214571Sdimdefine_ovtab_symbol (struct spu_link_hash_table *htab, const char *name) 1295214571Sdim{ 1296214571Sdim struct elf_link_hash_entry *h; 1297214571Sdim 1298214571Sdim h = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE); 1299214571Sdim if (h == NULL) 1300214571Sdim return NULL; 1301214571Sdim 1302214571Sdim if (h->root.type != bfd_link_hash_defined 1303214571Sdim || !h->def_regular) 1304214571Sdim { 1305214571Sdim h->root.type = bfd_link_hash_defined; 1306214571Sdim h->root.u.def.section = htab->ovtab; 1307214571Sdim h->type = STT_OBJECT; 1308214571Sdim h->ref_regular = 1; 1309214571Sdim h->def_regular = 1; 1310214571Sdim h->ref_regular_nonweak = 1; 1311214571Sdim h->non_elf = 0; 1312214571Sdim } 1313214571Sdim else 1314214571Sdim { 1315214571Sdim (*_bfd_error_handler) (_("%B is not allowed to define %s"), 1316214571Sdim h->root.u.def.section->owner, 1317214571Sdim h->root.root.string); 1318214571Sdim bfd_set_error (bfd_error_bad_value); 1319214571Sdim return NULL; 1320214571Sdim } 1321214571Sdim 1322214571Sdim return h; 1323214571Sdim} 1324214571Sdim 1325214571Sdim/* Fill in all stubs and the overlay tables. */ 1326214571Sdim 1327214571Sdimbfd_boolean 1328214571Sdimspu_elf_build_stubs (struct bfd_link_info *info, int emit_syms, asection *toe) 1329214571Sdim{ 1330214571Sdim struct spu_link_hash_table *htab = spu_hash_table (info); 1331214571Sdim struct elf_link_hash_entry *h; 1332214571Sdim bfd_byte *p; 1333214571Sdim asection *s; 1334214571Sdim bfd *obfd; 1335214571Sdim unsigned int i; 1336214571Sdim 1337214571Sdim htab->emit_stub_syms = emit_syms; 1338214571Sdim htab->stub->contents = bfd_zalloc (htab->stub->owner, htab->stub->size); 1339214571Sdim if (htab->stub->contents == NULL) 1340214571Sdim return FALSE; 1341214571Sdim 1342214571Sdim h = elf_link_hash_lookup (&htab->elf, "__ovly_load", FALSE, FALSE, FALSE); 1343214571Sdim htab->ovly_load = h; 1344214571Sdim BFD_ASSERT (h != NULL 1345214571Sdim && (h->root.type == bfd_link_hash_defined 1346214571Sdim || h->root.type == bfd_link_hash_defweak) 1347214571Sdim && h->def_regular); 1348214571Sdim 1349214571Sdim s = h->root.u.def.section->output_section; 1350214571Sdim if (spu_elf_section_data (s)->ovl_index) 1351214571Sdim { 1352214571Sdim (*_bfd_error_handler) (_("%s in overlay section"), 1353214571Sdim h->root.u.def.section->owner); 1354214571Sdim bfd_set_error (bfd_error_bad_value); 1355214571Sdim return FALSE; 1356214571Sdim } 1357214571Sdim 1358214571Sdim /* Write out all the stubs. */ 1359214571Sdim bfd_hash_traverse (&htab->stub_hash_table, write_one_stub, htab); 1360214571Sdim 1361214571Sdim if (htab->stub_overflow) 1362214571Sdim { 1363214571Sdim (*_bfd_error_handler) (_("overlay stub relocation overflow")); 1364214571Sdim bfd_set_error (bfd_error_bad_value); 1365214571Sdim return FALSE; 1366214571Sdim } 1367214571Sdim 1368214571Sdim htab->ovtab->contents = bfd_zalloc (htab->ovtab->owner, htab->ovtab->size); 1369214571Sdim if (htab->ovtab->contents == NULL) 1370214571Sdim return FALSE; 1371214571Sdim 1372214571Sdim /* Write out _ovly_table. */ 1373214571Sdim p = htab->ovtab->contents; 1374214571Sdim obfd = htab->ovtab->output_section->owner; 1375214571Sdim for (s = obfd->sections; s != NULL; s = s->next) 1376214571Sdim { 1377214571Sdim unsigned int ovl_index = spu_elf_section_data (s)->ovl_index; 1378214571Sdim 1379214571Sdim if (ovl_index != 0) 1380214571Sdim { 1381214571Sdim unsigned int lo, hi, mid; 1382214571Sdim unsigned long off = (ovl_index - 1) * 16; 1383214571Sdim bfd_put_32 (htab->ovtab->owner, s->vma, p + off); 1384214571Sdim bfd_put_32 (htab->ovtab->owner, (s->size + 15) & -16, p + off + 4); 1385214571Sdim /* file_off written later in spu_elf_modify_program_headers. */ 1386214571Sdim 1387214571Sdim lo = 0; 1388214571Sdim hi = htab->num_buf; 1389214571Sdim while (lo < hi) 1390214571Sdim { 1391214571Sdim mid = (lo + hi) >> 1; 1392214571Sdim if (htab->ovl_region[2 * mid + 1]->vma 1393214571Sdim + htab->ovl_region[2 * mid + 1]->size <= s->vma) 1394214571Sdim lo = mid + 1; 1395214571Sdim else if (htab->ovl_region[2 * mid]->vma > s->vma) 1396214571Sdim hi = mid; 1397214571Sdim else 1398214571Sdim { 1399214571Sdim bfd_put_32 (htab->ovtab->owner, mid + 1, p + off + 12); 1400214571Sdim break; 1401214571Sdim } 1402214571Sdim } 1403214571Sdim BFD_ASSERT (lo < hi); 1404214571Sdim } 1405214571Sdim } 1406214571Sdim 1407214571Sdim /* Write out _ovly_buf_table. */ 1408214571Sdim p = htab->ovtab->contents + htab->num_overlays * 16; 1409214571Sdim for (i = 0; i < htab->num_buf; i++) 1410214571Sdim { 1411214571Sdim bfd_put_32 (htab->ovtab->owner, 0, p); 1412214571Sdim p += 4; 1413214571Sdim } 1414214571Sdim 1415214571Sdim h = define_ovtab_symbol (htab, "_ovly_table"); 1416214571Sdim if (h == NULL) 1417214571Sdim return FALSE; 1418214571Sdim h->root.u.def.value = 0; 1419214571Sdim h->size = htab->num_overlays * 16; 1420214571Sdim 1421214571Sdim h = define_ovtab_symbol (htab, "_ovly_table_end"); 1422214571Sdim if (h == NULL) 1423214571Sdim return FALSE; 1424214571Sdim h->root.u.def.value = htab->num_overlays * 16; 1425214571Sdim h->size = 0; 1426214571Sdim 1427214571Sdim h = define_ovtab_symbol (htab, "_ovly_buf_table"); 1428214571Sdim if (h == NULL) 1429214571Sdim return FALSE; 1430214571Sdim h->root.u.def.value = htab->num_overlays * 16; 1431214571Sdim h->size = htab->num_buf * 4; 1432214571Sdim 1433214571Sdim h = define_ovtab_symbol (htab, "_ovly_buf_table_end"); 1434214571Sdim if (h == NULL) 1435214571Sdim return FALSE; 1436214571Sdim h->root.u.def.value = htab->num_overlays * 16 + htab->num_buf * 4; 1437214571Sdim h->size = 0; 1438214571Sdim 1439214571Sdim h = define_ovtab_symbol (htab, "_EAR_"); 1440214571Sdim if (h == NULL) 1441214571Sdim return FALSE; 1442214571Sdim h->root.u.def.section = toe; 1443214571Sdim h->root.u.def.value = 0; 1444214571Sdim h->size = 16; 1445214571Sdim 1446214571Sdim return TRUE; 1447214571Sdim} 1448214571Sdim 1449214571Sdim/* OFFSET in SEC (presumably) is the beginning of a function prologue. 1450214571Sdim Search for stack adjusting insns, and return the sp delta. */ 1451214571Sdim 1452214571Sdimstatic int 1453214571Sdimfind_function_stack_adjust (asection *sec, bfd_vma offset) 1454214571Sdim{ 1455214571Sdim int unrecog; 1456214571Sdim int reg[128]; 1457214571Sdim 1458214571Sdim memset (reg, 0, sizeof (reg)); 1459214571Sdim for (unrecog = 0; offset + 4 <= sec->size && unrecog < 32; offset += 4) 1460214571Sdim { 1461214571Sdim unsigned char buf[4]; 1462214571Sdim int rt, ra; 1463214571Sdim int imm; 1464214571Sdim 1465214571Sdim /* Assume no relocs on stack adjusing insns. */ 1466214571Sdim if (!bfd_get_section_contents (sec->owner, sec, buf, offset, 4)) 1467214571Sdim break; 1468214571Sdim 1469214571Sdim if (buf[0] == 0x24 /* stqd */) 1470214571Sdim continue; 1471214571Sdim 1472214571Sdim rt = buf[3] & 0x7f; 1473214571Sdim ra = ((buf[2] & 0x3f) << 1) | (buf[3] >> 7); 1474214571Sdim /* Partly decoded immediate field. */ 1475214571Sdim imm = (buf[1] << 9) | (buf[2] << 1) | (buf[3] >> 7); 1476214571Sdim 1477214571Sdim if (buf[0] == 0x1c /* ai */) 1478214571Sdim { 1479214571Sdim imm >>= 7; 1480214571Sdim imm = (imm ^ 0x200) - 0x200; 1481214571Sdim reg[rt] = reg[ra] + imm; 1482214571Sdim 1483214571Sdim if (rt == 1 /* sp */) 1484214571Sdim { 1485214571Sdim if (imm > 0) 1486214571Sdim break; 1487214571Sdim return reg[rt]; 1488214571Sdim } 1489214571Sdim } 1490214571Sdim else if (buf[0] == 0x18 && (buf[1] & 0xe0) == 0 /* a */) 1491214571Sdim { 1492214571Sdim int rb = ((buf[1] & 0x1f) << 2) | ((buf[2] & 0xc0) >> 6); 1493214571Sdim 1494214571Sdim reg[rt] = reg[ra] + reg[rb]; 1495214571Sdim if (rt == 1) 1496214571Sdim return reg[rt]; 1497214571Sdim } 1498214571Sdim else if ((buf[0] & 0xfc) == 0x40 /* il, ilh, ilhu, ila */) 1499214571Sdim { 1500214571Sdim if (buf[0] >= 0x42 /* ila */) 1501214571Sdim imm |= (buf[0] & 1) << 17; 1502214571Sdim else 1503214571Sdim { 1504214571Sdim imm &= 0xffff; 1505214571Sdim 1506214571Sdim if (buf[0] == 0x40 /* il */) 1507214571Sdim { 1508214571Sdim if ((buf[1] & 0x80) == 0) 1509214571Sdim goto unknown_insn; 1510214571Sdim imm = (imm ^ 0x8000) - 0x8000; 1511214571Sdim } 1512214571Sdim else if ((buf[1] & 0x80) == 0 /* ilhu */) 1513214571Sdim imm <<= 16; 1514214571Sdim } 1515214571Sdim reg[rt] = imm; 1516214571Sdim continue; 1517214571Sdim } 1518214571Sdim else if (buf[0] == 0x60 && (buf[1] & 0x80) != 0 /* iohl */) 1519214571Sdim { 1520214571Sdim reg[rt] |= imm & 0xffff; 1521214571Sdim continue; 1522214571Sdim } 1523214571Sdim else if (buf[0] == 0x04 /* ori */) 1524214571Sdim { 1525214571Sdim imm >>= 7; 1526214571Sdim imm = (imm ^ 0x200) - 0x200; 1527214571Sdim reg[rt] = reg[ra] | imm; 1528214571Sdim continue; 1529214571Sdim } 1530214571Sdim else if ((buf[0] == 0x33 && imm == 1 /* brsl .+4 */) 1531214571Sdim || (buf[0] == 0x08 && (buf[1] & 0xe0) == 0 /* sf */)) 1532214571Sdim { 1533214571Sdim /* Used in pic reg load. Say rt is trashed. */ 1534214571Sdim reg[rt] = 0; 1535214571Sdim continue; 1536214571Sdim } 1537214571Sdim else if (is_branch (buf)) 1538214571Sdim /* If we hit a branch then we must be out of the prologue. */ 1539214571Sdim break; 1540214571Sdim unknown_insn: 1541214571Sdim ++unrecog; 1542214571Sdim } 1543214571Sdim 1544214571Sdim return 0; 1545214571Sdim} 1546214571Sdim 1547214571Sdim/* qsort predicate to sort symbols by section and value. */ 1548214571Sdim 1549214571Sdimstatic Elf_Internal_Sym *sort_syms_syms; 1550214571Sdimstatic asection **sort_syms_psecs; 1551214571Sdim 1552214571Sdimstatic int 1553214571Sdimsort_syms (const void *a, const void *b) 1554214571Sdim{ 1555214571Sdim Elf_Internal_Sym *const *s1 = a; 1556214571Sdim Elf_Internal_Sym *const *s2 = b; 1557214571Sdim asection *sec1,*sec2; 1558214571Sdim bfd_signed_vma delta; 1559214571Sdim 1560214571Sdim sec1 = sort_syms_psecs[*s1 - sort_syms_syms]; 1561214571Sdim sec2 = sort_syms_psecs[*s2 - sort_syms_syms]; 1562214571Sdim 1563214571Sdim if (sec1 != sec2) 1564214571Sdim return sec1->index - sec2->index; 1565214571Sdim 1566214571Sdim delta = (*s1)->st_value - (*s2)->st_value; 1567214571Sdim if (delta != 0) 1568214571Sdim return delta < 0 ? -1 : 1; 1569214571Sdim 1570214571Sdim delta = (*s2)->st_size - (*s1)->st_size; 1571214571Sdim if (delta != 0) 1572214571Sdim return delta < 0 ? -1 : 1; 1573214571Sdim 1574214571Sdim return *s1 < *s2 ? -1 : 1; 1575214571Sdim} 1576214571Sdim 1577214571Sdimstruct call_info 1578214571Sdim{ 1579214571Sdim struct function_info *fun; 1580214571Sdim struct call_info *next; 1581214571Sdim int is_tail; 1582214571Sdim}; 1583214571Sdim 1584214571Sdimstruct function_info 1585214571Sdim{ 1586214571Sdim /* List of functions called. Also branches to hot/cold part of 1587214571Sdim function. */ 1588214571Sdim struct call_info *call_list; 1589214571Sdim /* For hot/cold part of function, point to owner. */ 1590214571Sdim struct function_info *start; 1591214571Sdim /* Symbol at start of function. */ 1592214571Sdim union { 1593214571Sdim Elf_Internal_Sym *sym; 1594214571Sdim struct elf_link_hash_entry *h; 1595214571Sdim } u; 1596214571Sdim /* Function section. */ 1597214571Sdim asection *sec; 1598214571Sdim /* Address range of (this part of) function. */ 1599214571Sdim bfd_vma lo, hi; 1600214571Sdim /* Stack usage. */ 1601214571Sdim int stack; 1602214571Sdim /* Set if global symbol. */ 1603214571Sdim unsigned int global : 1; 1604214571Sdim /* Set if known to be start of function (as distinct from a hunk 1605214571Sdim in hot/cold section. */ 1606214571Sdim unsigned int is_func : 1; 1607214571Sdim /* Flags used during call tree traversal. */ 1608214571Sdim unsigned int visit1 : 1; 1609214571Sdim unsigned int non_root : 1; 1610214571Sdim unsigned int visit2 : 1; 1611214571Sdim unsigned int marking : 1; 1612214571Sdim unsigned int visit3 : 1; 1613214571Sdim}; 1614214571Sdim 1615214571Sdimstruct spu_elf_stack_info 1616214571Sdim{ 1617214571Sdim int num_fun; 1618214571Sdim int max_fun; 1619214571Sdim /* Variable size array describing functions, one per contiguous 1620214571Sdim address range belonging to a function. */ 1621214571Sdim struct function_info fun[1]; 1622214571Sdim}; 1623214571Sdim 1624214571Sdim/* Allocate a struct spu_elf_stack_info with MAX_FUN struct function_info 1625214571Sdim entries for section SEC. */ 1626214571Sdim 1627214571Sdimstatic struct spu_elf_stack_info * 1628214571Sdimalloc_stack_info (asection *sec, int max_fun) 1629214571Sdim{ 1630214571Sdim struct _spu_elf_section_data *sec_data = spu_elf_section_data (sec); 1631214571Sdim bfd_size_type amt; 1632214571Sdim 1633214571Sdim amt = sizeof (struct spu_elf_stack_info); 1634214571Sdim amt += (max_fun - 1) * sizeof (struct function_info); 1635214571Sdim sec_data->stack_info = bfd_zmalloc (amt); 1636214571Sdim if (sec_data->stack_info != NULL) 1637214571Sdim sec_data->stack_info->max_fun = max_fun; 1638214571Sdim return sec_data->stack_info; 1639214571Sdim} 1640214571Sdim 1641214571Sdim/* Add a new struct function_info describing a (part of a) function 1642214571Sdim starting at SYM_H. Keep the array sorted by address. */ 1643214571Sdim 1644214571Sdimstatic struct function_info * 1645214571Sdimmaybe_insert_function (asection *sec, 1646214571Sdim void *sym_h, 1647214571Sdim bfd_boolean global, 1648214571Sdim bfd_boolean is_func) 1649214571Sdim{ 1650214571Sdim struct _spu_elf_section_data *sec_data = spu_elf_section_data (sec); 1651214571Sdim struct spu_elf_stack_info *sinfo = sec_data->stack_info; 1652214571Sdim int i; 1653214571Sdim bfd_vma off, size; 1654214571Sdim 1655214571Sdim if (sinfo == NULL) 1656214571Sdim { 1657214571Sdim sinfo = alloc_stack_info (sec, 20); 1658214571Sdim if (sinfo == NULL) 1659214571Sdim return NULL; 1660214571Sdim } 1661214571Sdim 1662214571Sdim if (!global) 1663214571Sdim { 1664214571Sdim Elf_Internal_Sym *sym = sym_h; 1665214571Sdim off = sym->st_value; 1666214571Sdim size = sym->st_size; 1667214571Sdim } 1668214571Sdim else 1669214571Sdim { 1670214571Sdim struct elf_link_hash_entry *h = sym_h; 1671214571Sdim off = h->root.u.def.value; 1672214571Sdim size = h->size; 1673214571Sdim } 1674214571Sdim 1675214571Sdim for (i = sinfo->num_fun; --i >= 0; ) 1676214571Sdim if (sinfo->fun[i].lo <= off) 1677214571Sdim break; 1678214571Sdim 1679214571Sdim if (i >= 0) 1680214571Sdim { 1681214571Sdim /* Don't add another entry for an alias, but do update some 1682214571Sdim info. */ 1683214571Sdim if (sinfo->fun[i].lo == off) 1684214571Sdim { 1685214571Sdim /* Prefer globals over local syms. */ 1686214571Sdim if (global && !sinfo->fun[i].global) 1687214571Sdim { 1688214571Sdim sinfo->fun[i].global = TRUE; 1689214571Sdim sinfo->fun[i].u.h = sym_h; 1690214571Sdim } 1691214571Sdim if (is_func) 1692214571Sdim sinfo->fun[i].is_func = TRUE; 1693214571Sdim return &sinfo->fun[i]; 1694214571Sdim } 1695214571Sdim /* Ignore a zero-size symbol inside an existing function. */ 1696214571Sdim else if (sinfo->fun[i].hi > off && size == 0) 1697214571Sdim return &sinfo->fun[i]; 1698214571Sdim } 1699214571Sdim 1700214571Sdim if (++i < sinfo->num_fun) 1701214571Sdim memmove (&sinfo->fun[i + 1], &sinfo->fun[i], 1702214571Sdim (sinfo->num_fun - i) * sizeof (sinfo->fun[i])); 1703214571Sdim else if (i >= sinfo->max_fun) 1704214571Sdim { 1705214571Sdim bfd_size_type amt = sizeof (struct spu_elf_stack_info); 1706214571Sdim bfd_size_type old = amt; 1707214571Sdim 1708214571Sdim old += (sinfo->max_fun - 1) * sizeof (struct function_info); 1709214571Sdim sinfo->max_fun += 20 + (sinfo->max_fun >> 1); 1710214571Sdim amt += (sinfo->max_fun - 1) * sizeof (struct function_info); 1711214571Sdim sinfo = bfd_realloc (sinfo, amt); 1712214571Sdim if (sinfo == NULL) 1713214571Sdim return NULL; 1714214571Sdim memset ((char *) sinfo + old, 0, amt - old); 1715214571Sdim sec_data->stack_info = sinfo; 1716214571Sdim } 1717214571Sdim sinfo->fun[i].is_func = is_func; 1718214571Sdim sinfo->fun[i].global = global; 1719214571Sdim sinfo->fun[i].sec = sec; 1720214571Sdim if (global) 1721214571Sdim sinfo->fun[i].u.h = sym_h; 1722214571Sdim else 1723214571Sdim sinfo->fun[i].u.sym = sym_h; 1724214571Sdim sinfo->fun[i].lo = off; 1725214571Sdim sinfo->fun[i].hi = off + size; 1726214571Sdim sinfo->fun[i].stack = -find_function_stack_adjust (sec, off); 1727214571Sdim sinfo->num_fun += 1; 1728214571Sdim return &sinfo->fun[i]; 1729214571Sdim} 1730214571Sdim 1731214571Sdim/* Return the name of FUN. */ 1732214571Sdim 1733214571Sdimstatic const char * 1734214571Sdimfunc_name (struct function_info *fun) 1735214571Sdim{ 1736214571Sdim asection *sec; 1737214571Sdim bfd *ibfd; 1738214571Sdim Elf_Internal_Shdr *symtab_hdr; 1739214571Sdim 1740214571Sdim while (fun->start != NULL) 1741214571Sdim fun = fun->start; 1742214571Sdim 1743214571Sdim if (fun->global) 1744214571Sdim return fun->u.h->root.root.string; 1745214571Sdim 1746214571Sdim sec = fun->sec; 1747214571Sdim if (fun->u.sym->st_name == 0) 1748214571Sdim { 1749214571Sdim size_t len = strlen (sec->name); 1750214571Sdim char *name = bfd_malloc (len + 10); 1751214571Sdim if (name == NULL) 1752214571Sdim return "(null)"; 1753214571Sdim sprintf (name, "%s+%lx", sec->name, 1754214571Sdim (unsigned long) fun->u.sym->st_value & 0xffffffff); 1755214571Sdim return name; 1756214571Sdim } 1757214571Sdim ibfd = sec->owner; 1758214571Sdim symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; 1759214571Sdim return bfd_elf_sym_name (ibfd, symtab_hdr, fun->u.sym, sec); 1760214571Sdim} 1761214571Sdim 1762214571Sdim/* Read the instruction at OFF in SEC. Return true iff the instruction 1763214571Sdim is a nop, lnop, or stop 0 (all zero insn). */ 1764214571Sdim 1765214571Sdimstatic bfd_boolean 1766214571Sdimis_nop (asection *sec, bfd_vma off) 1767214571Sdim{ 1768214571Sdim unsigned char insn[4]; 1769214571Sdim 1770214571Sdim if (off + 4 > sec->size 1771214571Sdim || !bfd_get_section_contents (sec->owner, sec, insn, off, 4)) 1772214571Sdim return FALSE; 1773214571Sdim if ((insn[0] & 0xbf) == 0 && (insn[1] & 0xe0) == 0x20) 1774214571Sdim return TRUE; 1775214571Sdim if (insn[0] == 0 && insn[1] == 0 && insn[2] == 0 && insn[3] == 0) 1776214571Sdim return TRUE; 1777214571Sdim return FALSE; 1778214571Sdim} 1779214571Sdim 1780214571Sdim/* Extend the range of FUN to cover nop padding up to LIMIT. 1781214571Sdim Return TRUE iff some instruction other than a NOP was found. */ 1782214571Sdim 1783214571Sdimstatic bfd_boolean 1784214571Sdiminsns_at_end (struct function_info *fun, bfd_vma limit) 1785214571Sdim{ 1786214571Sdim bfd_vma off = (fun->hi + 3) & -4; 1787214571Sdim 1788214571Sdim while (off < limit && is_nop (fun->sec, off)) 1789214571Sdim off += 4; 1790214571Sdim if (off < limit) 1791214571Sdim { 1792214571Sdim fun->hi = off; 1793214571Sdim return TRUE; 1794214571Sdim } 1795214571Sdim fun->hi = limit; 1796214571Sdim return FALSE; 1797214571Sdim} 1798214571Sdim 1799214571Sdim/* Check and fix overlapping function ranges. Return TRUE iff there 1800214571Sdim are gaps in the current info we have about functions in SEC. */ 1801214571Sdim 1802214571Sdimstatic bfd_boolean 1803214571Sdimcheck_function_ranges (asection *sec, struct bfd_link_info *info) 1804214571Sdim{ 1805214571Sdim struct _spu_elf_section_data *sec_data = spu_elf_section_data (sec); 1806214571Sdim struct spu_elf_stack_info *sinfo = sec_data->stack_info; 1807214571Sdim int i; 1808214571Sdim bfd_boolean gaps = FALSE; 1809214571Sdim 1810214571Sdim if (sinfo == NULL) 1811214571Sdim return FALSE; 1812214571Sdim 1813214571Sdim for (i = 1; i < sinfo->num_fun; i++) 1814214571Sdim if (sinfo->fun[i - 1].hi > sinfo->fun[i].lo) 1815214571Sdim { 1816214571Sdim /* Fix overlapping symbols. */ 1817214571Sdim const char *f1 = func_name (&sinfo->fun[i - 1]); 1818214571Sdim const char *f2 = func_name (&sinfo->fun[i]); 1819214571Sdim 1820214571Sdim info->callbacks->einfo (_("warning: %s overlaps %s\n"), f1, f2); 1821214571Sdim sinfo->fun[i - 1].hi = sinfo->fun[i].lo; 1822214571Sdim } 1823214571Sdim else if (insns_at_end (&sinfo->fun[i - 1], sinfo->fun[i].lo)) 1824214571Sdim gaps = TRUE; 1825214571Sdim 1826214571Sdim if (sinfo->num_fun == 0) 1827214571Sdim gaps = TRUE; 1828214571Sdim else 1829214571Sdim { 1830214571Sdim if (sinfo->fun[0].lo != 0) 1831214571Sdim gaps = TRUE; 1832214571Sdim if (sinfo->fun[sinfo->num_fun - 1].hi > sec->size) 1833214571Sdim { 1834214571Sdim const char *f1 = func_name (&sinfo->fun[sinfo->num_fun - 1]); 1835214571Sdim 1836214571Sdim info->callbacks->einfo (_("warning: %s exceeds section size\n"), f1); 1837214571Sdim sinfo->fun[sinfo->num_fun - 1].hi = sec->size; 1838214571Sdim } 1839214571Sdim else if (insns_at_end (&sinfo->fun[sinfo->num_fun - 1], sec->size)) 1840214571Sdim gaps = TRUE; 1841214571Sdim } 1842214571Sdim return gaps; 1843214571Sdim} 1844214571Sdim 1845214571Sdim/* Search current function info for a function that contains address 1846214571Sdim OFFSET in section SEC. */ 1847214571Sdim 1848214571Sdimstatic struct function_info * 1849214571Sdimfind_function (asection *sec, bfd_vma offset, struct bfd_link_info *info) 1850214571Sdim{ 1851214571Sdim struct _spu_elf_section_data *sec_data = spu_elf_section_data (sec); 1852214571Sdim struct spu_elf_stack_info *sinfo = sec_data->stack_info; 1853214571Sdim int lo, hi, mid; 1854214571Sdim 1855214571Sdim lo = 0; 1856214571Sdim hi = sinfo->num_fun; 1857214571Sdim while (lo < hi) 1858214571Sdim { 1859214571Sdim mid = (lo + hi) / 2; 1860214571Sdim if (offset < sinfo->fun[mid].lo) 1861214571Sdim hi = mid; 1862214571Sdim else if (offset >= sinfo->fun[mid].hi) 1863214571Sdim lo = mid + 1; 1864214571Sdim else 1865214571Sdim return &sinfo->fun[mid]; 1866214571Sdim } 1867214571Sdim info->callbacks->einfo (_("%A:0x%v not found in function table\n"), 1868214571Sdim sec, offset); 1869214571Sdim return NULL; 1870214571Sdim} 1871214571Sdim 1872214571Sdim/* Add CALLEE to CALLER call list if not already present. */ 1873214571Sdim 1874214571Sdimstatic bfd_boolean 1875214571Sdiminsert_callee (struct function_info *caller, struct call_info *callee) 1876214571Sdim{ 1877214571Sdim struct call_info *p; 1878214571Sdim for (p = caller->call_list; p != NULL; p = p->next) 1879214571Sdim if (p->fun == callee->fun) 1880214571Sdim { 1881214571Sdim /* Tail calls use less stack than normal calls. Retain entry 1882214571Sdim for normal call over one for tail call. */ 1883214571Sdim if (p->is_tail > callee->is_tail) 1884214571Sdim p->is_tail = callee->is_tail; 1885214571Sdim return FALSE; 1886214571Sdim } 1887214571Sdim callee->next = caller->call_list; 1888214571Sdim caller->call_list = callee; 1889214571Sdim return TRUE; 1890214571Sdim} 1891214571Sdim 1892214571Sdim/* Rummage through the relocs for SEC, looking for function calls. 1893214571Sdim If CALL_TREE is true, fill in call graph. If CALL_TREE is false, 1894214571Sdim mark destination symbols on calls as being functions. Also 1895214571Sdim look at branches, which may be tail calls or go to hot/cold 1896214571Sdim section part of same function. */ 1897214571Sdim 1898214571Sdimstatic bfd_boolean 1899214571Sdimmark_functions_via_relocs (asection *sec, 1900214571Sdim struct bfd_link_info *info, 1901214571Sdim int call_tree) 1902214571Sdim{ 1903214571Sdim Elf_Internal_Rela *internal_relocs, *irelaend, *irela; 1904214571Sdim Elf_Internal_Shdr *symtab_hdr = &elf_tdata (sec->owner)->symtab_hdr; 1905214571Sdim Elf_Internal_Sym *syms; 1906214571Sdim void *psyms; 1907214571Sdim static bfd_boolean warned; 1908214571Sdim 1909214571Sdim internal_relocs = _bfd_elf_link_read_relocs (sec->owner, sec, NULL, NULL, 1910214571Sdim info->keep_memory); 1911214571Sdim if (internal_relocs == NULL) 1912214571Sdim return FALSE; 1913214571Sdim 1914214571Sdim symtab_hdr = &elf_tdata (sec->owner)->symtab_hdr; 1915214571Sdim psyms = &symtab_hdr->contents; 1916214571Sdim syms = *(Elf_Internal_Sym **) psyms; 1917214571Sdim irela = internal_relocs; 1918214571Sdim irelaend = irela + sec->reloc_count; 1919214571Sdim for (; irela < irelaend; irela++) 1920214571Sdim { 1921214571Sdim enum elf_spu_reloc_type r_type; 1922214571Sdim unsigned int r_indx; 1923214571Sdim asection *sym_sec; 1924214571Sdim Elf_Internal_Sym *sym; 1925214571Sdim struct elf_link_hash_entry *h; 1926214571Sdim bfd_vma val; 1927214571Sdim unsigned char insn[4]; 1928214571Sdim bfd_boolean is_call; 1929214571Sdim struct function_info *caller; 1930214571Sdim struct call_info *callee; 1931214571Sdim 1932214571Sdim r_type = ELF32_R_TYPE (irela->r_info); 1933214571Sdim if (r_type != R_SPU_REL16 1934214571Sdim && r_type != R_SPU_ADDR16) 1935214571Sdim continue; 1936214571Sdim 1937214571Sdim r_indx = ELF32_R_SYM (irela->r_info); 1938214571Sdim if (!get_sym_h (&h, &sym, &sym_sec, psyms, r_indx, sec->owner)) 1939214571Sdim return FALSE; 1940214571Sdim 1941214571Sdim if (sym_sec == NULL 1942214571Sdim || sym_sec->output_section == NULL 1943214571Sdim || sym_sec->output_section->owner != sec->output_section->owner) 1944214571Sdim continue; 1945214571Sdim 1946214571Sdim if (!bfd_get_section_contents (sec->owner, sec, insn, 1947214571Sdim irela->r_offset, 4)) 1948214571Sdim return FALSE; 1949214571Sdim if (!is_branch (insn)) 1950214571Sdim continue; 1951214571Sdim 1952214571Sdim if ((sym_sec->flags & (SEC_ALLOC | SEC_LOAD | SEC_CODE)) 1953214571Sdim != (SEC_ALLOC | SEC_LOAD | SEC_CODE)) 1954214571Sdim { 1955214571Sdim if (!call_tree) 1956214571Sdim warned = TRUE; 1957214571Sdim if (!call_tree || !warned) 1958214571Sdim info->callbacks->einfo (_("%B(%A+0x%v): call to non-code section" 1959214571Sdim " %B(%A), stack analysis incomplete\n"), 1960214571Sdim sec->owner, sec, irela->r_offset, 1961214571Sdim sym_sec->owner, sym_sec); 1962214571Sdim continue; 1963214571Sdim } 1964214571Sdim 1965214571Sdim is_call = (insn[0] & 0xfd) == 0x31; 1966214571Sdim 1967214571Sdim if (h) 1968214571Sdim val = h->root.u.def.value; 1969214571Sdim else 1970214571Sdim val = sym->st_value; 1971214571Sdim val += irela->r_addend; 1972214571Sdim 1973214571Sdim if (!call_tree) 1974214571Sdim { 1975214571Sdim struct function_info *fun; 1976214571Sdim 1977214571Sdim if (irela->r_addend != 0) 1978214571Sdim { 1979214571Sdim Elf_Internal_Sym *fake = bfd_zmalloc (sizeof (*fake)); 1980214571Sdim if (fake == NULL) 1981214571Sdim return FALSE; 1982214571Sdim fake->st_value = val; 1983214571Sdim fake->st_shndx 1984214571Sdim = _bfd_elf_section_from_bfd_section (sym_sec->owner, sym_sec); 1985214571Sdim sym = fake; 1986214571Sdim } 1987214571Sdim if (sym) 1988214571Sdim fun = maybe_insert_function (sym_sec, sym, FALSE, is_call); 1989214571Sdim else 1990214571Sdim fun = maybe_insert_function (sym_sec, h, TRUE, is_call); 1991214571Sdim if (fun == NULL) 1992214571Sdim return FALSE; 1993214571Sdim if (irela->r_addend != 0 1994214571Sdim && fun->u.sym != sym) 1995214571Sdim free (sym); 1996214571Sdim continue; 1997214571Sdim } 1998214571Sdim 1999214571Sdim caller = find_function (sec, irela->r_offset, info); 2000214571Sdim if (caller == NULL) 2001214571Sdim return FALSE; 2002214571Sdim callee = bfd_malloc (sizeof *callee); 2003214571Sdim if (callee == NULL) 2004214571Sdim return FALSE; 2005214571Sdim 2006214571Sdim callee->fun = find_function (sym_sec, val, info); 2007214571Sdim if (callee->fun == NULL) 2008214571Sdim return FALSE; 2009214571Sdim callee->is_tail = !is_call; 2010214571Sdim if (!insert_callee (caller, callee)) 2011214571Sdim free (callee); 2012214571Sdim else if (!is_call 2013214571Sdim && !callee->fun->is_func 2014214571Sdim && callee->fun->stack == 0) 2015214571Sdim { 2016214571Sdim /* This is either a tail call or a branch from one part of 2017214571Sdim the function to another, ie. hot/cold section. If the 2018214571Sdim destination has been called by some other function then 2019214571Sdim it is a separate function. We also assume that functions 2020214571Sdim are not split across input files. */ 2021214571Sdim if (callee->fun->start != NULL 2022214571Sdim || sec->owner != sym_sec->owner) 2023214571Sdim { 2024214571Sdim callee->fun->start = NULL; 2025214571Sdim callee->fun->is_func = TRUE; 2026214571Sdim } 2027214571Sdim else 2028214571Sdim callee->fun->start = caller; 2029214571Sdim } 2030214571Sdim } 2031214571Sdim 2032214571Sdim return TRUE; 2033214571Sdim} 2034214571Sdim 2035214571Sdim/* Handle something like .init or .fini, which has a piece of a function. 2036214571Sdim These sections are pasted together to form a single function. */ 2037214571Sdim 2038214571Sdimstatic bfd_boolean 2039214571Sdimpasted_function (asection *sec, struct bfd_link_info *info) 2040214571Sdim{ 2041214571Sdim struct bfd_link_order *l; 2042214571Sdim struct _spu_elf_section_data *sec_data; 2043214571Sdim struct spu_elf_stack_info *sinfo; 2044214571Sdim Elf_Internal_Sym *fake; 2045214571Sdim struct function_info *fun, *fun_start; 2046214571Sdim 2047214571Sdim fake = bfd_zmalloc (sizeof (*fake)); 2048214571Sdim if (fake == NULL) 2049214571Sdim return FALSE; 2050214571Sdim fake->st_value = 0; 2051214571Sdim fake->st_size = sec->size; 2052214571Sdim fake->st_shndx 2053214571Sdim = _bfd_elf_section_from_bfd_section (sec->owner, sec); 2054214571Sdim fun = maybe_insert_function (sec, fake, FALSE, FALSE); 2055214571Sdim if (!fun) 2056214571Sdim return FALSE; 2057214571Sdim 2058214571Sdim /* Find a function immediately preceding this section. */ 2059214571Sdim fun_start = NULL; 2060214571Sdim for (l = sec->output_section->map_head.link_order; l != NULL; l = l->next) 2061214571Sdim { 2062214571Sdim if (l->u.indirect.section == sec) 2063214571Sdim { 2064214571Sdim if (fun_start != NULL) 2065214571Sdim { 2066214571Sdim if (fun_start->start) 2067214571Sdim fun_start = fun_start->start; 2068214571Sdim fun->start = fun_start; 2069214571Sdim } 2070214571Sdim return TRUE; 2071214571Sdim } 2072214571Sdim if (l->type == bfd_indirect_link_order 2073214571Sdim && (sec_data = spu_elf_section_data (l->u.indirect.section)) != NULL 2074214571Sdim && (sinfo = sec_data->stack_info) != NULL 2075214571Sdim && sinfo->num_fun != 0) 2076214571Sdim fun_start = &sinfo->fun[sinfo->num_fun - 1]; 2077214571Sdim } 2078214571Sdim 2079214571Sdim info->callbacks->einfo (_("%A link_order not found\n"), sec); 2080214571Sdim return FALSE; 2081214571Sdim} 2082214571Sdim 2083214571Sdim/* We're only interested in code sections. */ 2084214571Sdim 2085214571Sdimstatic bfd_boolean 2086214571Sdiminteresting_section (asection *s, bfd *obfd, struct spu_link_hash_table *htab) 2087214571Sdim{ 2088214571Sdim return (s != htab->stub 2089214571Sdim && s->output_section != NULL 2090214571Sdim && s->output_section->owner == obfd 2091214571Sdim && ((s->flags & (SEC_ALLOC | SEC_LOAD | SEC_CODE)) 2092214571Sdim == (SEC_ALLOC | SEC_LOAD | SEC_CODE)) 2093214571Sdim && s->size != 0); 2094214571Sdim} 2095214571Sdim 2096214571Sdim/* Map address ranges in code sections to functions. */ 2097214571Sdim 2098214571Sdimstatic bfd_boolean 2099214571Sdimdiscover_functions (bfd *output_bfd, struct bfd_link_info *info) 2100214571Sdim{ 2101214571Sdim struct spu_link_hash_table *htab = spu_hash_table (info); 2102214571Sdim bfd *ibfd; 2103214571Sdim int bfd_idx; 2104214571Sdim Elf_Internal_Sym ***psym_arr; 2105214571Sdim asection ***sec_arr; 2106214571Sdim bfd_boolean gaps = FALSE; 2107214571Sdim 2108214571Sdim bfd_idx = 0; 2109214571Sdim for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) 2110214571Sdim bfd_idx++; 2111214571Sdim 2112214571Sdim psym_arr = bfd_zmalloc (bfd_idx * sizeof (*psym_arr)); 2113214571Sdim if (psym_arr == NULL) 2114214571Sdim return FALSE; 2115214571Sdim sec_arr = bfd_zmalloc (bfd_idx * sizeof (*sec_arr)); 2116214571Sdim if (sec_arr == NULL) 2117214571Sdim return FALSE; 2118214571Sdim 2119214571Sdim 2120214571Sdim for (ibfd = info->input_bfds, bfd_idx = 0; 2121214571Sdim ibfd != NULL; 2122214571Sdim ibfd = ibfd->link_next, bfd_idx++) 2123214571Sdim { 2124214571Sdim extern const bfd_target bfd_elf32_spu_vec; 2125214571Sdim Elf_Internal_Shdr *symtab_hdr; 2126214571Sdim asection *sec; 2127214571Sdim size_t symcount; 2128214571Sdim Elf_Internal_Sym *syms, *sy, **psyms, **psy; 2129214571Sdim asection **psecs, **p; 2130214571Sdim 2131214571Sdim if (ibfd->xvec != &bfd_elf32_spu_vec) 2132214571Sdim continue; 2133214571Sdim 2134214571Sdim /* Read all the symbols. */ 2135214571Sdim symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; 2136214571Sdim symcount = symtab_hdr->sh_size / symtab_hdr->sh_entsize; 2137214571Sdim if (symcount == 0) 2138214571Sdim continue; 2139214571Sdim 2140214571Sdim syms = (Elf_Internal_Sym *) symtab_hdr->contents; 2141214571Sdim if (syms == NULL) 2142214571Sdim { 2143214571Sdim syms = bfd_elf_get_elf_syms (ibfd, symtab_hdr, symcount, 0, 2144214571Sdim NULL, NULL, NULL); 2145214571Sdim symtab_hdr->contents = (void *) syms; 2146214571Sdim if (syms == NULL) 2147214571Sdim return FALSE; 2148214571Sdim } 2149214571Sdim 2150214571Sdim /* Select defined function symbols that are going to be output. */ 2151214571Sdim psyms = bfd_malloc ((symcount + 1) * sizeof (*psyms)); 2152214571Sdim if (psyms == NULL) 2153214571Sdim return FALSE; 2154214571Sdim psym_arr[bfd_idx] = psyms; 2155214571Sdim psecs = bfd_malloc (symcount * sizeof (*psecs)); 2156214571Sdim if (psecs == NULL) 2157214571Sdim return FALSE; 2158214571Sdim sec_arr[bfd_idx] = psecs; 2159214571Sdim for (psy = psyms, p = psecs, sy = syms; sy < syms + symcount; ++p, ++sy) 2160214571Sdim if (ELF_ST_TYPE (sy->st_info) == STT_NOTYPE 2161214571Sdim || ELF_ST_TYPE (sy->st_info) == STT_FUNC) 2162214571Sdim { 2163214571Sdim asection *s; 2164214571Sdim 2165214571Sdim *p = s = bfd_section_from_elf_index (ibfd, sy->st_shndx); 2166214571Sdim if (s != NULL && interesting_section (s, output_bfd, htab)) 2167214571Sdim *psy++ = sy; 2168214571Sdim } 2169214571Sdim symcount = psy - psyms; 2170214571Sdim *psy = NULL; 2171214571Sdim 2172214571Sdim /* Sort them by section and offset within section. */ 2173214571Sdim sort_syms_syms = syms; 2174214571Sdim sort_syms_psecs = psecs; 2175214571Sdim qsort (psyms, symcount, sizeof (*psyms), sort_syms); 2176214571Sdim 2177214571Sdim /* Now inspect the function symbols. */ 2178214571Sdim for (psy = psyms; psy < psyms + symcount; ) 2179214571Sdim { 2180214571Sdim asection *s = psecs[*psy - syms]; 2181214571Sdim Elf_Internal_Sym **psy2; 2182214571Sdim 2183214571Sdim for (psy2 = psy; ++psy2 < psyms + symcount; ) 2184214571Sdim if (psecs[*psy2 - syms] != s) 2185214571Sdim break; 2186214571Sdim 2187214571Sdim if (!alloc_stack_info (s, psy2 - psy)) 2188214571Sdim return FALSE; 2189214571Sdim psy = psy2; 2190214571Sdim } 2191214571Sdim 2192214571Sdim /* First install info about properly typed and sized functions. 2193214571Sdim In an ideal world this will cover all code sections, except 2194214571Sdim when partitioning functions into hot and cold sections, 2195214571Sdim and the horrible pasted together .init and .fini functions. */ 2196214571Sdim for (psy = psyms; psy < psyms + symcount; ++psy) 2197214571Sdim { 2198214571Sdim sy = *psy; 2199214571Sdim if (ELF_ST_TYPE (sy->st_info) == STT_FUNC) 2200214571Sdim { 2201214571Sdim asection *s = psecs[sy - syms]; 2202214571Sdim if (!maybe_insert_function (s, sy, FALSE, TRUE)) 2203214571Sdim return FALSE; 2204214571Sdim } 2205214571Sdim } 2206214571Sdim 2207214571Sdim for (sec = ibfd->sections; sec != NULL && !gaps; sec = sec->next) 2208214571Sdim if (interesting_section (sec, output_bfd, htab)) 2209214571Sdim gaps |= check_function_ranges (sec, info); 2210214571Sdim } 2211214571Sdim 2212214571Sdim if (gaps) 2213214571Sdim { 2214214571Sdim /* See if we can discover more function symbols by looking at 2215214571Sdim relocations. */ 2216214571Sdim for (ibfd = info->input_bfds, bfd_idx = 0; 2217214571Sdim ibfd != NULL; 2218214571Sdim ibfd = ibfd->link_next, bfd_idx++) 2219214571Sdim { 2220214571Sdim asection *sec; 2221214571Sdim 2222214571Sdim if (psym_arr[bfd_idx] == NULL) 2223214571Sdim continue; 2224214571Sdim 2225214571Sdim for (sec = ibfd->sections; sec != NULL; sec = sec->next) 2226214571Sdim if (interesting_section (sec, output_bfd, htab) 2227214571Sdim && sec->reloc_count != 0) 2228214571Sdim { 2229214571Sdim if (!mark_functions_via_relocs (sec, info, FALSE)) 2230214571Sdim return FALSE; 2231214571Sdim } 2232214571Sdim } 2233214571Sdim 2234214571Sdim for (ibfd = info->input_bfds, bfd_idx = 0; 2235214571Sdim ibfd != NULL; 2236214571Sdim ibfd = ibfd->link_next, bfd_idx++) 2237214571Sdim { 2238214571Sdim Elf_Internal_Shdr *symtab_hdr; 2239214571Sdim asection *sec; 2240214571Sdim Elf_Internal_Sym *syms, *sy, **psyms, **psy; 2241214571Sdim asection **psecs; 2242214571Sdim 2243214571Sdim if ((psyms = psym_arr[bfd_idx]) == NULL) 2244214571Sdim continue; 2245214571Sdim 2246214571Sdim psecs = sec_arr[bfd_idx]; 2247214571Sdim 2248214571Sdim symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; 2249214571Sdim syms = (Elf_Internal_Sym *) symtab_hdr->contents; 2250214571Sdim 2251214571Sdim gaps = FALSE; 2252214571Sdim for (sec = ibfd->sections; sec != NULL && !gaps; sec = sec->next) 2253214571Sdim if (interesting_section (sec, output_bfd, htab)) 2254214571Sdim gaps |= check_function_ranges (sec, info); 2255214571Sdim if (!gaps) 2256214571Sdim continue; 2257214571Sdim 2258214571Sdim /* Finally, install all globals. */ 2259214571Sdim for (psy = psyms; (sy = *psy) != NULL; ++psy) 2260214571Sdim { 2261214571Sdim asection *s; 2262214571Sdim 2263214571Sdim s = psecs[sy - syms]; 2264214571Sdim 2265214571Sdim /* Global syms might be improperly typed functions. */ 2266214571Sdim if (ELF_ST_TYPE (sy->st_info) != STT_FUNC 2267214571Sdim && ELF_ST_BIND (sy->st_info) == STB_GLOBAL) 2268214571Sdim { 2269214571Sdim if (!maybe_insert_function (s, sy, FALSE, FALSE)) 2270214571Sdim return FALSE; 2271214571Sdim } 2272214571Sdim } 2273214571Sdim 2274214571Sdim /* Some of the symbols we've installed as marking the 2275214571Sdim beginning of functions may have a size of zero. Extend 2276214571Sdim the range of such functions to the beginning of the 2277214571Sdim next symbol of interest. */ 2278214571Sdim for (sec = ibfd->sections; sec != NULL; sec = sec->next) 2279214571Sdim if (interesting_section (sec, output_bfd, htab)) 2280214571Sdim { 2281214571Sdim struct _spu_elf_section_data *sec_data; 2282214571Sdim struct spu_elf_stack_info *sinfo; 2283214571Sdim 2284214571Sdim sec_data = spu_elf_section_data (sec); 2285214571Sdim sinfo = sec_data->stack_info; 2286214571Sdim if (sinfo != NULL) 2287214571Sdim { 2288214571Sdim int fun_idx; 2289214571Sdim bfd_vma hi = sec->size; 2290214571Sdim 2291214571Sdim for (fun_idx = sinfo->num_fun; --fun_idx >= 0; ) 2292214571Sdim { 2293214571Sdim sinfo->fun[fun_idx].hi = hi; 2294214571Sdim hi = sinfo->fun[fun_idx].lo; 2295214571Sdim } 2296214571Sdim } 2297214571Sdim /* No symbols in this section. Must be .init or .fini 2298214571Sdim or something similar. */ 2299214571Sdim else if (!pasted_function (sec, info)) 2300214571Sdim return FALSE; 2301214571Sdim } 2302214571Sdim } 2303214571Sdim } 2304214571Sdim 2305214571Sdim for (ibfd = info->input_bfds, bfd_idx = 0; 2306214571Sdim ibfd != NULL; 2307214571Sdim ibfd = ibfd->link_next, bfd_idx++) 2308214571Sdim { 2309214571Sdim if (psym_arr[bfd_idx] == NULL) 2310214571Sdim continue; 2311214571Sdim 2312214571Sdim free (psym_arr[bfd_idx]); 2313214571Sdim free (sec_arr[bfd_idx]); 2314214571Sdim } 2315214571Sdim 2316214571Sdim free (psym_arr); 2317214571Sdim free (sec_arr); 2318214571Sdim 2319214571Sdim return TRUE; 2320214571Sdim} 2321214571Sdim 2322214571Sdim/* Mark nodes in the call graph that are called by some other node. */ 2323214571Sdim 2324214571Sdimstatic void 2325214571Sdimmark_non_root (struct function_info *fun) 2326214571Sdim{ 2327214571Sdim struct call_info *call; 2328214571Sdim 2329214571Sdim fun->visit1 = TRUE; 2330214571Sdim for (call = fun->call_list; call; call = call->next) 2331214571Sdim { 2332214571Sdim call->fun->non_root = TRUE; 2333214571Sdim if (!call->fun->visit1) 2334214571Sdim mark_non_root (call->fun); 2335214571Sdim } 2336214571Sdim} 2337214571Sdim 2338214571Sdim/* Remove cycles from the call graph. */ 2339214571Sdim 2340214571Sdimstatic void 2341214571Sdimcall_graph_traverse (struct function_info *fun, struct bfd_link_info *info) 2342214571Sdim{ 2343214571Sdim struct call_info **callp, *call; 2344214571Sdim 2345214571Sdim fun->visit2 = TRUE; 2346214571Sdim fun->marking = TRUE; 2347214571Sdim 2348214571Sdim callp = &fun->call_list; 2349214571Sdim while ((call = *callp) != NULL) 2350214571Sdim { 2351214571Sdim if (!call->fun->visit2) 2352214571Sdim call_graph_traverse (call->fun, info); 2353214571Sdim else if (call->fun->marking) 2354214571Sdim { 2355214571Sdim const char *f1 = func_name (fun); 2356214571Sdim const char *f2 = func_name (call->fun); 2357214571Sdim 2358214571Sdim info->callbacks->info (_("Stack analysis will ignore the call " 2359214571Sdim "from %s to %s\n"), 2360214571Sdim f1, f2); 2361214571Sdim *callp = call->next; 2362214571Sdim continue; 2363214571Sdim } 2364214571Sdim callp = &call->next; 2365214571Sdim } 2366214571Sdim fun->marking = FALSE; 2367214571Sdim} 2368214571Sdim 2369214571Sdim/* Populate call_list for each function. */ 2370214571Sdim 2371214571Sdimstatic bfd_boolean 2372214571Sdimbuild_call_tree (bfd *output_bfd, struct bfd_link_info *info) 2373214571Sdim{ 2374214571Sdim struct spu_link_hash_table *htab = spu_hash_table (info); 2375214571Sdim bfd *ibfd; 2376214571Sdim 2377214571Sdim for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) 2378214571Sdim { 2379214571Sdim extern const bfd_target bfd_elf32_spu_vec; 2380214571Sdim asection *sec; 2381214571Sdim 2382214571Sdim if (ibfd->xvec != &bfd_elf32_spu_vec) 2383214571Sdim continue; 2384214571Sdim 2385214571Sdim for (sec = ibfd->sections; sec != NULL; sec = sec->next) 2386214571Sdim { 2387214571Sdim if (!interesting_section (sec, output_bfd, htab) 2388214571Sdim || sec->reloc_count == 0) 2389214571Sdim continue; 2390214571Sdim 2391214571Sdim if (!mark_functions_via_relocs (sec, info, TRUE)) 2392214571Sdim return FALSE; 2393214571Sdim } 2394214571Sdim 2395214571Sdim /* Transfer call info from hot/cold section part of function 2396214571Sdim to main entry. */ 2397214571Sdim for (sec = ibfd->sections; sec != NULL; sec = sec->next) 2398214571Sdim { 2399214571Sdim struct _spu_elf_section_data *sec_data; 2400214571Sdim struct spu_elf_stack_info *sinfo; 2401214571Sdim 2402214571Sdim if ((sec_data = spu_elf_section_data (sec)) != NULL 2403214571Sdim && (sinfo = sec_data->stack_info) != NULL) 2404214571Sdim { 2405214571Sdim int i; 2406214571Sdim for (i = 0; i < sinfo->num_fun; ++i) 2407214571Sdim { 2408214571Sdim if (sinfo->fun[i].start != NULL) 2409214571Sdim { 2410214571Sdim struct call_info *call = sinfo->fun[i].call_list; 2411214571Sdim 2412214571Sdim while (call != NULL) 2413214571Sdim { 2414214571Sdim struct call_info *call_next = call->next; 2415214571Sdim if (!insert_callee (sinfo->fun[i].start, call)) 2416214571Sdim free (call); 2417214571Sdim call = call_next; 2418214571Sdim } 2419214571Sdim sinfo->fun[i].call_list = NULL; 2420214571Sdim sinfo->fun[i].non_root = TRUE; 2421214571Sdim } 2422214571Sdim } 2423214571Sdim } 2424214571Sdim } 2425214571Sdim } 2426214571Sdim 2427214571Sdim /* Find the call graph root(s). */ 2428214571Sdim for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) 2429214571Sdim { 2430214571Sdim extern const bfd_target bfd_elf32_spu_vec; 2431214571Sdim asection *sec; 2432214571Sdim 2433214571Sdim if (ibfd->xvec != &bfd_elf32_spu_vec) 2434214571Sdim continue; 2435214571Sdim 2436214571Sdim for (sec = ibfd->sections; sec != NULL; sec = sec->next) 2437214571Sdim { 2438214571Sdim struct _spu_elf_section_data *sec_data; 2439214571Sdim struct spu_elf_stack_info *sinfo; 2440214571Sdim 2441214571Sdim if ((sec_data = spu_elf_section_data (sec)) != NULL 2442214571Sdim && (sinfo = sec_data->stack_info) != NULL) 2443214571Sdim { 2444214571Sdim int i; 2445214571Sdim for (i = 0; i < sinfo->num_fun; ++i) 2446214571Sdim if (!sinfo->fun[i].visit1) 2447214571Sdim mark_non_root (&sinfo->fun[i]); 2448214571Sdim } 2449214571Sdim } 2450214571Sdim } 2451214571Sdim 2452214571Sdim /* Remove cycles from the call graph. We start from the root node(s) 2453214571Sdim so that we break cycles in a reasonable place. */ 2454214571Sdim for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) 2455214571Sdim { 2456214571Sdim extern const bfd_target bfd_elf32_spu_vec; 2457214571Sdim asection *sec; 2458214571Sdim 2459214571Sdim if (ibfd->xvec != &bfd_elf32_spu_vec) 2460214571Sdim continue; 2461214571Sdim 2462214571Sdim for (sec = ibfd->sections; sec != NULL; sec = sec->next) 2463214571Sdim { 2464214571Sdim struct _spu_elf_section_data *sec_data; 2465214571Sdim struct spu_elf_stack_info *sinfo; 2466214571Sdim 2467214571Sdim if ((sec_data = spu_elf_section_data (sec)) != NULL 2468214571Sdim && (sinfo = sec_data->stack_info) != NULL) 2469214571Sdim { 2470214571Sdim int i; 2471214571Sdim for (i = 0; i < sinfo->num_fun; ++i) 2472214571Sdim if (!sinfo->fun[i].non_root) 2473214571Sdim call_graph_traverse (&sinfo->fun[i], info); 2474214571Sdim } 2475214571Sdim } 2476214571Sdim } 2477214571Sdim 2478214571Sdim return TRUE; 2479214571Sdim} 2480214571Sdim 2481214571Sdim/* Descend the call graph for FUN, accumulating total stack required. */ 2482214571Sdim 2483214571Sdimstatic bfd_vma 2484214571Sdimsum_stack (struct function_info *fun, 2485214571Sdim struct bfd_link_info *info, 2486214571Sdim int emit_stack_syms) 2487214571Sdim{ 2488214571Sdim struct call_info *call; 2489214571Sdim struct function_info *max = NULL; 2490214571Sdim bfd_vma max_stack = fun->stack; 2491214571Sdim bfd_vma stack; 2492214571Sdim const char *f1; 2493214571Sdim 2494214571Sdim if (fun->visit3) 2495214571Sdim return max_stack; 2496214571Sdim 2497214571Sdim for (call = fun->call_list; call; call = call->next) 2498214571Sdim { 2499214571Sdim stack = sum_stack (call->fun, info, emit_stack_syms); 2500214571Sdim /* Include caller stack for normal calls, don't do so for 2501214571Sdim tail calls. fun->stack here is local stack usage for 2502214571Sdim this function. */ 2503214571Sdim if (!call->is_tail) 2504214571Sdim stack += fun->stack; 2505214571Sdim if (max_stack < stack) 2506214571Sdim { 2507214571Sdim max_stack = stack; 2508214571Sdim max = call->fun; 2509214571Sdim } 2510214571Sdim } 2511214571Sdim 2512214571Sdim f1 = func_name (fun); 2513214571Sdim info->callbacks->minfo (_("%s: 0x%v 0x%v\n"), f1, fun->stack, max_stack); 2514214571Sdim 2515214571Sdim if (fun->call_list) 2516214571Sdim { 2517214571Sdim info->callbacks->minfo (_(" calls:\n")); 2518214571Sdim for (call = fun->call_list; call; call = call->next) 2519214571Sdim { 2520214571Sdim const char *f2 = func_name (call->fun); 2521214571Sdim const char *ann1 = call->fun == max ? "*" : " "; 2522214571Sdim const char *ann2 = call->is_tail ? "t" : " "; 2523214571Sdim 2524214571Sdim info->callbacks->minfo (_(" %s%s %s\n"), ann1, ann2, f2); 2525214571Sdim } 2526214571Sdim } 2527214571Sdim 2528214571Sdim /* Now fun->stack holds cumulative stack. */ 2529214571Sdim fun->stack = max_stack; 2530214571Sdim fun->visit3 = TRUE; 2531214571Sdim 2532214571Sdim if (emit_stack_syms) 2533214571Sdim { 2534214571Sdim struct spu_link_hash_table *htab = spu_hash_table (info); 2535214571Sdim char *name = bfd_malloc (18 + strlen (f1)); 2536214571Sdim struct elf_link_hash_entry *h; 2537214571Sdim 2538214571Sdim if (name != NULL) 2539214571Sdim { 2540214571Sdim if (fun->global || ELF_ST_BIND (fun->u.sym->st_info) == STB_GLOBAL) 2541214571Sdim sprintf (name, "__stack_%s", f1); 2542214571Sdim else 2543214571Sdim sprintf (name, "__stack_%x_%s", fun->sec->id & 0xffffffff, f1); 2544214571Sdim 2545214571Sdim h = elf_link_hash_lookup (&htab->elf, name, TRUE, TRUE, FALSE); 2546214571Sdim free (name); 2547214571Sdim if (h != NULL 2548214571Sdim && (h->root.type == bfd_link_hash_new 2549214571Sdim || h->root.type == bfd_link_hash_undefined 2550214571Sdim || h->root.type == bfd_link_hash_undefweak)) 2551214571Sdim { 2552214571Sdim h->root.type = bfd_link_hash_defined; 2553214571Sdim h->root.u.def.section = bfd_abs_section_ptr; 2554214571Sdim h->root.u.def.value = max_stack; 2555214571Sdim h->size = 0; 2556214571Sdim h->type = 0; 2557214571Sdim h->ref_regular = 1; 2558214571Sdim h->def_regular = 1; 2559214571Sdim h->ref_regular_nonweak = 1; 2560214571Sdim h->forced_local = 1; 2561214571Sdim h->non_elf = 0; 2562214571Sdim } 2563214571Sdim } 2564214571Sdim } 2565214571Sdim 2566214571Sdim return max_stack; 2567214571Sdim} 2568214571Sdim 2569214571Sdim/* Provide an estimate of total stack required. */ 2570214571Sdim 2571214571Sdimstatic bfd_boolean 2572214571Sdimspu_elf_stack_analysis (bfd *output_bfd, 2573214571Sdim struct bfd_link_info *info, 2574214571Sdim int emit_stack_syms) 2575214571Sdim{ 2576214571Sdim bfd *ibfd; 2577214571Sdim bfd_vma max_stack = 0; 2578214571Sdim 2579214571Sdim if (!discover_functions (output_bfd, info)) 2580214571Sdim return FALSE; 2581214571Sdim 2582214571Sdim if (!build_call_tree (output_bfd, info)) 2583214571Sdim return FALSE; 2584214571Sdim 2585214571Sdim info->callbacks->info (_("Stack size for call graph root nodes.\n")); 2586214571Sdim info->callbacks->minfo (_("\nStack size for functions. " 2587214571Sdim "Annotations: '*' max stack, 't' tail call\n")); 2588214571Sdim for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) 2589214571Sdim { 2590214571Sdim extern const bfd_target bfd_elf32_spu_vec; 2591214571Sdim asection *sec; 2592214571Sdim 2593214571Sdim if (ibfd->xvec != &bfd_elf32_spu_vec) 2594214571Sdim continue; 2595214571Sdim 2596214571Sdim for (sec = ibfd->sections; sec != NULL; sec = sec->next) 2597214571Sdim { 2598214571Sdim struct _spu_elf_section_data *sec_data; 2599214571Sdim struct spu_elf_stack_info *sinfo; 2600214571Sdim 2601214571Sdim if ((sec_data = spu_elf_section_data (sec)) != NULL 2602214571Sdim && (sinfo = sec_data->stack_info) != NULL) 2603214571Sdim { 2604214571Sdim int i; 2605214571Sdim for (i = 0; i < sinfo->num_fun; ++i) 2606214571Sdim { 2607214571Sdim if (!sinfo->fun[i].non_root) 2608214571Sdim { 2609214571Sdim bfd_vma stack; 2610214571Sdim const char *f1; 2611214571Sdim 2612214571Sdim stack = sum_stack (&sinfo->fun[i], info, 2613214571Sdim emit_stack_syms); 2614214571Sdim f1 = func_name (&sinfo->fun[i]); 2615214571Sdim info->callbacks->info (_(" %s: 0x%v\n"), 2616214571Sdim f1, stack); 2617214571Sdim if (max_stack < stack) 2618214571Sdim max_stack = stack; 2619214571Sdim } 2620214571Sdim } 2621214571Sdim } 2622214571Sdim } 2623214571Sdim } 2624214571Sdim 2625214571Sdim info->callbacks->info (_("Maximum stack required is 0x%v\n"), max_stack); 2626214571Sdim return TRUE; 2627214571Sdim} 2628214571Sdim 2629214571Sdim/* Perform a final link. */ 2630214571Sdim 2631214571Sdimstatic bfd_boolean 2632214571Sdimspu_elf_final_link (bfd *output_bfd, struct bfd_link_info *info) 2633214571Sdim{ 2634214571Sdim struct spu_link_hash_table *htab = spu_hash_table (info); 2635214571Sdim 2636214571Sdim if (htab->stack_analysis 2637214571Sdim && !spu_elf_stack_analysis (output_bfd, info, htab->emit_stack_syms)) 2638214571Sdim info->callbacks->einfo ("%X%P: stack analysis error: %E\n"); 2639214571Sdim 2640214571Sdim return bfd_elf_final_link (output_bfd, info); 2641214571Sdim} 2642214571Sdim 2643214571Sdim/* Called when not normally emitting relocs, ie. !info->relocatable 2644214571Sdim and !info->emitrelocations. Returns a count of special relocs 2645214571Sdim that need to be emitted. */ 2646214571Sdim 2647214571Sdimstatic unsigned int 2648214571Sdimspu_elf_count_relocs (asection *sec, Elf_Internal_Rela *relocs) 2649214571Sdim{ 2650214571Sdim unsigned int count = 0; 2651214571Sdim Elf_Internal_Rela *relend = relocs + sec->reloc_count; 2652214571Sdim 2653214571Sdim for (; relocs < relend; relocs++) 2654214571Sdim { 2655214571Sdim int r_type = ELF32_R_TYPE (relocs->r_info); 2656214571Sdim if (r_type == R_SPU_PPU32 || r_type == R_SPU_PPU64) 2657214571Sdim ++count; 2658214571Sdim } 2659214571Sdim 2660214571Sdim return count; 2661214571Sdim} 2662214571Sdim 2663214571Sdim/* Apply RELOCS to CONTENTS of INPUT_SECTION from INPUT_BFD. */ 2664214571Sdim 2665214571Sdimstatic bfd_boolean 2666214571Sdimspu_elf_relocate_section (bfd *output_bfd, 2667214571Sdim struct bfd_link_info *info, 2668214571Sdim bfd *input_bfd, 2669214571Sdim asection *input_section, 2670214571Sdim bfd_byte *contents, 2671214571Sdim Elf_Internal_Rela *relocs, 2672214571Sdim Elf_Internal_Sym *local_syms, 2673214571Sdim asection **local_sections) 2674214571Sdim{ 2675214571Sdim Elf_Internal_Shdr *symtab_hdr; 2676214571Sdim struct elf_link_hash_entry **sym_hashes; 2677214571Sdim Elf_Internal_Rela *rel, *relend; 2678214571Sdim struct spu_link_hash_table *htab; 2679214571Sdim bfd_boolean ret = TRUE; 2680214571Sdim bfd_boolean emit_these_relocs = FALSE; 2681214571Sdim 2682214571Sdim htab = spu_hash_table (info); 2683214571Sdim symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; 2684214571Sdim sym_hashes = (struct elf_link_hash_entry **) (elf_sym_hashes (input_bfd)); 2685214571Sdim 2686214571Sdim rel = relocs; 2687214571Sdim relend = relocs + input_section->reloc_count; 2688214571Sdim for (; rel < relend; rel++) 2689214571Sdim { 2690214571Sdim int r_type; 2691214571Sdim reloc_howto_type *howto; 2692214571Sdim unsigned long r_symndx; 2693214571Sdim Elf_Internal_Sym *sym; 2694214571Sdim asection *sec; 2695214571Sdim struct elf_link_hash_entry *h; 2696214571Sdim const char *sym_name; 2697214571Sdim bfd_vma relocation; 2698214571Sdim bfd_vma addend; 2699214571Sdim bfd_reloc_status_type r; 2700214571Sdim bfd_boolean unresolved_reloc; 2701214571Sdim bfd_boolean warned; 2702214571Sdim bfd_boolean branch; 2703214571Sdim 2704214571Sdim r_symndx = ELF32_R_SYM (rel->r_info); 2705214571Sdim r_type = ELF32_R_TYPE (rel->r_info); 2706214571Sdim if (r_type == R_SPU_PPU32 || r_type == R_SPU_PPU64) 2707214571Sdim { 2708214571Sdim emit_these_relocs = TRUE; 2709214571Sdim continue; 2710214571Sdim } 2711214571Sdim 2712214571Sdim howto = elf_howto_table + r_type; 2713214571Sdim unresolved_reloc = FALSE; 2714214571Sdim warned = FALSE; 2715214571Sdim h = NULL; 2716214571Sdim sym = NULL; 2717214571Sdim sec = NULL; 2718214571Sdim if (r_symndx < symtab_hdr->sh_info) 2719214571Sdim { 2720214571Sdim sym = local_syms + r_symndx; 2721214571Sdim sec = local_sections[r_symndx]; 2722214571Sdim sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, sec); 2723214571Sdim relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); 2724214571Sdim } 2725214571Sdim else 2726214571Sdim { 2727214571Sdim RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, 2728214571Sdim r_symndx, symtab_hdr, sym_hashes, 2729214571Sdim h, sec, relocation, 2730214571Sdim unresolved_reloc, warned); 2731214571Sdim sym_name = h->root.root.string; 2732214571Sdim } 2733214571Sdim 2734214571Sdim if (sec != NULL && elf_discarded_section (sec)) 2735214571Sdim { 2736214571Sdim /* For relocs against symbols from removed linkonce sections, 2737214571Sdim or sections discarded by a linker script, we just want the 2738214571Sdim section contents zeroed. Avoid any special processing. */ 2739214571Sdim _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset); 2740214571Sdim rel->r_info = 0; 2741214571Sdim rel->r_addend = 0; 2742214571Sdim continue; 2743214571Sdim } 2744214571Sdim 2745214571Sdim if (info->relocatable) 2746214571Sdim continue; 2747214571Sdim 2748214571Sdim if (unresolved_reloc) 2749214571Sdim { 2750214571Sdim (*_bfd_error_handler) 2751214571Sdim (_("%B(%s+0x%lx): unresolvable %s relocation against symbol `%s'"), 2752214571Sdim input_bfd, 2753214571Sdim bfd_get_section_name (input_bfd, input_section), 2754214571Sdim (long) rel->r_offset, 2755214571Sdim howto->name, 2756214571Sdim sym_name); 2757214571Sdim ret = FALSE; 2758214571Sdim } 2759214571Sdim 2760214571Sdim /* If this symbol is in an overlay area, we may need to relocate 2761214571Sdim to the overlay stub. */ 2762214571Sdim addend = rel->r_addend; 2763214571Sdim branch = (is_branch (contents + rel->r_offset) 2764214571Sdim || is_hint (contents + rel->r_offset)); 2765214571Sdim if (needs_ovl_stub (sym_name, sec, input_section, htab, branch)) 2766214571Sdim { 2767214571Sdim char *stub_name; 2768214571Sdim struct spu_stub_hash_entry *sh; 2769214571Sdim 2770214571Sdim stub_name = spu_stub_name (sec, h, rel); 2771214571Sdim if (stub_name == NULL) 2772214571Sdim return FALSE; 2773214571Sdim 2774214571Sdim sh = (struct spu_stub_hash_entry *) 2775214571Sdim bfd_hash_lookup (&htab->stub_hash_table, stub_name, FALSE, FALSE); 2776214571Sdim if (sh != NULL) 2777214571Sdim { 2778214571Sdim relocation = (htab->stub->output_section->vma 2779214571Sdim + htab->stub->output_offset 2780214571Sdim + sh->off); 2781214571Sdim addend = 0; 2782214571Sdim } 2783214571Sdim free (stub_name); 2784214571Sdim } 2785214571Sdim 2786214571Sdim r = _bfd_final_link_relocate (howto, 2787214571Sdim input_bfd, 2788214571Sdim input_section, 2789214571Sdim contents, 2790214571Sdim rel->r_offset, relocation, addend); 2791214571Sdim 2792214571Sdim if (r != bfd_reloc_ok) 2793214571Sdim { 2794214571Sdim const char *msg = (const char *) 0; 2795214571Sdim 2796214571Sdim switch (r) 2797214571Sdim { 2798214571Sdim case bfd_reloc_overflow: 2799214571Sdim if (!((*info->callbacks->reloc_overflow) 2800214571Sdim (info, (h ? &h->root : NULL), sym_name, howto->name, 2801214571Sdim (bfd_vma) 0, input_bfd, input_section, rel->r_offset))) 2802214571Sdim return FALSE; 2803214571Sdim break; 2804214571Sdim 2805214571Sdim case bfd_reloc_undefined: 2806214571Sdim if (!((*info->callbacks->undefined_symbol) 2807214571Sdim (info, sym_name, input_bfd, input_section, 2808214571Sdim rel->r_offset, TRUE))) 2809214571Sdim return FALSE; 2810214571Sdim break; 2811214571Sdim 2812214571Sdim case bfd_reloc_outofrange: 2813214571Sdim msg = _("internal error: out of range error"); 2814214571Sdim goto common_error; 2815214571Sdim 2816214571Sdim case bfd_reloc_notsupported: 2817214571Sdim msg = _("internal error: unsupported relocation error"); 2818214571Sdim goto common_error; 2819214571Sdim 2820214571Sdim case bfd_reloc_dangerous: 2821214571Sdim msg = _("internal error: dangerous error"); 2822214571Sdim goto common_error; 2823214571Sdim 2824214571Sdim default: 2825214571Sdim msg = _("internal error: unknown error"); 2826214571Sdim /* fall through */ 2827214571Sdim 2828214571Sdim common_error: 2829214571Sdim if (!((*info->callbacks->warning) 2830214571Sdim (info, msg, sym_name, input_bfd, input_section, 2831214571Sdim rel->r_offset))) 2832214571Sdim return FALSE; 2833214571Sdim break; 2834214571Sdim } 2835214571Sdim } 2836214571Sdim } 2837214571Sdim 2838214571Sdim if (ret 2839214571Sdim && emit_these_relocs 2840214571Sdim && !info->relocatable 2841214571Sdim && !info->emitrelocations) 2842214571Sdim { 2843214571Sdim Elf_Internal_Rela *wrel; 2844214571Sdim Elf_Internal_Shdr *rel_hdr; 2845214571Sdim 2846214571Sdim wrel = rel = relocs; 2847214571Sdim relend = relocs + input_section->reloc_count; 2848214571Sdim for (; rel < relend; rel++) 2849214571Sdim { 2850214571Sdim int r_type; 2851214571Sdim 2852214571Sdim r_type = ELF32_R_TYPE (rel->r_info); 2853214571Sdim if (r_type == R_SPU_PPU32 || r_type == R_SPU_PPU64) 2854214571Sdim *wrel++ = *rel; 2855214571Sdim } 2856214571Sdim input_section->reloc_count = wrel - relocs; 2857214571Sdim /* Backflips for _bfd_elf_link_output_relocs. */ 2858214571Sdim rel_hdr = &elf_section_data (input_section)->rel_hdr; 2859214571Sdim rel_hdr->sh_size = input_section->reloc_count * rel_hdr->sh_entsize; 2860214571Sdim ret = 2; 2861214571Sdim } 2862214571Sdim 2863214571Sdim return ret; 2864214571Sdim} 2865214571Sdim 2866214571Sdim/* Adjust _SPUEAR_ syms to point at their overlay stubs. */ 2867214571Sdim 2868214571Sdimstatic bfd_boolean 2869214571Sdimspu_elf_output_symbol_hook (struct bfd_link_info *info, 2870214571Sdim const char *sym_name ATTRIBUTE_UNUSED, 2871214571Sdim Elf_Internal_Sym *sym, 2872214571Sdim asection *sym_sec ATTRIBUTE_UNUSED, 2873214571Sdim struct elf_link_hash_entry *h) 2874214571Sdim{ 2875214571Sdim struct spu_link_hash_table *htab = spu_hash_table (info); 2876214571Sdim 2877214571Sdim if (!info->relocatable 2878214571Sdim && htab->num_overlays != 0 2879214571Sdim && h != NULL 2880214571Sdim && (h->root.type == bfd_link_hash_defined 2881214571Sdim || h->root.type == bfd_link_hash_defweak) 2882214571Sdim && h->def_regular 2883214571Sdim && strncmp (h->root.root.string, "_SPUEAR_", 8) == 0) 2884214571Sdim { 2885214571Sdim static Elf_Internal_Rela zero_rel; 2886214571Sdim char *stub_name = spu_stub_name (h->root.u.def.section, h, &zero_rel); 2887214571Sdim struct spu_stub_hash_entry *sh; 2888214571Sdim 2889214571Sdim if (stub_name == NULL) 2890214571Sdim return FALSE; 2891214571Sdim sh = (struct spu_stub_hash_entry *) 2892214571Sdim bfd_hash_lookup (&htab->stub_hash_table, stub_name, FALSE, FALSE); 2893214571Sdim free (stub_name); 2894214571Sdim if (sh == NULL) 2895214571Sdim return TRUE; 2896214571Sdim sym->st_shndx 2897214571Sdim = _bfd_elf_section_from_bfd_section (htab->stub->output_section->owner, 2898214571Sdim htab->stub->output_section); 2899214571Sdim sym->st_value = (htab->stub->output_section->vma 2900214571Sdim + htab->stub->output_offset 2901214571Sdim + sh->off); 2902214571Sdim } 2903214571Sdim 2904214571Sdim return TRUE; 2905214571Sdim} 2906214571Sdim 2907214571Sdimstatic int spu_plugin = 0; 2908214571Sdim 2909214571Sdimvoid 2910214571Sdimspu_elf_plugin (int val) 2911214571Sdim{ 2912214571Sdim spu_plugin = val; 2913214571Sdim} 2914214571Sdim 2915214571Sdim/* Set ELF header e_type for plugins. */ 2916214571Sdim 2917214571Sdimstatic void 2918214571Sdimspu_elf_post_process_headers (bfd *abfd, 2919214571Sdim struct bfd_link_info *info ATTRIBUTE_UNUSED) 2920214571Sdim{ 2921214571Sdim if (spu_plugin) 2922214571Sdim { 2923214571Sdim Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd); 2924214571Sdim 2925214571Sdim i_ehdrp->e_type = ET_DYN; 2926214571Sdim } 2927214571Sdim} 2928214571Sdim 2929214571Sdim/* We may add an extra PT_LOAD segment for .toe. We also need extra 2930214571Sdim segments for overlays. */ 2931214571Sdim 2932214571Sdimstatic int 2933214571Sdimspu_elf_additional_program_headers (bfd *abfd, struct bfd_link_info *info) 2934214571Sdim{ 2935214571Sdim struct spu_link_hash_table *htab = spu_hash_table (info); 2936214571Sdim int extra = htab->num_overlays; 2937214571Sdim asection *sec; 2938214571Sdim 2939214571Sdim if (extra) 2940214571Sdim ++extra; 2941214571Sdim 2942214571Sdim sec = bfd_get_section_by_name (abfd, ".toe"); 2943214571Sdim if (sec != NULL && (sec->flags & SEC_LOAD) != 0) 2944214571Sdim ++extra; 2945214571Sdim 2946214571Sdim return extra; 2947214571Sdim} 2948214571Sdim 2949214571Sdim/* Remove .toe section from other PT_LOAD segments and put it in 2950214571Sdim a segment of its own. Put overlays in separate segments too. */ 2951214571Sdim 2952214571Sdimstatic bfd_boolean 2953214571Sdimspu_elf_modify_segment_map (bfd *abfd, struct bfd_link_info *info) 2954214571Sdim{ 2955214571Sdim asection *toe, *s; 2956214571Sdim struct elf_segment_map *m; 2957214571Sdim unsigned int i; 2958214571Sdim 2959214571Sdim if (info == NULL) 2960214571Sdim return TRUE; 2961214571Sdim 2962214571Sdim toe = bfd_get_section_by_name (abfd, ".toe"); 2963214571Sdim for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) 2964214571Sdim if (m->p_type == PT_LOAD && m->count > 1) 2965214571Sdim for (i = 0; i < m->count; i++) 2966214571Sdim if ((s = m->sections[i]) == toe 2967214571Sdim || spu_elf_section_data (s)->ovl_index != 0) 2968214571Sdim { 2969214571Sdim struct elf_segment_map *m2; 2970214571Sdim bfd_vma amt; 2971214571Sdim 2972214571Sdim if (i + 1 < m->count) 2973214571Sdim { 2974214571Sdim amt = sizeof (struct elf_segment_map); 2975214571Sdim amt += (m->count - (i + 2)) * sizeof (m->sections[0]); 2976214571Sdim m2 = bfd_zalloc (abfd, amt); 2977214571Sdim if (m2 == NULL) 2978214571Sdim return FALSE; 2979214571Sdim m2->count = m->count - (i + 1); 2980214571Sdim memcpy (m2->sections, m->sections + i + 1, 2981214571Sdim m2->count * sizeof (m->sections[0])); 2982214571Sdim m2->p_type = PT_LOAD; 2983214571Sdim m2->next = m->next; 2984214571Sdim m->next = m2; 2985214571Sdim } 2986214571Sdim m->count = 1; 2987214571Sdim if (i != 0) 2988214571Sdim { 2989214571Sdim m->count = i; 2990214571Sdim amt = sizeof (struct elf_segment_map); 2991214571Sdim m2 = bfd_zalloc (abfd, amt); 2992214571Sdim if (m2 == NULL) 2993214571Sdim return FALSE; 2994214571Sdim m2->p_type = PT_LOAD; 2995214571Sdim m2->count = 1; 2996214571Sdim m2->sections[0] = s; 2997214571Sdim m2->next = m->next; 2998214571Sdim m->next = m2; 2999214571Sdim } 3000214571Sdim break; 3001214571Sdim } 3002214571Sdim 3003214571Sdim return TRUE; 3004214571Sdim} 3005214571Sdim 3006214571Sdim/* Check that all loadable section VMAs lie in the range 3007214571Sdim LO .. HI inclusive. */ 3008214571Sdim 3009214571Sdimasection * 3010214571Sdimspu_elf_check_vma (bfd *abfd, bfd_vma lo, bfd_vma hi) 3011214571Sdim{ 3012214571Sdim struct elf_segment_map *m; 3013214571Sdim unsigned int i; 3014214571Sdim 3015214571Sdim for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) 3016214571Sdim if (m->p_type == PT_LOAD) 3017214571Sdim for (i = 0; i < m->count; i++) 3018214571Sdim if (m->sections[i]->size != 0 3019214571Sdim && (m->sections[i]->vma < lo 3020214571Sdim || m->sections[i]->vma > hi 3021214571Sdim || m->sections[i]->vma + m->sections[i]->size - 1 > hi)) 3022214571Sdim return m->sections[i]; 3023214571Sdim 3024214571Sdim return NULL; 3025214571Sdim} 3026214571Sdim 3027214571Sdim/* Tweak the section type of .note.spu_name. */ 3028214571Sdim 3029214571Sdimstatic bfd_boolean 3030214571Sdimspu_elf_fake_sections (bfd *obfd ATTRIBUTE_UNUSED, 3031214571Sdim Elf_Internal_Shdr *hdr, 3032214571Sdim asection *sec) 3033214571Sdim{ 3034214571Sdim if (strcmp (sec->name, SPU_PTNOTE_SPUNAME) == 0) 3035214571Sdim hdr->sh_type = SHT_NOTE; 3036214571Sdim return TRUE; 3037214571Sdim} 3038214571Sdim 3039214571Sdim/* Tweak phdrs before writing them out. */ 3040214571Sdim 3041214571Sdimstatic int 3042214571Sdimspu_elf_modify_program_headers (bfd *abfd, struct bfd_link_info *info) 3043214571Sdim{ 3044214571Sdim const struct elf_backend_data *bed; 3045214571Sdim struct elf_obj_tdata *tdata; 3046214571Sdim Elf_Internal_Phdr *phdr, *last; 3047214571Sdim struct spu_link_hash_table *htab; 3048214571Sdim unsigned int count; 3049214571Sdim unsigned int i; 3050214571Sdim 3051214571Sdim if (info == NULL) 3052214571Sdim return TRUE; 3053214571Sdim 3054214571Sdim bed = get_elf_backend_data (abfd); 3055214571Sdim tdata = elf_tdata (abfd); 3056214571Sdim phdr = tdata->phdr; 3057214571Sdim count = tdata->program_header_size / bed->s->sizeof_phdr; 3058214571Sdim htab = spu_hash_table (info); 3059214571Sdim if (htab->num_overlays != 0) 3060214571Sdim { 3061214571Sdim struct elf_segment_map *m; 3062214571Sdim unsigned int o; 3063214571Sdim 3064214571Sdim for (i = 0, m = elf_tdata (abfd)->segment_map; m; ++i, m = m->next) 3065214571Sdim if (m->count != 0 3066214571Sdim && (o = spu_elf_section_data (m->sections[0])->ovl_index) != 0) 3067214571Sdim { 3068214571Sdim /* Mark this as an overlay header. */ 3069214571Sdim phdr[i].p_flags |= PF_OVERLAY; 3070214571Sdim 3071214571Sdim if (htab->ovtab != NULL && htab->ovtab->size != 0) 3072214571Sdim { 3073214571Sdim bfd_byte *p = htab->ovtab->contents; 3074214571Sdim unsigned int off = (o - 1) * 16 + 8; 3075214571Sdim 3076214571Sdim /* Write file_off into _ovly_table. */ 3077214571Sdim bfd_put_32 (htab->ovtab->owner, phdr[i].p_offset, p + off); 3078214571Sdim } 3079214571Sdim } 3080214571Sdim } 3081214571Sdim 3082214571Sdim /* Round up p_filesz and p_memsz of PT_LOAD segments to multiples 3083214571Sdim of 16. This should always be possible when using the standard 3084214571Sdim linker scripts, but don't create overlapping segments if 3085214571Sdim someone is playing games with linker scripts. */ 3086214571Sdim last = NULL; 3087214571Sdim for (i = count; i-- != 0; ) 3088214571Sdim if (phdr[i].p_type == PT_LOAD) 3089214571Sdim { 3090214571Sdim unsigned adjust; 3091214571Sdim 3092214571Sdim adjust = -phdr[i].p_filesz & 15; 3093214571Sdim if (adjust != 0 3094214571Sdim && last != NULL 3095214571Sdim && phdr[i].p_offset + phdr[i].p_filesz > last->p_offset - adjust) 3096214571Sdim break; 3097214571Sdim 3098214571Sdim adjust = -phdr[i].p_memsz & 15; 3099214571Sdim if (adjust != 0 3100214571Sdim && last != NULL 3101214571Sdim && phdr[i].p_filesz != 0 3102214571Sdim && phdr[i].p_vaddr + phdr[i].p_memsz > last->p_vaddr - adjust 3103214571Sdim && phdr[i].p_vaddr + phdr[i].p_memsz <= last->p_vaddr) 3104214571Sdim break; 3105214571Sdim 3106214571Sdim if (phdr[i].p_filesz != 0) 3107214571Sdim last = &phdr[i]; 3108214571Sdim } 3109214571Sdim 3110214571Sdim if (i == (unsigned int) -1) 3111214571Sdim for (i = count; i-- != 0; ) 3112214571Sdim if (phdr[i].p_type == PT_LOAD) 3113214571Sdim { 3114214571Sdim unsigned adjust; 3115214571Sdim 3116214571Sdim adjust = -phdr[i].p_filesz & 15; 3117214571Sdim phdr[i].p_filesz += adjust; 3118214571Sdim 3119214571Sdim adjust = -phdr[i].p_memsz & 15; 3120214571Sdim phdr[i].p_memsz += adjust; 3121214571Sdim } 3122214571Sdim 3123214571Sdim return TRUE; 3124214571Sdim} 3125214571Sdim 3126214571Sdim#define TARGET_BIG_SYM bfd_elf32_spu_vec 3127214571Sdim#define TARGET_BIG_NAME "elf32-spu" 3128214571Sdim#define ELF_ARCH bfd_arch_spu 3129214571Sdim#define ELF_MACHINE_CODE EM_SPU 3130214571Sdim/* This matches the alignment need for DMA. */ 3131214571Sdim#define ELF_MAXPAGESIZE 0x80 3132214571Sdim#define elf_backend_rela_normal 1 3133214571Sdim#define elf_backend_can_gc_sections 1 3134214571Sdim 3135214571Sdim#define bfd_elf32_bfd_reloc_type_lookup spu_elf_reloc_type_lookup 3136214571Sdim#define bfd_elf32_bfd_reloc_name_lookup spu_elf_reloc_name_lookup 3137214571Sdim#define elf_info_to_howto spu_elf_info_to_howto 3138214571Sdim#define elf_backend_count_relocs spu_elf_count_relocs 3139214571Sdim#define elf_backend_relocate_section spu_elf_relocate_section 3140214571Sdim#define elf_backend_symbol_processing spu_elf_backend_symbol_processing 3141214571Sdim#define elf_backend_link_output_symbol_hook spu_elf_output_symbol_hook 3142214571Sdim#define bfd_elf32_new_section_hook spu_elf_new_section_hook 3143214571Sdim#define bfd_elf32_bfd_link_hash_table_create spu_elf_link_hash_table_create 3144214571Sdim#define bfd_elf32_bfd_link_hash_table_free spu_elf_link_hash_table_free 3145214571Sdim 3146214571Sdim#define elf_backend_additional_program_headers spu_elf_additional_program_headers 3147214571Sdim#define elf_backend_modify_segment_map spu_elf_modify_segment_map 3148214571Sdim#define elf_backend_modify_program_headers spu_elf_modify_program_headers 3149214571Sdim#define elf_backend_post_process_headers spu_elf_post_process_headers 3150214571Sdim#define elf_backend_fake_sections spu_elf_fake_sections 3151214571Sdim#define elf_backend_special_sections spu_elf_special_sections 3152214571Sdim#define bfd_elf32_bfd_final_link spu_elf_final_link 3153214571Sdim 3154214571Sdim#include "elf32-target.h" 3155