* config.sub, config.guess: Update from upstream sources.
[deliverable/binutils-gdb.git] / bfd / elf32-s390.c
index dc4e5b0fbd42fa8d28fae1912a539cc1a38fd7ea..b887640640d01865d5f40955d22a1948adeddab4 100644 (file)
@@ -1,5 +1,5 @@
 /* IBM S/390-specific support for 32-bit ELF
-   Copyright 2000, 2001, 2002, 2003, 2004, 2005
+   Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006
    Free Software Foundation, Inc.
    Contributed by Carl B. Pedersen and Martin Schwidefsky.
 
@@ -41,7 +41,7 @@ static bfd_boolean create_got_section
 static bfd_boolean elf_s390_create_dynamic_sections
   PARAMS((bfd *, struct bfd_link_info *));
 static void elf_s390_copy_indirect_symbol
-  PARAMS ((const struct elf_backend_data *, struct elf_link_hash_entry *,
+  PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *,
           struct elf_link_hash_entry *));
 static bfd_boolean elf_s390_check_relocs
   PARAMS ((bfd *, struct bfd_link_info *, asection *,
@@ -73,8 +73,6 @@ static enum elf_reloc_type_class elf_s390_reloc_type_class
   PARAMS ((const Elf_Internal_Rela *));
 static bfd_boolean elf_s390_finish_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *));
-static bfd_boolean elf_s390_mkobject
-  PARAMS ((bfd *));
 static bfd_boolean elf_s390_object_p
   PARAMS ((bfd *));
 static bfd_boolean elf_s390_grok_prstatus
@@ -351,7 +349,8 @@ elf_s390_info_to_howto (abfd, cache_ptr, dst)
      arelent *cache_ptr;
      Elf_Internal_Rela *dst;
 {
-  switch (ELF32_R_TYPE(dst->r_info))
+  unsigned int r_type = ELF32_R_TYPE(dst->r_info);
+  switch (r_type)
     {
     case R_390_GNU_VTINHERIT:
       cache_ptr->howto = &elf32_s390_vtinherit_howto;
@@ -362,8 +361,13 @@ elf_s390_info_to_howto (abfd, cache_ptr, dst)
       break;
 
     default:
-      BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_390_max);
-      cache_ptr->howto = &elf_howto_table[ELF32_R_TYPE(dst->r_info)];
+      if (r_type >= sizeof (elf_howto_table) / sizeof (elf_howto_table[0]))
+       {
+         (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
+                                abfd, (int) r_type);
+         r_type = R_390_NONE;
+       }
+      cache_ptr->howto = &elf_howto_table[r_type];
     }
 }
 
@@ -672,14 +676,16 @@ struct elf_s390_obj_tdata
   (elf_s390_tdata (abfd)->local_got_tls_type)
 
 static bfd_boolean
-elf_s390_mkobject (abfd)
-     bfd *abfd;
+elf_s390_mkobject (bfd *abfd)
 {
-  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 TRUE;
+    {
+      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);
 }
 
 static bfd_boolean
@@ -765,7 +771,8 @@ elf_s390_link_hash_table_create (abfd)
   if (ret == NULL)
     return NULL;
 
-  if (! _bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc))
+  if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc,
+                                     sizeof (struct elf_s390_link_hash_entry)))
     {
       free (ret);
       return NULL;
@@ -849,8 +856,8 @@ elf_s390_create_dynamic_sections (dynobj, info)
 /* Copy the extra info we tack onto an elf_link_hash_entry.  */
 
 static void
-elf_s390_copy_indirect_symbol (bed, dir, ind)
-     const struct elf_backend_data *bed;
+elf_s390_copy_indirect_symbol (info, dir, ind)
+     struct bfd_link_info *info;
      struct elf_link_hash_entry *dir, *ind;
 {
   struct elf_s390_link_hash_entry *edir, *eind;
@@ -865,10 +872,7 @@ elf_s390_copy_indirect_symbol (bed, dir, ind)
          struct elf_s390_dyn_relocs **pp;
          struct elf_s390_dyn_relocs *p;
 
-         if (ind->root.type == bfd_link_hash_indirect)
-           abort ();
-
-         /* Add reloc counts against the weak sym to the strong sym
+         /* Add reloc counts against the indirect sym to the direct sym
             list.  Merge any entries against the same section.  */
          for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
            {
@@ -912,7 +916,7 @@ elf_s390_copy_indirect_symbol (bed, dir, ind)
       dir->needs_plt |= ind->needs_plt;
     }
   else
-    _bfd_elf_link_hash_copy_indirect (bed, dir, ind);
+    _bfd_elf_link_hash_copy_indirect (info, dir, ind);
 }
 
 static int
