bfd/
authorAlan Modra <amodra@gmail.com>
Wed, 10 Dec 2008 06:32:52 +0000 (06:32 +0000)
committerAlan Modra <amodra@gmail.com>
Wed, 10 Dec 2008 06:32:52 +0000 (06:32 +0000)
* elf32-spu.g (struct spu_elf_params, enum _ovly_flavour): New.
(spu_elf_setup): Declare.
(spu_elf_create_sections, spu_elf_size_stubs): Update prototype.
(spu_elf_build_stubs, spu_elf_check_vma): Likewise.
* elf32-spu.c (struct spu_link_hash_table): Add "params". Remove
various other fields now in "params".  Adjust code throughout.
(struct call_info, struct function_info): Move earlier in file.
(struct spu_elf_stack_info): Likewise.
(spu_elf_setup): New function.
(spu_elf_create_sections): Remove args other than "info".
(spu_elf_size_stubs, spu_elf_build_stubs, spu_elf_check_vma): Likewise.
(maybe_needs_stubs): Remove "output_bfd" arg.  Adjust all calls.
(interesting_section): Similarly with "obfd" arg.
(needs_ovl_stub): Adjust output_section test.
(allocate_spuear_stubs): Likewise.
(OVL_STUB_SIZE): Don't define.
(ovl_stub_size): New function, use in place of OVL_STUB_SIZE.
(build_stub): Test params->ovly_flavour rather than OVL_STUB_SIZE.
(spu_elf_auto_overlay): Remove args other than "info".  Make use
of size returned from spu_elf_load_ovl_mgr.
(spu_elf_stack_analysis): Remove args other than "info".
(spu_elf_relocate_section): Tidy setting of "ea".
ld/
* emultempl/spuelf.em (params): New var, used instead of various others.
Adjust use throughout file.
(spu_after_open): Call spu_elf_setup.
(spu_place_special_section): Tidy.
(spu_elf_load_ovl_mgr): Return total size of sections loaded.  Move
code setting overlay section alignment to..
(spu_before_allocation): ..here.

bfd/ChangeLog
bfd/elf32-spu.c
bfd/elf32-spu.h
ld/ChangeLog
ld/emultempl/spuelf.em

index 17f1fb4d7b9615b33f9cae2f06791133b2388e27..ebb847b7016ac4c92a4c638b0fc3f4ce35885efd 100644 (file)
@@ -1,3 +1,28 @@
+2008-12-10  Alan Modra  <amodra@bigpond.net.au>
+
+       * elf32-spu.g (struct spu_elf_params, enum _ovly_flavour): New.
+       (spu_elf_setup): Declare.
+       (spu_elf_create_sections, spu_elf_size_stubs): Update prototype.
+       (spu_elf_build_stubs, spu_elf_check_vma): Likewise.
+       * elf32-spu.c (struct spu_link_hash_table): Add "params". Remove
+       various other fields now in "params".  Adjust code throughout.
+       (struct call_info, struct function_info): Move earlier in file.
+       (struct spu_elf_stack_info): Likewise.
+       (spu_elf_setup): New function.
+       (spu_elf_create_sections): Remove args other than "info".
+       (spu_elf_size_stubs, spu_elf_build_stubs, spu_elf_check_vma): Likewise.
+       (maybe_needs_stubs): Remove "output_bfd" arg.  Adjust all calls.
+       (interesting_section): Similarly with "obfd" arg.
+       (needs_ovl_stub): Adjust output_section test.
+       (allocate_spuear_stubs): Likewise.
+       (OVL_STUB_SIZE): Don't define.
+       (ovl_stub_size): New function, use in place of OVL_STUB_SIZE.
+       (build_stub): Test params->ovly_flavour rather than OVL_STUB_SIZE.
+       (spu_elf_auto_overlay): Remove args other than "info".  Make use
+       of size returned from spu_elf_load_ovl_mgr.
+       (spu_elf_stack_analysis): Remove args other than "info".
+       (spu_elf_relocate_section): Tidy setting of "ea".
+
 2008-12-10  Alan Modra  <amodra@bigpond.net.au>
 
        * elf32-spu.c (find_function_stack_adjust): Don't limit number
index b2ac17e1f1047654b8f3fa233ee49a2693863c76..3908ecd125c44fa2e76dbfbbbfc9333d9779ea50 100644 (file)
@@ -297,6 +297,8 @@ struct spu_link_hash_table
 {
   struct elf_link_hash_table elf;
 
+  struct spu_elf_params *params;
+
   /* Shortcuts to overlay sections.  */
   asection *ovtab;
   asection *toe;
@@ -333,34 +335,8 @@ struct spu_link_hash_table
   /* Count of overlay stubs needed in non-overlay area.  */
   unsigned int non_ovly_stub;
 
-  /* Stash various callbacks for --auto-overlay.  */
-  void (*spu_elf_load_ovl_mgr) (void);
-  FILE *(*spu_elf_open_overlay_script) (void);
-  void (*spu_elf_relink) (void);
-
-  /* Bit 0 set if --auto-overlay.
-     Bit 1 set if --auto-relink.
-     Bit 2 set if --overlay-rodata.  */
-  unsigned int auto_overlay : 3;
-#define AUTO_OVERLAY 1
-#define AUTO_RELINK 2
-#define OVERLAY_RODATA 4
-
-  /* Set if we should emit symbols for stubs.  */
-  unsigned int emit_stub_syms:1;
-
-  /* Set if we want stubs on calls out of overlay regions to
-     non-overlay regions.  */
-  unsigned int non_overlay_stubs : 1;
-
   /* Set on error.  */
   unsigned int stub_err : 1;
-
-  /* Set if stack size analysis should be done.  */
-  unsigned int stack_analysis : 1;
-
-  /* Set if __stack_* syms will be emitted.  */
-  unsigned int emit_stack_syms : 1;
 };
 
 /* Hijack the generic got fields for overlay stub accounting.  */
@@ -376,6 +352,69 @@ struct got_entry
 #define spu_hash_table(p) \
   ((struct spu_link_hash_table *) ((p)->hash))
 
