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