]> oss.titaniummirror.com Git - msp430-binutils.git/blobdiff - bfd/elf32-s390.c
Imported binutils-2.20
[msp430-binutils.git] / bfd / elf32-s390.c
index 67cc059c55903110b1bf2b7ebd2362234d3945eb..094a8dc38dc30b5287d5db137724f20ce172d20d 100644 (file)
@@ -1,5 +1,5 @@
 /* IBM S/390-specific support for 32-bit ELF
-   Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
    Contributed by Carl B. Pedersen and Martin Schwidefsky.
 
@@ -674,11 +674,13 @@ struct elf_s390_link_hash_entry
 #define elf_s390_hash_entry(ent) \
   ((struct elf_s390_link_hash_entry *)(ent))
 
+/* NOTE: Keep this structure in sync with
+   the one declared in elf64-s390.c.  */
 struct elf_s390_obj_tdata
 {
   struct elf_obj_tdata root;
 
-  /* tls_type for each local got entry.  */
+  /* TLS type for each local got entry.  */
   char *local_got_tls_type;
 };
 
@@ -688,17 +690,16 @@ struct elf_s390_obj_tdata
 #define elf_s390_local_got_tls_type(abfd) \
   (elf_s390_tdata (abfd)->local_got_tls_type)
 
+#define is_s390_elf(bfd) \
+  (bfd_get_flavour (bfd) == bfd_target_elf_flavour \
+   && elf_tdata (bfd) != NULL \
+   && elf_object_id (bfd) == S390_ELF_TDATA)
+
 static bfd_boolean
 elf_s390_mkobject (bfd *abfd)
 {
-  if (abfd->tdata.any == NULL)
-    {
-      bfd_size_type amt = sizeof (struct elf_s390_obj_tdata);
-      abfd->tdata.any = bfd_zalloc (abfd, amt);
-      if (abfd->tdata.any == NULL)
-       return FALSE;
-    }
-  return bfd_elf_mkobject (abfd);
+  return bfd_elf_allocate_object (abfd, sizeof (struct elf_s390_obj_tdata),
+                                 S390_ELF_TDATA);
 }
 
 static bfd_boolean
@@ -729,8 +730,8 @@ struct elf_s390_link_hash_table
     bfd_vma offset;
   } tls_ldm_got;
 
-  /* Small local sym to section mapping cache.  */
-  struct sym_sec_cache sym_sec;
+  /* Small local sym cache.  */
+  struct sym_cache sym_cache;
 };
 
 /* Get the s390 ELF linker hash table from a link_info structure.  */
@@ -799,7 +800,7 @@ elf_s390_link_hash_table_create (abfd)
   ret->sdynbss = NULL;
   ret->srelbss = NULL;
   ret->tls_ldm_got.refcount = 0;
-  ret->sym_sec.abfd = NULL;
+  ret->sym_cache.abfd = NULL;
 
   return &ret->elf.root;
 }
@@ -820,18 +821,10 @@ create_got_section (dynobj, info)
   htab = elf_s390_hash_table (info);
   htab->sgot = bfd_get_section_by_name (dynobj, ".got");
   htab->sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
-  if (!htab->sgot || !htab->sgotplt)
+  htab->srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+  if (!htab->sgot || !htab->sgotplt || !htab->srelgot)
     abort ();
 
-  htab->srelgot = bfd_make_section_with_flags (dynobj, ".rela.got",
-                                              (SEC_ALLOC | SEC_LOAD
-                                               | SEC_HAS_CONTENTS
-                                               | SEC_IN_MEMORY
-                                               | SEC_LINKER_CREATED
-                                               | SEC_READONLY));
-  if (htab->srelgot == NULL
-      || ! bfd_set_section_alignment (dynobj, htab->srelgot, 2))
-    return FALSE;
   return TRUE;
 }
 
@@ -982,8 +975,10 @@ elf_s390_check_relocs (abfd, info, sec, relocs)
   if (info->relocatable)
     return TRUE;
 
+  BFD_ASSERT (is_s390_elf (abfd));
+
   htab = elf_s390_hash_table (info);
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  symtab_hdr = &elf_symtab_hdr (abfd);
   sym_hashes = elf_sym_hashes (abfd);
   local_got_refcounts = elf_local_got_refcounts (abfd);
 