@@ -1269,7 +1273,7 @@ elf_s390_check_relocs (abfd, info, sec, relocs)
                  if (name == NULL)
                    return FALSE;
 
-                 if (strncmp (name, ".rela", 5) != 0
+                 if (! CONST_STRNEQ (name, ".rela")
                      || strcmp (bfd_get_section_name (abfd, sec),
                                 name + 5) != 0)
                    {
@@ -1313,14 +1317,15 @@ elf_s390_check_relocs (abfd, info, sec, relocs)
                     We really need local syms available to do this
                     easily.  Oh well.  */
                  asection *s;
+                 void *vpp;
 
                  s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
                                                 sec, r_symndx);
                  if (s == NULL)
                    return FALSE;
 
-                 head = ((struct elf_s390_dyn_relocs **)
-                         &elf_section_data (s)->local_dynrel);
+                 vpp = &elf_section_data (s)->local_dynrel;
+                 head = (struct elf_s390_dyn_relocs **) vpp;
                }
 
              p = *head;
@@ -1677,6 +1682,13 @@ elf_s390_adjust_dynamic_symbol (info, h)
        }
     }
 
+  if (h->size == 0)
+    {
+      (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"),
+                            h->root.root.string);
+      return TRUE;
+    }
+
   /* We must allocate the symbol in our .dynbss section, which will
      become part of the .bss section of the executable.  There will be
      an entry for this symbol in the .dynsym section.  The dynamic
@@ -1897,9 +1909,21 @@ allocate_dynrelocs (h, inf)
 
       /* Also discard relocs on undefined weak syms with non-default
         visibility.  */
-      if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+      if (eh->dyn_relocs != NULL
          && h->root.type == bfd_link_hash_undefweak)
