* elf-eh-frame.c (_bfd_elf_discard_section_eh_frame): Warn if
[deliverable/binutils-gdb.git] / bfd / elf32-spu.c
index 5d0c0f76ef1604a2fc262e9f8a0b27802532e6ce..df0b68ae22d149c7edbfbfe6887b40c77830e4ab 100644 (file)
@@ -1,6 +1,6 @@
 /* SPU specific support for 32-bit ELF
 
-   Copyright 2006 Free Software Foundation, Inc.
+   Copyright 2006, 2007 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -142,6 +142,20 @@ spu_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
   return elf_howto_table + spu_elf_bfd_to_reloc_type (code);
 }
 
+static reloc_howto_type *
+spu_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+                          const char *r_name)
+{
+  unsigned int i;
+
+  for (i = 0; i < sizeof (elf_howto_table) / sizeof (elf_howto_table[0]); i++)
+    if (elf_howto_table[i].name != NULL
+       && strcasecmp (elf_howto_table[i].name, r_name) == 0)
+      return &elf_howto_table[i];
+
+  return NULL;
+}
+
 /* Apply R_SPU_REL9 and R_SPU_REL9I relocs.  */
 
 static bfd_reloc_status_type
@@ -425,14 +439,11 @@ get_sym_h (struct elf_link_hash_entry **hp,
   return TRUE;
 }
 
-/* Build a name for an entry in the stub hash table.  The input section
-   id isn't really necessary but we add that in for consistency with
-   ppc32 and ppc64 stub names.  We can't use a local symbol name
-   because ld -r might generate duplicate local symbols.  */
+/* Build a name for an entry in the stub hash table.  We can't use a
+   local symbol name because ld -r might generate duplicate local symbols.  */
 
 static char *