+struct call_info
+{
+  struct function_info *fun;
+  struct call_info *next;
+  unsigned int count;
+  unsigned int max_depth;
+  unsigned int is_tail : 1;
+  unsigned int is_pasted : 1;
+};
+
+struct function_info
+{
+  /* List of functions called.  Also branches to hot/cold part of
+     function.  */
+  struct call_info *call_list;
+  /* For hot/cold part of function, point to owner.  */
+  struct function_info *start;
+  /* Symbol at start of function.  */
+  union {
+    Elf_Internal_Sym *sym;
+    struct elf_link_hash_entry *h;
+  } u;
+  /* Function section.  */
+  asection *sec;
+  asection *rodata;
+  /* Where last called from, and number of sections called from.  */
+  asection *last_caller;
+  unsigned int call_count;
+  /* Address range of (this part of) function.  */
+  bfd_vma lo, hi;
+  /* Stack usage.  */
+  int stack;
+  /* Distance from root of call tree.  Tail and hot/cold branches
+     count as one deeper.  We aren't counting stack frames here.  */
+  unsigned int depth;
+  /* Set if global symbol.  */
+  unsigned int global : 1;
+  /* Set if known to be start of function (as distinct from a hunk
+     in hot/cold section.  */
+  unsigned int is_func : 1;
+  /* Set if not a root node.  */
+  unsigned int non_root : 1;
+  /* Flags used during call tree traversal.  It's cheaper to replicate
+     the visit flags than have one which needs clearing after a traversal.  */
+  unsigned int visit1 : 1;
+  unsigned int visit2 : 1;
+  unsigned int marking : 1;
+  unsigned int visit3 : 1;
+  unsigned int visit4 : 1;
+  unsigned int visit5 : 1;
+  unsigned int visit6 : 1;
+  unsigned int visit7 : 1;
+};
+
+struct spu_elf_stack_info
+{
+  int num_fun;
+  int max_fun;
+  /* Variable size array describing functions, one per contiguous
+     address range belonging to a function.  */
+  struct function_info fun[1];
+};
+
 /* Create a spu ELF linker hash table.  */
 
 static struct bfd_link_hash_table *
@@ -405,6 +444,13 @@ spu_elf_link_hash_table_create (bfd *abfd)
   return &htab->elf.root;
 }
 
+void
+spu_elf_setup (struct bfd_link_info *info, struct spu_elf_params *params)
+{
+  struct spu_link_hash_table *htab = spu_hash_table (info);
+  htab->params = params;
+}
+
 /* Find the symbol for the given R_SYMNDX in IBFD and set *HP and *SYMP
    to (hash, NULL) for global symbols, and (NULL, sym) for locals.  Set
    *SYMSECP to the symbol's section.  *LOCSYMSP caches local syms.  */