@@ -1258,7 +1253,7 @@ elf_s390_check_relocs (abfd, info, sec, relocs)
                    && ELF32_R_TYPE (rel->r_info) != R_390_PC32DBL
                    && ELF32_R_TYPE (rel->r_info) != R_390_PC32)
                   || (h != NULL
-                      && (! info->symbolic
+                      && (! SYMBOLIC_BIND (info, h)
                           || h->root.type == bfd_link_hash_defweak
                           || !h->def_regular))))
              || (ELIMINATE_COPY_RELOCS
@@ -1276,46 +1271,14 @@ elf_s390_check_relocs (abfd, info, sec, relocs)
                 this reloc.  */
              if (sreloc == NULL)
                {
-                 const char *name;
-                 bfd *dynobj;
-
-                 name = (bfd_elf_string_from_elf_section
-                         (abfd,
-                          elf_elfheader (abfd)->e_shstrndx,
-                          elf_section_data (sec)->rel_hdr.sh_name));
-                 if (name == NULL)
-                   return FALSE;
-
-                 if (! CONST_STRNEQ (name, ".rela")
-                     || strcmp (bfd_get_section_name (abfd, sec),
-                                name + 5) != 0)
-                   {
-                     (*_bfd_error_handler)
-                       (_("%B: bad relocation section name `%s\'"),
-                        abfd, name);
-                   }
-
                  if (htab->elf.dynobj == NULL)
                    htab->elf.dynobj = abfd;
 
-                 dynobj = htab->elf.dynobj;
-                 sreloc = bfd_get_section_by_name (dynobj, name);
+                 sreloc = _bfd_elf_make_dynamic_reloc_section
+                   (sec, htab->elf.dynobj, 2, abfd, /*rela?*/ TRUE);
+
                  if (sreloc == NULL)
-                   {
-                     flagword flags;
-
-                     flags = (SEC_HAS_CONTENTS | SEC_READONLY
-                              | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-                     if ((sec->flags & SEC_ALLOC) != 0)
-                       flags |= SEC_ALLOC | SEC_LOAD;
-                     sreloc = bfd_make_section_with_flags (dynobj,
-                                                           name,
-                                                           flags);
-                     if (sreloc == NULL
-                         || ! bfd_set_section_alignment (dynobj, sreloc, 2))
-                       return FALSE;
-                   }
-                 elf_section_data (sec)->sreloc = sreloc;
+                   return FALSE;
                }
 
              /* If this is a global symbol, we count the number of
@@ -1331,12 +1294,17 @@ elf_s390_check_relocs (abfd, info, sec, relocs)
                     easily.  Oh well.  */
                  asection *s;
                  void *vpp;
+                 Elf_Internal_Sym *isym;
 
-                 s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
-                                                sec, r_symndx);
-                 if (s == NULL)
+                 isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+                                               abfd, r_symndx);
+                 if (isym == NULL)
                    return FALSE;
 
+                 s = bfd_section_from_elf_index (abfd, isym->st_shndx);
+                 if (s == NULL)
+                   s = sec;
+
                  vpp = &elf_section_data (s)->local_dynrel;
                  head = (struct elf_s390_dyn_relocs **) vpp;
                }
@@ -1376,7 +1344,9 @@ elf_s390_check_relocs (abfd, info, sec, relocs)
          /* This relocation describes which C++ vtable entries are actually
             used.  Record for later use during GC.  */
        case R_390_GNU_VTENTRY:
-         if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+         BFD_ASSERT (h != NULL);
+         if (h != NULL
+             && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
            return FALSE;
          break;
 
@@ -1422,9 +1392,12 @@ elf_s390_gc_sweep_hook (bfd *abfd,
   bfd_signed_vma *local_got_refcounts;
   const Elf_Internal_Rela *rel, *relend;
 
+  if (info->relocatable)
+    return TRUE;
+
   elf_section_data (sec)->local_dynrel = NULL;
 
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  symtab_hdr = &elf_symtab_hdr (abfd);
   sym_hashes = elf_sym_hashes (abfd);
   local_got_refcounts = elf_local_got_refcounts (abfd);
 
@@ -1590,11 +1563,9 @@ elf_s390_adjust_dynamic_symbol (info, h)
       || h->needs_plt)
     {
       if (h->plt.refcount <= 0
-         || (! info->shared
-             && !h->def_dynamic
-             && !h->ref_dynamic
-             && h->root.type != bfd_link_hash_undefweak
-             && h->root.type != bfd_link_hash_undefined))
+         || SYMBOL_CALLS_LOCAL (info, h)
+         || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+             && h->root.type != bfd_link_hash_undefweak))
        {
          /* This case can occur if we saw a PLT32 reloc in an input
             file, but the symbol was never referred to by a dynamic
@@ -1733,9 +1704,7 @@ allocate_dynrelocs (h, inf)
   htab = elf_s390_hash_table (info);
 
   if (htab->elf.dynamic_sections_created
-      && h->plt.refcount > 0
-      && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
-         || h->root.type != bfd_link_hash_undefweak))
+      && h->plt.refcount > 0)
     {
       /* Make sure this symbol is output as a dynamic symbol.
         Undefined weak syms won't yet be marked as dynamic.  */
@@ -1864,7 +1833,7 @@ allocate_dynrelocs (h, inf)
 
   if (info->shared)
     {
-      if (SYMBOL_REFERENCES_LOCAL (info, h))
+      if (SYMBOL_CALLS_LOCAL (info, h))
        {
          struct elf_s390_dyn_relocs **pp;
 
@@ -2014,7 +1983,7 @@ elf_s390_size_dynamic_sections (output_bfd, info)
       Elf_Internal_Shdr *symtab_hdr;
       asection *srela;
 
-      if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
+      if (! is_s390_elf (ibfd))
        continue;
 
       for (s = ibfd->sections; s != NULL; s = s->next)
@@ -2045,7 +2014,7 @@ elf_s390_size_dynamic_sections (output_bfd, info)
       if (!local_got)
        continue;
 
-      symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
+      symtab_hdr = &elf_symtab_hdr (ibfd);
       locsymcount = symtab_hdr->sh_info;
       end_local_got = local_got + locsymcount;
       local_tls_type = elf_s390_local_got_tls_type (ibfd);
@@ -2264,8 +2233,10 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
   Elf_Internal_Rela *rel;
   Elf_Internal_Rela *relend;
 
+  BFD_ASSERT (is_s390_elf (input_bfd));
+
   htab = elf_s390_hash_table (info);
-  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+  symtab_hdr = &elf_symtab_hdr (input_bfd);
   sym_hashes = elf_sym_hashes (input_bfd);
   local_got_offsets = elf_local_got_offsets (input_bfd);
 
@@ -2386,10 +2357,7 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
              dyn = htab->elf.dynamic_sections_created;
              if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
                  || (info->shared
-                     && (info->symbolic
-                         || h->dynindx == -1
-                         || h->forced_local)
-                     && h->def_regular)
+                     && SYMBOL_REFERENCES_LOCAL (info, h))
                  || (ELF_ST_VISIBILITY (h->other)
                      && h->root.type == bfd_link_hash_undefweak))
                {
@@ -2559,8 +2527,7 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
                    && r_type != R_390_PC16DBL
                    && r_type != R_390_PC32DBL
                    && r_type != R_390_PC32)
-                  || (h != NULL
-                      && !SYMBOL_REFERENCES_LOCAL (info, h))))
+                  || !SYMBOL_CALLS_LOCAL (info, h)))
              || (ELIMINATE_COPY_RELOCS
                  && !info->shared
                  && h != NULL
@@ -2602,7 +2569,7 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
                           || r_type == R_390_PC32DBL
                           || r_type == R_390_PC32
                           || !info->shared
-                          || !info->symbolic
+                          || !SYMBOLIC_BIND (info, h)
                           || !h->def_regular))
                {
                  outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
@@ -3284,11 +3251,10 @@ elf_s390_finish_dynamic_symbol (output_bfd, info, h, sym)
         The entry in the global offset table will already have been
         initialized in the relocate_section function.  */
       if (info->shared
-         && (info->symbolic
-             || h->dynindx == -1
-             || h->forced_local)
-         && h->def_regular)
+         && SYMBOL_REFERENCES_LOCAL (info, h))
        {
+         if (!h->def_regular)
+           return FALSE;
          BFD_ASSERT((h->got.offset & 1) != 0);
          rela.r_info = ELF32_R_INFO (0, R_390_RELATIVE);
          rela.r_addend = (h->root.u.def.value