-spu_stub_name (const asection *input_sec,
-              const asection *sym_sec,
+spu_stub_name (const asection *sym_sec,
               const struct elf_link_hash_entry *h,
               const Elf_Internal_Rela *rel)
 {
@@ -441,26 +452,24 @@ spu_stub_name (const asection *input_sec,
 
   if (h)
     {
-      len = 8 + 1 + strlen (h->root.root.string) + 1 + 8 + 1;
+      len = strlen (h->root.root.string) + 1 + 8 + 1;
       stub_name = bfd_malloc (len);
       if (stub_name == NULL)
        return stub_name;
 
-      sprintf (stub_name, "%08x.%s+%x",
-              input_sec->id & 0xffffffff,
+      sprintf (stub_name, "%s+%x",
               h->root.root.string,
               (int) rel->r_addend & 0xffffffff);
       len -= 8;
     }
   else
     {
-      len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1;
+      len = 8 + 1 + 8 + 1 + 8 + 1;
       stub_name = bfd_malloc (len);
       if (stub_name == NULL)
        return stub_name;
 
-      sprintf (stub_name, "%08x.%x:%x+%x",
-              input_sec->id & 0xffffffff,
+      sprintf (stub_name, "%x:%x+%x",
               sym_sec->id & 0xffffffff,
               (int) ELF32_R_SYM (rel->r_info) & 0xffffffff,
               (int) rel->r_addend & 0xffffffff);
@@ -682,11 +691,100 @@ is_branch (const unsigned char *insn)
          || (insn[0] & 0xfc) == 0x10);
 }
 
+/* Return TRUE if this reloc symbol should possibly go via an overlay stub.  */
+
+static bfd_boolean
+needs_ovl_stub (const char *sym_name,
+               asection *sym_sec,
+               asection *input_section,
+               struct spu_link_hash_table *htab,
+               bfd_boolean is_branch)
+{
+  if (htab->num_overlays == 0)
+    return FALSE;
+
+  if (sym_sec == NULL
+      || sym_sec->output_section == NULL
+      || spu_elf_section_data (sym_sec->output_section) == NULL)
+    return FALSE;
+
+  /* setjmp always goes via an overlay stub, because then the return
+     and hence the longjmp goes via __ovly_return.  That magically
+     makes setjmp/longjmp between overlays work.  */
+  if (strncmp (sym_name, "setjmp", 6) == 0
+      && (sym_name[6] == '\0' || sym_name[6] == '@'))
+    return TRUE;
+
+  /* Usually, symbols in non-overlay sections don't need stubs.  */
+  if (spu_elf_section_data (sym_sec->output_section)->ovl_index == 0
+      && !htab->non_overlay_stubs)
+    return FALSE;
+
+  /* A reference from some other section to a symbol in an overlay
+     section needs a stub.  */
+  if (spu_elf_section_data (sym_sec->output_section)->ovl_index
+       != spu_elf_section_data (input_section->output_section)->ovl_index)
+    return TRUE;
+
+  /* If this insn isn't a branch then we are possibly taking the
+     address of a function and passing it out somehow.  */
+  return !is_branch;
+}
+
 struct stubarr {
+  struct bfd_hash_table *stub_hash_table;
   struct spu_stub_hash_entry **sh;
   unsigned int count;
+  int err;
 };
 
+/* Called via elf_link_hash_traverse to allocate stubs for any _SPUEAR_
+   symbols.  */
+
+static bfd_boolean
+allocate_spuear_stubs (struct elf_link_hash_entry *h, void *inf)
+{
+  /* Symbols starting with _SPUEAR_ need a stub because they may be
+     invoked by the PPU.  */
+  if ((h->root.type == bfd_link_hash_defined
+       || h->root.type == bfd_link_hash_defweak)
+      && h->def_regular
+      && strncmp (h->root.root.string, "_SPUEAR_", 8) == 0)
+    {
+      struct stubarr *stubs = inf;
+      static Elf_Internal_Rela zero_rel;
+      char *stub_name = spu_stub_name (h->root.u.def.section, h, &zero_rel);
+      struct spu_stub_hash_entry *sh;
+
+      if (stub_name == NULL)
+       {
+         stubs->err = 1;
+         return FALSE;
+       }
+
+      sh = (struct spu_stub_hash_entry *)
+       bfd_hash_lookup (stubs->stub_hash_table, stub_name, TRUE, FALSE);
+      if (sh == NULL)
+       {
+         free (stub_name);
+         return FALSE;
+       }
+
+      /* If this entry isn't new, we already have a stub.  */
+      if (sh->target_section != NULL)
+       {
+         free (stub_name);
+         return TRUE;
+       }
+
+      sh->target_section = h->root.u.def.section;
+      sh->target_off = h->root.u.def.value;
+      stubs->count += 1;
+    }
+  
+  return TRUE;
+}
+
 /* Called via bfd_hash_traverse to set up pointers to all symbols
    in the stub hash table.  */
 
@@ -746,7 +844,9 @@ spu_elf_size_stubs (bfd *output_bfd,
   flagword flags;
 
   htab->non_overlay_stubs = non_overlay_stubs;
+  stubs.stub_hash_table = &htab->stub_hash_table;
   stubs.count = 0;
+  stubs.err = 0;
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
     {
       extern const bfd_target bfd_elf32_spu_vec;
@@ -797,6 +897,7 @@ spu_elf_size_stubs (bfd *output_bfd,
              asection *sym_sec;
              Elf_Internal_Sym *sym;
              struct elf_link_hash_entry *h;
+             const char *sym_name;
              char *stub_name;
              struct spu_stub_hash_entry *sh;
              unsigned int sym_type;
@@ -846,9 +947,18 @@ spu_elf_size_stubs (bfd *output_bfd,
 
              /* We are only interested in function symbols.  */
              if (h != NULL)
-               sym_type = h->type;
+               {
+                 sym_type = h->type;
+                 sym_name = h->root.root.string;
+               }
              else
-               sym_type = ELF_ST_TYPE (sym->st_info);
+               {
+                 sym_type = ELF_ST_TYPE (sym->st_info);
+                 sym_name = bfd_elf_sym_name (sym_sec->owner,
+                                              symtab_hdr,
+                                              sym,
+                                              sym_sec);
+               }
              if (sym_type != STT_FUNC)
                {
                  /* It's common for people to write assembly and forget
@@ -858,43 +968,18 @@ spu_elf_size_stubs (bfd *output_bfd,
                     type to be correct to distinguish function pointer
                     initialisation from other pointer initialisation.  */
                  if (insn_type == call)
-                   {
-                     const char *sym_name;
-
-                     if (h != NULL)
-                       sym_name = h->root.root.string;
-                     else
-                       sym_name = bfd_elf_sym_name (sym_sec->owner,
-                                                    symtab_hdr,
-                                                    sym,
-                                                    sym_sec);
-
-                     (*_bfd_error_handler) (_("warning: call to non-function"
-                                              " symbol %s defined in %B"),
-                                            sym_name, sym_sec->owner);
-                   }
+                   (*_bfd_error_handler) (_("warning: call to non-function"
+                                            " symbol %s defined in %B"),
+                                          sym_sec->owner, sym_name);
                  else
                    continue;
                }
 
-             /* Usually, non-overlay sections don't need stubs.  */
-             if (!spu_elf_section_data (sym_sec->output_section)->ovl_index
-                 && !non_overlay_stubs)
+             if (!needs_ovl_stub (sym_name, sym_sec, section, htab,
+                                  insn_type != non_branch))
                continue;
 
-             /* We need a reference from some other section before
-                we consider that a symbol might need an overlay stub.  */
-             if (spu_elf_section_data (sym_sec->output_section)->ovl_index
-                 == spu_elf_section_data (section->output_section)->ovl_index)
-               {
-                 /* Or we need this to *not* be a branch.  ie. We are
-                    possibly taking the address of a function and
-                    passing it out somehow.  */
-                 if (insn_type != non_branch)
-                   continue;
-               }
-
-             stub_name = spu_stub_name (section, sym_sec, h, irela);
+             stub_name = spu_stub_name (sym_sec, h, irela);
              if (stub_name == NULL)
                goto error_ret_free_internal;
 
@@ -947,6 +1032,10 @@ spu_elf_size_stubs (bfd *output_bfd,
        }
     }
 
+  elf_link_hash_traverse (&htab->elf, allocate_spuear_stubs, &stubs);
+  if (stubs.err)
+    return FALSE;
+
   *stub = NULL;
   if (stubs.count == 0)
     return TRUE;
@@ -1069,7 +1158,7 @@ ovl_mgr_pread (struct bfd *abfd ATTRIBUTE_UNUSED,
   size_t max;
 
   os = (struct _ovl_stream *) stream;
-  max = (char *) os->end - (char *) os->start;
+  max = (const char *) os->end - (const char *) os->start;
 
   if ((ufile_ptr) offset >= max)
     return 0;
@@ -1078,7 +1167,7 @@ ovl_mgr_pread (struct bfd *abfd ATTRIBUTE_UNUSED,
   if (count > max - offset)
     count = max - offset;
 
-  memcpy (buf, (char *) os->start + offset, count);
+  memcpy (buf, (const char *) os->start + offset, count);
   return count;
 }
 
@@ -1145,14 +1234,13 @@ write_one_stub (struct bfd_hash_entry *bh, void *inf)
       size_t len1, len2;
       char *name;
 
-      len1 = sizeof ("ovl_call.") - 1;
+      len1 = sizeof ("00000000.ovl_call.") - 1;
       len2 = strlen (ent->root.string);
       name = bfd_malloc (len1 + len2 + 1);
       if (name == NULL)
        return FALSE;
-      memcpy (name, ent->root.string, 9);
-      memcpy (name + 9, "ovl_call.", len1);
-      memcpy (name + 9 + len1, ent->root.string + 9, len2 - 9 + 1);
+      memcpy (name, "00000000.ovl_call.", len1);
+      memcpy (name + len1, ent->root.string, len2 + 1);
       h = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE);
       if (h == NULL)
        return FALSE;
@@ -1351,9 +1439,6 @@ spu_elf_relocate_section (bfd *output_bfd,
   struct spu_link_hash_table *htab;
   bfd_boolean ret = TRUE;
 
-  if (info->relocatable)
-    return TRUE;
-
   htab = spu_hash_table (info);
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
   sym_hashes = (struct elf_link_hash_entry **) (elf_sym_hashes (input_bfd));
@@ -1400,6 +1485,20 @@ spu_elf_relocate_section (bfd *output_bfd,
          sym_name = h->root.root.string;
        }
 
+      if (sec != NULL && elf_discarded_section (sec))
+       {
+         /* For relocs against symbols from removed linkonce sections,
+            or sections discarded by a linker script, we just want the
+            section contents zeroed.  Avoid any special processing.  */
+         _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
+         rel->r_info = 0;
+         rel->r_addend = 0;
+         continue;
+       }
+
+      if (info->relocatable)
+       continue;
+
       if (unresolved_reloc)
        {
          (*_bfd_error_handler)
@@ -1415,18 +1514,13 @@ spu_elf_relocate_section (bfd *output_bfd,
       /* If this symbol is in an overlay area, we may need to relocate
         to the overlay stub.  */
       addend = rel->r_addend;
-      if (sec != NULL
-         && sec->output_section != NULL
-         && sec->output_section->owner == output_bfd
-         && (spu_elf_section_data (sec->output_section)->ovl_index != 0
-             || htab->non_overlay_stubs)
-         && !(sec == input_section
-              && is_branch (contents + rel->r_offset)))
+      if (needs_ovl_stub (sym_name, sec, input_section, htab,
+                         is_branch (contents + rel->r_offset)))
        {
          char *stub_name;
          struct spu_stub_hash_entry *sh;
 
-         stub_name = spu_stub_name (input_section, sec, h, rel);
+         stub_name = spu_stub_name (sec, h, rel);
          if (stub_name == NULL)
            return FALSE;
 
@@ -1497,6 +1591,47 @@ spu_elf_relocate_section (bfd *output_bfd,
   return ret;
 }
 
+/* Adjust _SPUEAR_ syms to point at their overlay stubs.  */
+
+static bfd_boolean
+spu_elf_output_symbol_hook (struct bfd_link_info *info,
+                           const char *sym_name ATTRIBUTE_UNUSED,
+                           Elf_Internal_Sym *sym,
+                           asection *sym_sec ATTRIBUTE_UNUSED,
+                           struct elf_link_hash_entry *h)
+{
+  struct spu_link_hash_table *htab = spu_hash_table (info);
+
+  if (!info->relocatable
+      && htab->num_overlays != 0
+      && h != NULL
+      && (h->root.type == bfd_link_hash_defined
+         || h->root.type == bfd_link_hash_defweak)
+      && h->def_regular
+      && strncmp (h->root.root.string, "_SPUEAR_", 8) == 0)
+    {
+      static Elf_Internal_Rela zero_rel;
+      char *stub_name = spu_stub_name (h->root.u.def.section, h, &zero_rel);
+      struct spu_stub_hash_entry *sh;
+
+      if (stub_name == NULL)
+       return FALSE;
+      sh = (struct spu_stub_hash_entry *)
+       bfd_hash_lookup (&htab->stub_hash_table, stub_name, FALSE, FALSE);
+      free (stub_name);
+      if (sh == NULL)
+       return TRUE;
+      sym->st_shndx
+       = _bfd_elf_section_from_bfd_section (htab->stub->output_section->owner,
+                                            htab->stub->output_section);
+      sym->st_value = (htab->stub->output_section->vma
+                      + htab->stub->output_offset
+                      + sh->off);
+    }
+
+  return TRUE;
+}
+
 static int spu_plugin = 0;
 
 void
@@ -1732,10 +1867,12 @@ spu_elf_section_processing (bfd *abfd ATTRIBUTE_UNUSED,
 #define elf_backend_can_gc_sections    1
 
 #define bfd_elf32_bfd_reloc_type_lookup                spu_elf_reloc_type_lookup
+#define bfd_elf32_bfd_reloc_name_lookup        spu_elf_reloc_name_lookup
 #define elf_info_to_howto                      spu_elf_info_to_howto
 #define elf_backend_gc_mark_hook               spu_elf_gc_mark_hook
 #define elf_backend_relocate_section           spu_elf_relocate_section
 #define elf_backend_symbol_processing          spu_elf_backend_symbol_processing
+#define elf_backend_link_output_symbol_hook    spu_elf_output_symbol_hook
 #define bfd_elf32_new_section_hook             spu_elf_new_section_hook
 #define bfd_elf32_bfd_link_hash_table_create   spu_elf_link_hash_table_create
 #define bfd_elf32_bfd_link_hash_table_free     spu_elf_link_hash_table_free
This page took 0.028947 seconds and 4 git commands to generate.