@@ -479,16 +525,9 @@ get_sym_h (struct elf_link_hash_entry **hp,
    that the linker maps the sections to the right place in the output.  */
 
 bfd_boolean
-spu_elf_create_sections (struct bfd_link_info *info,
-                        int stack_analysis,
-                        int emit_stack_syms)
+spu_elf_create_sections (struct bfd_link_info *info)
 {
   bfd *ibfd;
-  struct spu_link_hash_table *htab = spu_hash_table (info);
-
-  /* Stash some options away where we can get at them later.  */
-  htab->stack_analysis = stack_analysis;
-  htab->emit_stack_syms = emit_stack_syms;
 
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
     if (bfd_get_section_by_name (ibfd, SPU_PTNOTE_SPUNAME) != NULL)
@@ -626,13 +665,6 @@ spu_elf_find_overlays (struct bfd_link_info *info)
   return ovl_index != 0;
 }
 
-/* Support two sizes of overlay stubs, a slower more compact stub of two
-   intructions, and a faster stub of four instructions.  */
-#ifndef OVL_STUB_SIZE
-/* Default to faster.  */
-#define OVL_STUB_SIZE 16
-/* #define OVL_STUB_SIZE 8 */
-#endif
 #define BRSL   0x33000000
 #define BR     0x32000000
 #define NOP    0x40200000
@@ -684,15 +716,14 @@ is_hint (const unsigned char *insn)
 /* True if INPUT_SECTION might need overlay stubs.  */
 
 static bfd_boolean
-maybe_needs_stubs (asection *input_section, bfd *output_bfd)
+maybe_needs_stubs (asection *input_section)
 {
   /* No stubs for debug sections and suchlike.  */
   if ((input_section->flags & SEC_ALLOC) == 0)
     return FALSE;
 
   /* No stubs for link-once sections that will be discarded.  */
-  if (input_section->output_section == NULL
-      || input_section->output_section->owner != output_bfd)
+  if (input_section->output_section == bfd_abs_section_ptr)
     return FALSE;
 
   /* Don't create stubs for .eh_frame references.  */
@@ -729,8 +760,7 @@ needs_ovl_stub (struct elf_link_hash_entry *h,
   enum _stub_type ret = no_stub;
 
   if (sym_sec == NULL
-      || sym_sec->output_section == NULL
-      || sym_sec->output_section->owner != info->output_bfd
+      || sym_sec->output_section == bfd_abs_section_ptr
       || spu_elf_section_data (sym_sec->output_section) == NULL)
     return ret;
 
@@ -750,7 +780,7 @@ needs_ovl_stub (struct elf_link_hash_entry *h,
 
   /* Usually, symbols in non-overlay sections don't need stubs.  */
   if (spu_elf_section_data (sym_sec->output_section)->u.o.ovl_index == 0
-      && !htab->non_overlay_stubs)
+      && !htab->params->non_overlay_stubs)
     return ret;
 
   if (h != NULL)
@@ -911,6 +941,15 @@ count_stub (struct spu_link_hash_table *htab,
   return TRUE;
 }
 
+/* Support two sizes of overlay stubs, a slower more compact stub of two
+   intructions, and a faster stub of four instructions.  */
+
+static unsigned int
+ovl_stub_size (enum _ovly_flavour ovly_flavour)
+{
+  return 8 << ovly_flavour;
+}
+
 /* Two instruction overlay stubs look like:
 
    brsl $75,__ovly_load
@@ -936,10 +975,10 @@ build_stub (struct spu_link_hash_table *htab,
            bfd_vma dest,
            asection *dest_sec)
 {
-  unsigned int ovl;
+  unsigned int ovl, dest_ovl;
   struct got_entry *g, **head;
   asection *sec;
-  bfd_vma addend, val, from, to;
+  bfd_vma addend, from, to;
 
   ovl = 0;
   if (stub_type != nonovl_stub)
@@ -973,42 +1012,40 @@ build_stub (struct spu_link_hash_table *htab,
   to = (htab->ovly_load->root.u.def.value
        + htab->ovly_load->root.u.def.section->output_offset
        + htab->ovly_load->root.u.def.section->output_section->vma);
-  val = to - from;
-  if (OVL_STUB_SIZE == 16)
-    val -= 12;
-  if (((dest | to | from) & 3) != 0
-      || val + 0x40000 >= 0x80000)
+
+  if (((dest | to | from) & 3) != 0)
     {
       htab->stub_err = 1;
       return FALSE;
     }
-  ovl = spu_elf_section_data (dest_sec->output_section)->u.o.ovl_index;
+  dest_ovl = spu_elf_section_data (dest_sec->output_section)->u.o.ovl_index;
 
-  if (OVL_STUB_SIZE == 16)
+  switch (htab->params->ovly_flavour)
     {
-      bfd_put_32 (sec->owner, ILA + ((ovl << 7) & 0x01ffff80) + 78,
+    case ovly_normal:
+      bfd_put_32 (sec->owner, ILA + ((dest_ovl << 7) & 0x01ffff80) + 78,
                  sec->contents + sec->size);
       bfd_put_32 (sec->owner, LNOP,
                  sec->contents + sec->size + 4);
       bfd_put_32 (sec->owner, ILA + ((dest << 7) & 0x01ffff80) + 79,
                  sec->contents + sec->size + 8);
-      bfd_put_32 (sec->owner, BR + ((val << 5) & 0x007fff80),
+      bfd_put_32 (sec->owner, BR + (((to - (from + 12)) << 5) & 0x007fff80),
                  sec->contents + sec->size + 12);
-    }
-  else if (OVL_STUB_SIZE == 8)
-    {
-      bfd_put_32 (sec->owner, BRSL + ((val << 5) & 0x007fff80) + 75,
-                 sec->contents + sec->size);
+      break;
 
-      val = (dest & 0x3ffff) | (ovl << 18);
-      bfd_put_32 (sec->owner, val,
+    case ovly_compact:
+      bfd_put_32 (sec->owner, BRSL + (((to - from) << 5) & 0x007fff80) + 75,
+                 sec->contents + sec->size);
+      bfd_put_32 (sec->owner, (dest & 0x3ffff) | (dest_ovl << 18),
                  sec->contents + sec->size + 4);
+      break;
+
+    default:
+      abort ();
     }
-  else
-    abort ();
-  sec->size += OVL_STUB_SIZE;
+  sec->size += ovl_stub_size (htab->params->ovly_flavour);
 
-  if (htab->emit_stub_syms)
+  if (htab->params->emit_stub_syms)
     {
       size_t len;
       char *name;
@@ -1046,8 +1083,8 @@ build_stub (struct spu_link_hash_table *htab,
        {
          h->root.type = bfd_link_hash_defined;
          h->root.u.def.section = sec;
-         h->root.u.def.value = sec->size - OVL_STUB_SIZE;
-         h->size = OVL_STUB_SIZE;
+         h->size = ovl_stub_size (htab->params->ovly_flavour);
+         h->root.u.def.value = sec->size - h->size;
          h->type = STT_FUNC;
          h->ref_regular = 1;
          h->def_regular = 1;
@@ -1077,11 +1114,10 @@ allocate_spuear_stubs (struct elf_link_hash_entry *h, void *inf)
       && h->def_regular
       && strncmp (h->root.root.string, "_SPUEAR_", 8) == 0
       && (sym_sec = h->root.u.def.section) != NULL
-      && sym_sec->output_section != NULL
-      && sym_sec->output_section->owner == info->output_bfd
+      && sym_sec->output_section != bfd_abs_section_ptr
       && spu_elf_section_data (sym_sec->output_section) != NULL
       && (spu_elf_section_data (sym_sec->output_section)->u.o.ovl_index != 0
-         || htab->non_overlay_stubs))
+         || htab->params->non_overlay_stubs))
     {
       return count_stub (htab, NULL, NULL, nonovl_stub, h, NULL);
     }
@@ -1103,11 +1139,10 @@ build_spuear_stubs (struct elf_link_hash_entry *h, void *inf)
       && h->def_regular
       && strncmp (h->root.root.string, "_SPUEAR_", 8) == 0
       && (sym_sec = h->root.u.def.section) != NULL
-      && sym_sec->output_section != NULL
-      && sym_sec->output_section->owner == info->output_bfd
+      && sym_sec->output_section != bfd_abs_section_ptr
       && spu_elf_section_data (sym_sec->output_section) != NULL
       && (spu_elf_section_data (sym_sec->output_section)->u.o.ovl_index != 0
-         || htab->non_overlay_stubs))
+         || htab->params->non_overlay_stubs))
     {
       return build_stub (htab, NULL, NULL, nonovl_stub, h, NULL,
                         h->root.u.def.value, sym_sec);
@@ -1149,7 +1184,7 @@ process_stubs (struct bfd_link_info *info, bfd_boolean build)
              || isec->reloc_count == 0)
            continue;
 
-         if (!maybe_needs_stubs (isec, info->output_bfd))
+         if (!maybe_needs_stubs (isec))
            continue;
 
          /* Get the relocs.  */
@@ -1248,22 +1283,19 @@ process_stubs (struct bfd_link_info *info, bfd_boolean build)
 /* Allocate space for overlay call and return stubs.  */
 
 int
-spu_elf_size_stubs (struct bfd_link_info *info,
-                   void (*place_spu_section) (asection *, asection *,
-                                              const char *),
-                   int non_overlay_stubs)
+spu_elf_size_stubs (struct bfd_link_info *info)
 {
-  struct spu_link_hash_table *htab = spu_hash_table (info);
+  struct spu_link_hash_table *htab;
   bfd *ibfd;
   bfd_size_type amt;
   flagword flags;
   unsigned int i;
   asection *stub;
 
-  htab->non_overlay_stubs = non_overlay_stubs;
   if (!process_stubs (info, FALSE))
     return 0;
 
+  htab = spu_hash_table (info);
   elf_link_hash_traverse (&htab->elf, allocate_spuear_stubs, info);
   if (htab->stub_err)
     return 0;
@@ -1282,10 +1314,11 @@ spu_elf_size_stubs (struct bfd_link_info *info,
   stub = bfd_make_section_anyway_with_flags (ibfd, ".stub", flags);
   htab->stub_sec[0] = stub;
   if (stub == NULL
-      || !bfd_set_section_alignment (ibfd, stub, 3 + (OVL_STUB_SIZE > 8)))
+      || !bfd_set_section_alignment (ibfd, stub,
+                                    htab->params->ovly_flavour + 3))
     return 0;
-  stub->size = htab->stub_count[0] * OVL_STUB_SIZE;
-  (*place_spu_section) (stub, NULL, ".text");
+  stub->size = htab->stub_count[0] * ovl_stub_size (htab->params->ovly_flavour);
+  (*htab->params->place_spu_section) (stub, NULL, ".text");
 
   for (i = 0; i < htab->num_overlays; ++i)
     {
@@ -1294,10 +1327,11 @@ spu_elf_size_stubs (struct bfd_link_info *info,
       stub = bfd_make_section_anyway_with_flags (ibfd, ".stub", flags);
       htab->stub_sec[ovl] = stub;
       if (stub == NULL
-         || !bfd_set_section_alignment (ibfd, stub, 3 + (OVL_STUB_SIZE > 8)))
+         || !bfd_set_section_alignment (ibfd, stub,
+                                        htab->params->ovly_flavour + 3))
        return 0;
-      stub->size = htab->stub_count[ovl] * OVL_STUB_SIZE;
-      (*place_spu_section) (stub, osec, NULL);
+      stub->size = htab->stub_count[ovl] * ovl_stub_size (htab->params->ovly_flavour);
+      (*htab->params->place_spu_section) (stub, osec, NULL);
     }
 
  /* htab->ovtab consists of two arrays.
@@ -1321,14 +1355,14 @@ spu_elf_size_stubs (struct bfd_link_info *info,
     return 0;
 
   htab->ovtab->size = htab->num_overlays * 16 + 16 + htab->num_buf * 4;
-  (*place_spu_section) (htab->ovtab, NULL, ".data");
+  (*htab->params->place_spu_section) (htab->ovtab, NULL, ".data");
 
   htab->toe = bfd_make_section_anyway_with_flags (ibfd, ".toe", SEC_ALLOC);
   if (htab->toe == NULL
       || !bfd_set_section_alignment (ibfd, htab->toe, 4))
     return 0;
   htab->toe->size = 16;
-  (*place_spu_section) (htab->toe, NULL, ".toe");
+  (*htab->params->place_spu_section) (htab->toe, NULL, ".toe");
 
   return 2;
 }
@@ -1423,7 +1457,7 @@ define_ovtab_symbol (struct spu_link_hash_table *htab, const char *name)
 /* Fill in all stubs and the overlay tables.  */
 
 bfd_boolean
-spu_elf_build_stubs (struct bfd_link_info *info, int emit_syms)
+spu_elf_build_stubs (struct bfd_link_info *info)
 {
   struct spu_link_hash_table *htab = spu_hash_table (info);
   struct elf_link_hash_entry *h;
@@ -1432,7 +1466,6 @@ spu_elf_build_stubs (struct bfd_link_info *info, int emit_syms)
   bfd *obfd;
   unsigned int i;
 
-  htab->emit_stub_syms = emit_syms;
   if (htab->stub_count == NULL)
     return TRUE;
 
@@ -1552,31 +1585,16 @@ spu_elf_build_stubs (struct bfd_link_info *info, int emit_syms)
    LO .. HI inclusive, and stash some parameters for --auto-overlay.  */
 
 asection *
-spu_elf_check_vma (struct bfd_link_info *info,
-                  int auto_overlay,
-                  unsigned int lo,
-                  unsigned int hi,
-                  unsigned int overlay_fixed,
-                  unsigned int reserved,
-                  int extra_stack_space,
-                  void (*spu_elf_load_ovl_mgr) (void),
-                  FILE *(*spu_elf_open_overlay_script) (void),
-                  void (*spu_elf_relink) (void))
+spu_elf_check_vma (struct bfd_link_info *info)
 {
   struct elf_segment_map *m;
   unsigned int i;
   struct spu_link_hash_table *htab = spu_hash_table (info);
   bfd *abfd = info->output_bfd;
+  bfd_vma hi = htab->params->local_store_hi;
+  bfd_vma lo = htab->params->local_store_lo;
 
-  if (auto_overlay & AUTO_OVERLAY)
-    htab->auto_overlay = auto_overlay;
   htab->local_store = hi + 1 - lo;
-  htab->overlay_fixed = overlay_fixed;
-  htab->reserved = reserved;
-  htab->extra_stack_space = extra_stack_space;
-  htab->spu_elf_load_ovl_mgr = spu_elf_load_ovl_mgr;
-  htab->spu_elf_open_overlay_script = spu_elf_open_overlay_script;
-  htab->spu_elf_relink = spu_elf_relink;
 
   for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
     if (m->p_type == PT_LOAD)
@@ -1588,7 +1606,7 @@ spu_elf_check_vma (struct bfd_link_info *info,
          return m->sections[i];
 
   /* No need for overlays if it all fits.  */
-  htab->auto_overlay = 0;
+  htab->params->auto_overlay = 0;
   return NULL;
 }
 
@@ -1738,69 +1756,6 @@ sort_syms (const void *a, const void *b)
   return *s1 < *s2 ? -1 : 1;
 }
 
-struct call_info
-{
-  struct function_info *fun;
-  struct call_info *next;
-  unsigned int count;
-  unsigned int max_depth;
-  unsigned int is_tail : 1;
-  unsigned int is_pasted : 1;
-};
-
-struct function_info
-{
-  /* List of functions called.  Also branches to hot/cold part of
-     function.  */
-  struct call_info *call_list;
-  /* For hot/cold part of function, point to owner.  */
-  struct function_info *start;
-  /* Symbol at start of function.  */
-  union {
-    Elf_Internal_Sym *sym;
-    struct elf_link_hash_entry *h;
-  } u;
-  /* Function section.  */
-  asection *sec;
-  asection *rodata;
-  /* Where last called from, and number of sections called from.  */
-  asection *last_caller;
-  unsigned int call_count;
-  /* Address range of (this part of) function.  */
-  bfd_vma lo, hi;
-  /* Stack usage.  */
-  int stack;
-  /* Distance from root of call tree.  Tail and hot/cold branches
-     count as one deeper.  We aren't counting stack frames here.  */
-  unsigned int depth;
-  /* Set if global symbol.  */
-  unsigned int global : 1;
-  /* Set if known to be start of function (as distinct from a hunk
-     in hot/cold section.  */
-  unsigned int is_func : 1;
-  /* Set if not a root node.  */
-  unsigned int non_root : 1;
-  /* Flags used during call tree traversal.  It's cheaper to replicate
-     the visit flags than have one which needs clearing after a traversal.  */
-  unsigned int visit1 : 1;
-  unsigned int visit2 : 1;
-  unsigned int marking : 1;
-  unsigned int visit3 : 1;
-  unsigned int visit4 : 1;
-  unsigned int visit5 : 1;
-  unsigned int visit6 : 1;
-  unsigned int visit7 : 1;
-};
-
-struct spu_elf_stack_info
-{
-  int num_fun;
-  int max_fun;
-  /* Variable size array describing functions, one per contiguous
-     address range belonging to a function.  */
-  struct function_info fun[1];
-};
-
 /* Allocate a struct spu_elf_stack_info with MAX_FUN struct function_info
    entries for section SEC.  */
 
@@ -2102,10 +2057,9 @@ copy_callee (struct function_info *caller, const struct call_info *call)
    overlay stub sections.  */
 
 static bfd_boolean
-interesting_section (asection *s, bfd *obfd)
+interesting_section (asection *s)
 {
-  return (s->output_section != NULL
-         && s->output_section->owner == obfd
+  return (s->output_section != bfd_abs_section_ptr
          && ((s->flags & (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_IN_MEMORY))
              == (SEC_ALLOC | SEC_LOAD | SEC_CODE))
          && s->size != 0);
@@ -2127,7 +2081,7 @@ mark_functions_via_relocs (asection *sec,
   void *psyms;
   static bfd_boolean warned;
 
-  if (!interesting_section (sec, info->output_bfd)
+  if (!interesting_section (sec)
       || sec->reloc_count == 0)
     return TRUE;
 
@@ -2158,7 +2112,7 @@ mark_functions_via_relocs (asection *sec,
          && r_type != R_SPU_ADDR16)
        {
          reject = TRUE;
-         if (!(call_tree && spu_hash_table (info)->auto_overlay))
+         if (!(call_tree && spu_hash_table (info)->params->auto_overlay))
            continue;
        }
 
@@ -2167,8 +2121,7 @@ mark_functions_via_relocs (asection *sec,
        return FALSE;
 
       if (sym_sec == NULL
-         || sym_sec->output_section == NULL
-         || sym_sec->output_section->owner != info->output_bfd)
+         || sym_sec->output_section == bfd_abs_section_ptr)
        continue;
 
       is_call = FALSE;
@@ -2198,7 +2151,7 @@ mark_functions_via_relocs (asection *sec,
          else
            {
              reject = TRUE;
-             if (!(call_tree && spu_hash_table (info)->auto_overlay)
+             if (!(call_tree && spu_hash_table (info)->params->auto_overlay)
                  || is_hint (insn))
                continue;
            }
@@ -2409,7 +2362,7 @@ discover_functions (struct bfd_link_info *info)
        {
          if (!gaps)
            for (sec = ibfd->sections; sec != NULL && !gaps; sec = sec->next)
-             if (interesting_section (sec, info->output_bfd))
+             if (interesting_section (sec))
                {
                  gaps = TRUE;
                  break;
@@ -2447,7 +2400,7 @@ discover_functions (struct bfd_link_info *info)
            asection *s;
 
            *p = s = bfd_section_from_elf_index (ibfd, sy->st_shndx);
-           if (s != NULL && interesting_section (s, info->output_bfd))
+           if (s != NULL && interesting_section (s))
              *psy++ = sy;
          }
       symcount = psy - psyms;
@@ -2489,7 +2442,7 @@ discover_functions (struct bfd_link_info *info)
        }
 
       for (sec = ibfd->sections; sec != NULL && !gaps; sec = sec->next)
-       if (interesting_section (sec, info->output_bfd))
+       if (interesting_section (sec))
          gaps |= check_function_ranges (sec, info);
     }
 
@@ -2530,7 +2483,7 @@ discover_functions (struct bfd_link_info *info)
 
          gaps = FALSE;
          for (sec = ibfd->sections; sec != NULL && !gaps; sec = sec->next)
-           if (interesting_section (sec, info->output_bfd))
+           if (interesting_section (sec))
              gaps |= check_function_ranges (sec, info);
          if (!gaps)
            continue;
@@ -2565,7 +2518,7 @@ discover_functions (struct bfd_link_info *info)
             the range of such functions to the beginning of the
             next symbol of interest.  */
          for (sec = ibfd->sections; sec != NULL; sec = sec->next)
-           if (interesting_section (sec, info->output_bfd))
+           if (interesting_section (sec))
              {
                struct _spu_elf_section_data *sec_data;
                struct spu_elf_stack_info *sinfo;
@@ -2724,7 +2677,7 @@ remove_cycles (struct function_info *fun,
        }
       else if (call->fun->marking)
        {
-         if (!spu_hash_table (info)->auto_overlay)
+         if (!spu_hash_table (info)->params->auto_overlay)
            {
              const char *f1 = func_name (fun);
              const char *f2 = func_name (call->fun);
@@ -2784,7 +2737,7 @@ build_call_tree (struct bfd_link_info *info)
 
   /* Transfer call info from hot/cold section part of function
      to main entry.  */
-  if (!spu_hash_table (info)->auto_overlay
+  if (!spu_hash_table (info)->params->auto_overlay
       && !for_each_node (transfer_calls, info, 0, FALSE))
     return FALSE;
 
@@ -2863,7 +2816,7 @@ mark_overlay_section (struct function_info *fun,
         this flag to differentiate the two overlay section types.  */
       fun->sec->flags |= SEC_CODE;
 
-      if (spu_hash_table (info)->auto_overlay & OVERLAY_RODATA)
+      if (spu_hash_table (info)->params->auto_overlay & OVERLAY_RODATA)
        {
          char *name = NULL;
 
@@ -3119,6 +3072,7 @@ auto_ovl_lib_functions (struct bfd_link_info *info, unsigned int lib_size)
   unsigned int i, lib_count;
   struct _cl_param collect_lib_param;
   struct function_info dummy_caller;
+  struct spu_link_hash_table *htab;
 
   memset (&dummy_caller, 0, sizeof (dummy_caller));
   lib_count = 0;
@@ -3150,6 +3104,7 @@ auto_ovl_lib_functions (struct bfd_link_info *info, unsigned int lib_size)
   if (lib_count > 1)
     qsort (lib_sections, lib_count, 2 * sizeof (*lib_sections), sort_lib);
 
+  htab = spu_hash_table (info);
   for (i = 0; i < lib_count; i++)
     {
       unsigned int tmp, stub_size;
@@ -3181,7 +3136,7 @@ auto_ovl_lib_functions (struct bfd_link_info *info, unsigned int lib_size)
                    if (p->fun == call->fun)
                      break;
                  if (!p)
-                   stub_size += OVL_STUB_SIZE;
+                   stub_size += ovl_stub_size (htab->params->ovly_flavour);
                }
        }
       if (tmp + stub_size < lib_size)
@@ -3199,7 +3154,7 @@ auto_ovl_lib_functions (struct bfd_link_info *info, unsigned int lib_size)
          while ((p = *pp) != NULL)
            if (!p->fun->sec->linker_mark)
              {
-               lib_size += OVL_STUB_SIZE;
+               lib_size += ovl_stub_size (htab->params->ovly_flavour);
                *pp = p->next;
                free (p);
              }
@@ -3386,7 +3341,7 @@ sum_stack (struct function_info *fun,
     sum_stack_param->overall_stack = cum_stack;
 
   htab = spu_hash_table (info);
-  if (htab->auto_overlay)
+  if (htab->params->auto_overlay)
     return TRUE;
 
   f1 = func_name (fun);
@@ -3477,12 +3432,11 @@ sort_bfds (const void *a, const void *b)
 
 /* Handle --auto-overlay.  */
 
-static void spu_elf_auto_overlay (struct bfd_link_info *, void (*) (void))
+static void spu_elf_auto_overlay (struct bfd_link_info *)
      ATTRIBUTE_NORETURN;
 
 static void
-spu_elf_auto_overlay (struct bfd_link_info *info,
-                     void (*spu_elf_load_ovl_mgr) (void))
+spu_elf_auto_overlay (struct bfd_link_info *info)
 {
   bfd *ibfd;
   bfd **bfd_arr;
@@ -3539,13 +3493,7 @@ spu_elf_auto_overlay (struct bfd_link_info *info,
     {
       /* If no user overlay manager, spu_elf_load_ovl_mgr will add our
         builtin version to .text, and will adjust .text size.  */
-      asection *text = bfd_get_section_by_name (info->output_bfd, ".text");
-      if (text != NULL)
-       fixed_size -= text->size;
-      spu_elf_load_ovl_mgr ();
-      text = bfd_get_section_by_name (info->output_bfd, ".text");
-      if (text != NULL)
-       fixed_size += text->size;
+      fixed_size += (*htab->params->spu_elf_load_ovl_mgr) ();
     }
 
   /* Mark overlay sections, and find max overlay section size.  */
@@ -3637,7 +3585,7 @@ spu_elf_auto_overlay (struct bfd_link_info *info,
       htab->reserved = sum_stack_param.overall_stack + htab->extra_stack_space;
     }
   fixed_size += htab->reserved;
-  fixed_size += htab->non_ovly_stub * OVL_STUB_SIZE;
+  fixed_size += htab->non_ovly_stub * ovl_stub_size (htab->params->ovly_flavour);
   if (fixed_size + mos_param.max_overlay_size <= htab->local_store)
     {
       /* Guess number of overlays.  Assuming overlay buffer is on
@@ -3678,7 +3626,7 @@ spu_elf_auto_overlay (struct bfd_link_info *info,
     goto err_exit;
   count = (size_t) (ovly_p - ovly_sections) / 2;
 
-  script = htab->spu_elf_open_overlay_script ();
+  script = (*htab->params->spu_elf_open_overlay_script) ();
 
   if (fprintf (script, "SECTIONS\n{\n OVERLAY :\n {\n") <= 0)
     goto file_err;
@@ -3696,7 +3644,7 @@ spu_elf_auto_overlay (struct bfd_link_info *info,
        {
          asection *sec;
          unsigned int tmp;
-         unsigned int stub_size;
+         unsigned int num_stubs;
          struct call_info *call, *pasty;
          struct _spu_elf_section_data *sec_data;
          struct spu_elf_stack_info *sinfo;
@@ -3761,22 +3709,23 @@ spu_elf_auto_overlay (struct bfd_link_info *info,
            }
 
          /* Calculate call stub size.  */
-         stub_size = 0;
+         num_stubs = 0;
          for (call = dummy_caller.call_list; call; call = call->next)
            {
              unsigned int k;
 
-             stub_size += OVL_STUB_SIZE;
+             ++num_stubs;
              /* If the call is within this overlay, we won't need a
                 stub.  */
              for (k = base; k < i + 1; k++)
                if (call->fun->sec == ovly_sections[2 * k])
                  {
-                   stub_size -= OVL_STUB_SIZE;
+                   --num_stubs;
                    break;
                  }
            }
-         if (tmp + stub_size > overlay_size)
+         if (tmp + num_stubs * ovl_stub_size (htab->params->ovly_flavour)
+             > overlay_size)
            break;
          
          size = tmp;
@@ -3880,8 +3829,8 @@ spu_elf_auto_overlay (struct bfd_link_info *info,
   if (fclose (script) != 0)
     goto file_err;
 
-  if (htab->auto_overlay & AUTO_RELINK)
-    htab->spu_elf_relink ();
+  if (htab->params->auto_overlay & AUTO_RELINK)
+    (*htab->params->spu_elf_relink) ();
 
   xexit (0);
 
@@ -3895,8 +3844,9 @@ spu_elf_auto_overlay (struct bfd_link_info *info,
 /* Provide an estimate of total stack required.  */
 
 static bfd_boolean
-spu_elf_stack_analysis (struct bfd_link_info *info, int emit_stack_syms)
+spu_elf_stack_analysis (struct bfd_link_info *info)
 {
+  struct spu_link_hash_table *htab;
   struct _sum_stack_param sum_stack_param;
 
   if (!discover_functions (info))
@@ -3905,11 +3855,12 @@ spu_elf_stack_analysis (struct bfd_link_info *info, int emit_stack_syms)
   if (!build_call_tree (info))
     return FALSE;
 
+  htab = spu_hash_table (info);
   info->callbacks->info (_("Stack size for call graph root nodes.\n"));
   info->callbacks->minfo (_("\nStack size for functions.  "
                            "Annotations: '*' max stack, 't' tail call\n"));
 
-  sum_stack_param.emit_stack_syms = emit_stack_syms;
+  sum_stack_param.emit_stack_syms = htab->params->emit_stack_syms;
   sum_stack_param.overall_stack = 0;
   if (!for_each_node (sum_stack, info, &sum_stack_param, TRUE))
     return FALSE;
@@ -3926,11 +3877,11 @@ spu_elf_final_link (bfd *output_bfd, struct bfd_link_info *info)
 {
   struct spu_link_hash_table *htab = spu_hash_table (info);
 
-  if (htab->auto_overlay)
-    spu_elf_auto_overlay (info, htab->spu_elf_load_ovl_mgr);
+  if (htab->params->auto_overlay)
+    spu_elf_auto_overlay (info);
 
-  if (htab->stack_analysis
-      && !spu_elf_stack_analysis (info, htab->emit_stack_syms))
+  if (htab->params->stack_analysis
+      && !spu_elf_stack_analysis (info))
     info->callbacks->einfo ("%X%P: stack analysis error: %E\n");
 
   return bfd_elf_final_link (output_bfd, info);
@@ -3983,7 +3934,7 @@ spu_elf_relocate_section (bfd *output_bfd,
   struct elf_link_hash_entry **sym_hashes;
   Elf_Internal_Rela *rel, *relend;
   struct spu_link_hash_table *htab;
-  asection *ea = bfd_get_section_by_name (output_bfd, "._ea");
+  asection *ea;
   int ret = TRUE;
   bfd_boolean emit_these_relocs = FALSE;
   bfd_boolean is_ea_sym;
@@ -3991,7 +3942,8 @@ spu_elf_relocate_section (bfd *output_bfd,
 
   htab = spu_hash_table (info);
   stubs = (htab->stub_sec != NULL
-          && maybe_needs_stubs (input_section, output_bfd));
+          && maybe_needs_stubs (input_section));
+  ea = bfd_get_section_by_name (output_bfd, "._ea");
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
   sym_hashes = (struct elf_link_hash_entry **) (elf_sym_hashes (input_bfd));
 
index ec443fd99f8245472aa81fe6be8a611180c84106..8cac3a33760bbcbb6d09448c5883f1d403a7f7a4 100644 (file)
    along with this program; if not, write to the Free Software Foundation,
    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
+struct spu_elf_params
+{
+  /* Stash various callbacks for --auto-overlay.  */
+  void (*place_spu_section) (asection *, asection *, const char *);
+  bfd_size_type (*spu_elf_load_ovl_mgr) (void);
+  FILE *(*spu_elf_open_overlay_script) (void);
+  void (*spu_elf_relink) (void);
+
+  /* Bit 0 set if --auto-overlay.
+     Bit 1 set if --auto-relink.
+     Bit 2 set if --overlay-rodata.  */
+  unsigned int auto_overlay : 3;
+#define AUTO_OVERLAY 1
+#define AUTO_RELINK 2
+#define OVERLAY_RODATA 4
+
+  /* Type of overlays, enum _ovly_flavour.  */
+  unsigned int ovly_flavour : 2;
+
+  /* Set if we should emit symbols for stubs.  */
+  unsigned int emit_stub_syms : 1;
+
+  /* Set if we want stubs on calls out of overlay regions to
+     non-overlay regions.  */
+  unsigned int non_overlay_stubs : 1;
+
+  /* Set if stack size analysis should be done.  */
+  unsigned int stack_analysis : 1;
+
+  /* Set if __stack_* syms will be emitted.  */
+  unsigned int emit_stack_syms : 1;
+
+  /* Range of valid addresses for loadable sections.  */
+  bfd_vma local_store_lo;
+  bfd_vma local_store_hi;
+
+  /* Control --auto-overlay feature.  */
+  unsigned int auto_overlay_fixed;
+  unsigned int auto_overlay_reserved;
+  int extra_stack_space;
+};
+
 /* Extra info kept for SPU sections.  */
 
 struct spu_elf_stack_info;
@@ -45,22 +87,25 @@ struct _spu_elf_section_data
 #define spu_elf_section_data(sec) \
   ((struct _spu_elf_section_data *) elf_section_data (sec))
 
+enum _ovly_flavour
+{
+  ovly_compact,
+  ovly_normal,
+  ovly_none
+};
+
 struct _ovl_stream
 {
   const void *start;
   const void *end;
 };
 
+extern void spu_elf_setup (struct bfd_link_info *, struct spu_elf_params *);
 extern void spu_elf_plugin (int);
 extern bfd_boolean spu_elf_open_builtin_lib (bfd **,
                                             const struct _ovl_stream *);
-extern bfd_boolean spu_elf_create_sections (struct bfd_link_info *, int, int);
+extern bfd_boolean spu_elf_create_sections (struct bfd_link_info *);
 extern bfd_boolean spu_elf_find_overlays (struct bfd_link_info *);
-extern int spu_elf_size_stubs (struct bfd_link_info *,
-                              void (*) (asection *, asection *, const char *),
-                              int);
-extern bfd_boolean spu_elf_build_stubs (struct bfd_link_info *, int);
-extern asection *spu_elf_check_vma (struct bfd_link_info *, int,
-                                   unsigned int, unsigned int, unsigned int,
-                                   unsigned int, int, void (*) (void),
-                                   FILE *(*) (void), void (*) (void));
+extern int spu_elf_size_stubs (struct bfd_link_info *);
+extern bfd_boolean spu_elf_build_stubs (struct bfd_link_info *);
+extern asection *spu_elf_check_vma (struct bfd_link_info *);
index b7d0cf2f00eb7cc10c140608869061ccdfee0854..864cba31f1c550c0d62e2abfc1d70783119390a6 100644 (file)
@@ -1,3 +1,13 @@
+2008-12-10  Alan Modra  <amodra@bigpond.net.au>
+
+       * emultempl/spuelf.em (params): New var, used instead of various others.
+       Adjust use throughout file.
+       (spu_after_open): Call spu_elf_setup.
+       (spu_place_special_section): Tidy.
+       (spu_elf_load_ovl_mgr): Return total size of sections loaded.  Move
+       code setting overlay section alignment to..
+       (spu_before_allocation): ..here.
+
 2008-12-03  Nick Clifton  <nickc@redhat.com>
 
        * NEWS: Mention new feature.
index fe248af6a46b86bc2e6b1de90274bf0586932186..cb80c45cbf30f2ae75e0e6f09d9bf268af52cb2b 100644 (file)
@@ -26,31 +26,23 @@ fragment <<EOF
 #include "ldctor.h"
 #include "elf32-spu.h"
 
-/* Non-zero if no overlay processing should be done.  */
-static int no_overlays = 0;
+static void spu_place_special_section (asection *, asection *, const char *);
+static bfd_size_type spu_elf_load_ovl_mgr (void);
+static FILE *spu_elf_open_overlay_script (void);
+static void spu_elf_relink (void);
 
-/* Non-zero if we want stubs on all calls out of overlay regions.  */
-static int non_overlay_stubs = 0;
-
-/* Whether to emit symbols for stubs.  */
-static int emit_stub_syms = 0;
-
-/* Non-zero to perform stack space analysis.  */
-static int stack_analysis = 0;
-
-/* Whether to emit symbols with stack requirements for each function.  */
-static int emit_stack_syms = 0;
-
-/* Range of valid addresses for loadable sections.  */
-static bfd_vma local_store_lo = 0;
-static bfd_vma local_store_hi = 0x3ffff;
-
-/* Control --auto-overlay feature.  */
-static int auto_overlay = 0;
+static struct spu_elf_params params =
+{
+  &spu_place_special_section,
+  &spu_elf_load_ovl_mgr,
+  &spu_elf_open_overlay_script,
+  &spu_elf_relink,
+  0, ovly_normal, 0, 0, 0, 0,
+  0, 0x3ffff,
+  0, 0, 2000
+};
+  
 static char *auto_overlay_file = 0;
-static unsigned int auto_overlay_fixed = 0;
-static unsigned int auto_overlay_reserved = 0;
-static int extra_stack_space = 2000;
 int my_argc;
 char **my_argv;
 
@@ -86,12 +78,19 @@ is_spu_target (void)
 static void
 spu_after_open (void)
 {
-  if (is_spu_target ()
-      && !link_info.relocatable
-      && link_info.input_bfds != NULL
-      && !spu_elf_create_sections (&link_info,
-                                  stack_analysis, emit_stack_syms))
-    einfo ("%X%P: can not create note section: %E\n");
+  if (is_spu_target ())
+    {
+      /* Pass params to backend.  */
+      if ((params.auto_overlay & AUTO_OVERLAY) == 0)
+       params.auto_overlay = 0;
+      params.emit_stub_syms |= link_info.emitrelocations;
+      spu_elf_setup (&link_info, &params);
+
+      if (!link_info.relocatable
+         && link_info.input_bfds != NULL
+         && !spu_elf_create_sections (&link_info))
+       einfo ("%X%P: can not create note section: %E\n");
+    }
 
   gld${EMULATION_NAME}_after_open ();
 }
@@ -112,7 +111,9 @@ spu_place_special_section (asection *s, asection *o, const char *output_name)
 {
   lang_output_section_statement_type *os;
 
-  os = lang_output_section_find (o != NULL ? o->name : output_name);
+  if (o != NULL)
+    output_name = o->name;
+  os = lang_output_section_find (output_name);
   if (os == NULL)
     gld${EMULATION_NAME}_place_orphan (s, output_name, 0);
   else if (o != NULL && os->children.head != NULL)
@@ -130,13 +131,13 @@ spu_place_special_section (asection *s, asection *o, const char *output_name)
   s->output_section->size += s->size;
 }
 
-/* Load built-in overlay manager, and tweak overlay section alignment.  */
+/* Load built-in overlay manager.  */
 
-static void
+static bfd_size_type
 spu_elf_load_ovl_mgr (void)
 {
-  lang_output_section_statement_type *os;
   struct elf_link_hash_entry *h;
+  bfd_size_type total = 0;
 
   h = elf_link_hash_lookup (elf_hash_table (&link_info),
                            "__ovly_load", FALSE, FALSE, FALSE);
@@ -171,24 +172,13 @@ spu_elf_load_ovl_mgr (void)
          for (in = ovl_is->the_bfd->sections; in != NULL; in = in->next)
            if ((in->flags & (SEC_ALLOC | SEC_LOAD))
                == (SEC_ALLOC | SEC_LOAD))
-             spu_place_special_section (in, NULL, ".text");
+             {
+               total += in->size;
+               spu_place_special_section (in, NULL, ".text");
+             }
        }
     }
-
-  /* Ensure alignment of overlay sections is sufficient.  */
-  for (os = &lang_output_section_statement.head->output_section_statement;
-       os != NULL;
-       os = os->next)
-    if (os->bfd_section != NULL
-       && spu_elf_section_data (os->bfd_section) != NULL
-       && spu_elf_section_data (os->bfd_section)->u.o.ovl_index != 0)
-      {
-       if (os->bfd_section->alignment_power < 4)
-         os->bfd_section->alignment_power = 4;
-
-       /* Also ensure size rounds up.  */
-       os->block_value = 16;
-      }
+  return total;
 }
 
 /* Go find if we need to do anything special for overlays.  */
@@ -198,7 +188,7 @@ spu_before_allocation (void)
 {
   if (is_spu_target ()
       && !link_info.relocatable
-      && !no_overlays)
+      && params.ovly_flavour != ovly_none)
     {
       /* Size the sections.  This is premature, but we need to know the
         rough layout so that overlays can be found.  */
@@ -210,16 +200,30 @@ spu_before_allocation (void)
       if (spu_elf_find_overlays (&link_info))
        {
          int ret;
+         lang_output_section_statement_type *os;
 
-         if (auto_overlay != 0)
+         if (params.auto_overlay != 0)
            {
              einfo ("%P: --auto-overlay ignored with user overlay script\n");
-             auto_overlay = 0;
+             params.auto_overlay = 0;
            }
 
-         ret = spu_elf_size_stubs (&link_info,
-                                   spu_place_special_section,
-                                   non_overlay_stubs);
+         /* Ensure alignment of overlay sections is sufficient.  */
+         for (os = &lang_output_section_statement.head->output_section_statement;
+              os != NULL;
+              os = os->next)
+           if (os->bfd_section != NULL
+               && spu_elf_section_data (os->bfd_section) != NULL
+               && spu_elf_section_data (os->bfd_section)->u.o.ovl_index != 0)
+             {
+               if (os->bfd_section->alignment_power < 4)
+                 os->bfd_section->alignment_power = 4;
+
+               /* Also ensure size rounds up.  */
+               os->block_value = 16;
+             }
+
+         ret = spu_elf_size_stubs (&link_info);
          if (ret == 0)
            einfo ("%X%P: can not size overlay stubs: %E\n");
          else if (ret == 2)
@@ -324,25 +328,18 @@ gld${EMULATION_NAME}_finish (void)
 
   if (is_spu_target ())
     {
-      if (local_store_lo < local_store_hi)
+      if (params.local_store_lo < params.local_store_hi)
         {
          asection *s;
 
-         s = spu_elf_check_vma (&link_info, auto_overlay,
-                                local_store_lo, local_store_hi,
-                                auto_overlay_fixed, auto_overlay_reserved,
-                                extra_stack_space,
-                                spu_elf_load_ovl_mgr,
-                                spu_elf_open_overlay_script,
-                                spu_elf_relink);
-         if (s != NULL && !auto_overlay)
+         s = spu_elf_check_vma (&link_info);
+         if (s != NULL && !params.auto_overlay)
            einfo ("%X%P: %A exceeds local store range\n", s);
        }
-      else if (auto_overlay)
+      else if (params.auto_overlay)
        einfo ("%P: --auto-overlay ignored with zero local store range\n");
 
-      if (!spu_elf_build_stubs (&link_info,
-                               emit_stub_syms || link_info.emitrelocations))
+      if (!spu_elf_build_stubs (&link_info))
        einfo ("%F%P: can not build overlay stubs: %E\n");
     }
 
@@ -574,24 +571,24 @@ PARSE_AND_LIST_ARGS_CASES='
       break;
 
     case OPTION_SPU_NO_OVERLAYS:
-      no_overlays = 1;
+      params.ovly_flavour = ovly_none;
       break;
 
     case OPTION_SPU_STUB_SYMS:
-      emit_stub_syms = 1;
+      params.emit_stub_syms = 1;
       break;
 
     case OPTION_SPU_NON_OVERLAY_STUBS:
-      non_overlay_stubs = 1;
+      params.non_overlay_stubs = 1;
       break;
 
     case OPTION_SPU_LOCAL_STORE:
       {
        char *end;
-       local_store_lo = strtoul (optarg, &end, 0);
+       params.local_store_lo = strtoul (optarg, &end, 0);
        if (*end == '\'':'\'')
          {
-           local_store_hi = strtoul (end + 1, &end, 0);
+           params.local_store_hi = strtoul (end + 1, &end, 0);
            if (*end == 0)
              break;
          }
@@ -600,15 +597,15 @@ PARSE_AND_LIST_ARGS_CASES='
       break;
 
     case OPTION_SPU_STACK_ANALYSIS:
-      stack_analysis = 1;
+      params.stack_analysis = 1;
       break;
 
     case OPTION_SPU_STACK_SYMS:
-      emit_stack_syms = 1;
+      params.emit_stack_syms = 1;
       break;
 
     case OPTION_SPU_AUTO_OVERLAY:
-      auto_overlay |= 1;
+      params.auto_overlay |= 1;
       if (optarg != NULL)
        {
          auto_overlay_file = optarg;
@@ -617,17 +614,17 @@ PARSE_AND_LIST_ARGS_CASES='
       /* Fall thru */
 
     case OPTION_SPU_AUTO_RELINK:
-      auto_overlay |= 2;
+      params.auto_overlay |= 2;
       break;
 
     case OPTION_SPU_OVERLAY_RODATA:
-      auto_overlay |= 4;
+      params.auto_overlay |= 4;
       break;
 
     case OPTION_SPU_FIXED_SPACE:
       {
        char *end;
-       auto_overlay_fixed = strtoul (optarg, &end, 0);
+       params.auto_overlay_fixed = strtoul (optarg, &end, 0);
        if (*end != 0)
          einfo (_("%P%F: invalid --fixed-space value `%s'\''\n"), optarg);
       }
@@ -636,7 +633,7 @@ PARSE_AND_LIST_ARGS_CASES='
     case OPTION_SPU_RESERVED_SPACE:
       {
        char *end;
-       auto_overlay_reserved = strtoul (optarg, &end, 0);
+       params.auto_overlay_reserved = strtoul (optarg, &end, 0);
        if (*end != 0)
          einfo (_("%P%F: invalid --reserved-space value `%s'\''\n"), optarg);
       }
@@ -645,14 +642,14 @@ PARSE_AND_LIST_ARGS_CASES='
     case OPTION_SPU_EXTRA_STACK:
       {
        char *end;
-       extra_stack_space = strtol (optarg, &end, 0);
+       params.extra_stack_space = strtol (optarg, &end, 0);
        if (*end != 0)
          einfo (_("%P%F: invalid --extra-stack-space value `%s'\''\n"), optarg);
       }
       break;
 
     case OPTION_SPU_NO_AUTO_OVERLAY:
-      auto_overlay = 0;
+      params.auto_overlay = 0;
       if (optarg != NULL)
        {
          struct tflist *tf;