-       eh->dyn_relocs = NULL;
+       {
+         if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+           eh->dyn_relocs = NULL;
+
+         /* Make sure undefined weak symbols are output as a dynamic
+            symbol in PIEs.  */
+         else if (h->dynindx == -1
+                  && !h->forced_local)
+           {
+             if (! bfd_elf_link_record_dynamic_symbol (info, h))
+               return FALSE;
+           }
+       }
     }
   else if (ELIMINATE_COPY_RELOCS)
     {
@@ -2025,10 +2049,7 @@ elf_s390_size_dynamic_sections (output_bfd, info)
        {
          struct elf_s390_dyn_relocs *p;
 
-         for (p = *((struct elf_s390_dyn_relocs **)
-                    &elf_section_data (s)->local_dynrel);
-              p != NULL;
-              p = p->next)
+         for (p = elf_section_data (s)->local_dynrel; p != NULL; p = p->next)
            {
              if (!bfd_is_abs_section (p->sec)
                  && bfd_is_abs_section (p->sec->output_section))
@@ -2099,12 +2120,13 @@ elf_s390_size_dynamic_sections (output_bfd, info)
 
       if (s == htab->splt
          || s == htab->sgot
-         || s == htab->sgotplt)
+         || s == htab->sgotplt
+         || s == htab->sdynbss)
        {
          /* Strip this section if we don't need it; see the
             comment below.  */
        }
-      else if (strncmp (bfd_get_section_name (dynobj, s), ".rela", 5) == 0)
+      else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela"))
        {
          if (s->size != 0)
            relocs = TRUE;
@@ -2135,6 +2157,9 @@ elf_s390_size_dynamic_sections (output_bfd, info)
          continue;
        }
 
+      if ((s->flags & SEC_HAS_CONTENTS) == 0)
+       continue;
+
       /* Allocate memory for the section contents.  We use bfd_zalloc
         here in case unused entries are not reclaimed before the
         section's contents are written out.  This should not happen,
@@ -2243,6 +2268,7 @@ invalid_tls_insn (input_bfd, input_section, rel)
      input_section,
      (long) rel->r_offset,
      howto->name);
+  bfd_set_error (bfd_error_bad_value);
 }
 
 /* Relocate a 390 ELF section.  */
@@ -2901,7 +2927,7 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
          continue;
 
        case R_390_TLS_LDO32:
-         if (info->shared || (input_section->flags & SEC_CODE) == 0)
+         if (info->shared)
            relocation -= dtpoff_base (info);
          else
            /* When converting LDO to LE, we must negate.  */
@@ -2957,16 +2983,44 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
              unsigned int insn;
 
              insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
-             if ((insn & 0xff000fff) != 0x4d000000)
+             if ((insn & 0xff000fff) != 0x4d000000 &&
+                 (insn & 0xffff0000) != 0xc0e50000)
                invalid_tls_insn (input_bfd, input_section, rel);
              if (!info->shared && (h == NULL || h->dynindx == -1))
-               /* GD->LE transition.
-                  bas %r14,0(%rx,%r13) -> bc 0,0  */
-               insn = 0x47000000;
+               {
+                 if ((insn & 0xff000000) == 0x4d000000)
+                   {
+                     /* GD->LE transition.
+                        bas %r14,0(%rx,%r13) -> bc 0,0  */
+                     insn = 0x47000000;
+                   }
+                 else
+                   {
+                     /* GD->LE transition.
+                        brasl %r14,_tls_get_addr@plt -> brcl 0,.  */
+                     insn = 0xc0040000;
+                     bfd_put_16 (output_bfd, 0x0000,
+                                 contents + rel->r_offset + 4);
+                   }
+               }
              else
-               /* GD->IE transition.
-                  bas %r14,0(%rx,%r13) -> l %r2,0(%r2,%r12)  */
-               insn = 0x5822c000;
+               {
+                 if ((insn & 0xff000000) == 0x4d000000)
+                   {
+                     /* GD->IE transition.
+                        bas %r14,0(%rx,%r13) -> l %r2,0(%r2,%r12)  */
+                     insn = 0x5822c000;
+                   }
+                 else
+                   {
+                     /* GD->IE transition.
+                        brasl %r14,__tls_get_addr@plt ->
+                               l %r2,0(%r2,%r12) ; bcr 0,0 */
+                     insn = 0x5822c000;
+                     bfd_put_16 (output_bfd, 0x0700,
+                                 contents + rel->r_offset + 4);
+                   }
+               }
              bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
            }
          else if (r_type == R_390_TLS_LDCALL)
@@ -2976,11 +3030,23 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
                  unsigned int insn;
 
                  insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
-                 if ((insn & 0xff000fff) != 0x4d000000)
+                 if ((insn & 0xff000fff) != 0x4d000000 &&
+                     (insn & 0xffff0000) != 0xc0e50000)
                    invalid_tls_insn (input_bfd, input_section, rel);
-                 /* LD->LE transition.
-                    bas %r14,0(%rx,%r13) -> bc 0,0  */
-                 insn = 0x47000000;
+                 if ((insn & 0xff000000) == 0x4d000000)
+                   {
+                     /* LD->LE transition.
+                        bas %r14,0(%rx,%r13) -> bc 0,0  */
+                     insn = 0x47000000;
+                   }
+                 else
+                   {
+                     /* LD->LE transition.
+                        brasl %r14,__tls_get_addr@plt -> brcl 0,. */
+                     insn = 0xc0040000;
+                     bfd_put_16 (output_bfd, 0x0000,
+                                 contents + rel->r_offset + 4);
+                   }
                  bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
                }
            }
@@ -2997,10 +3063,11 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
          && !((input_section->flags & SEC_DEBUGGING) != 0
               && h->def_dynamic))
        (*_bfd_error_handler)
-         (_("%B(%A+0x%lx): unresolvable relocation against symbol `%s'"),
+         (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
           input_bfd,
           input_section,
           (long) rel->r_offset,
+          howto->name,
           h->root.root.string);
 
       if (r_type == R_390_20
@@ -3284,8 +3351,8 @@ elf_s390_finish_dynamic_symbol (output_bfd, info, h, sym)
 
   /* Mark some specially defined symbols as absolute.  */
   if (strcmp (h->root.root.string, "_DYNAMIC") == 0
-      || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
-      || strcmp (h->root.root.string, "_PROCEDURE_LINKAGE_TABLE_") == 0)
+      || h == htab->elf.hgot
+      || h == htab->elf.hplt)
     sym->st_shndx = SHN_ABS;
 
   return TRUE;
This page took 0.030367 seconds and 4 git commands to generate.