2012-02-24 Luis Machado <lgustavo@codesourcery>
[deliverable/binutils-gdb.git] / bfd / elf32-s390.c
index 14c4cb0c998278ae16af273c0da4343318250dea..85a20bdc46bf9365eff367fd4505facb87a48a1e 100644 (file)
@@ -1,6 +1,6 @@
 /* IBM S/390-specific support for 32-bit ELF
-   Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
-   Free Software Foundation, Inc.
+   Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+   2011 Free Software Foundation, Inc.
    Contributed by Carl B. Pedersen and Martin Schwidefsky.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -693,13 +693,13 @@ struct elf_s390_obj_tdata
 #define is_s390_elf(bfd) \
   (bfd_get_flavour (bfd) == bfd_target_elf_flavour \
    && elf_tdata (bfd) != NULL \
-   && elf_object_id (bfd) == S390_ELF_TDATA)
+   && elf_object_id (bfd) == S390_ELF_DATA)
 
 static bfd_boolean
 elf_s390_mkobject (bfd *abfd)
 {
   return bfd_elf_allocate_object (abfd, sizeof (struct elf_s390_obj_tdata),
-                                 S390_ELF_TDATA);
+                                 S390_ELF_DATA);
 }
 
 static bfd_boolean
@@ -730,14 +730,15 @@ 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.  */
 
 #define elf_s390_hash_table(p) \
-  ((struct elf_s390_link_hash_table *) ((p)->hash))
+  (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
+  == S390_ELF_DATA ? ((struct elf_s390_link_hash_table *) ((p)->hash)) : NULL)
 
 /* Create an entry in an s390 ELF linker hash table.  */
 
@@ -786,7 +787,8 @@ elf_s390_link_hash_table_create (abfd)
     return NULL;
 
   if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc,
-                                     sizeof (struct elf_s390_link_hash_entry)))
+                                     sizeof (struct elf_s390_link_hash_entry),
+                                     S390_ELF_DATA))
     {
       free (ret);
       return NULL;
@@ -800,7 +802,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;
 }
@@ -821,18 +823,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;
 }
 
@@ -1302,12 +1296,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;
                }
@@ -1697,12 +1696,6 @@ allocate_dynrelocs (h, inf)
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
 
-  if (h->root.type == bfd_link_hash_warning)
-    /* When warning symbols are created, they **replace** the "real"
-       entry in the hash table, thus we never get to see the real
-       symbol in a hash traversal.  So look at it now.  */
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   info = (struct bfd_link_info *) inf;
   htab = elf_s390_hash_table (info);
 
@@ -1923,9 +1916,6 @@ readonly_dynrelocs (h, inf)
   struct elf_s390_link_hash_entry *eh;
   struct elf_s390_dyn_relocs *p;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   eh = (struct elf_s390_link_hash_entry *) h;
   for (p = eh->dyn_relocs; p != NULL; p = p->next)
     {
@@ -2293,15 +2283,8 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
        }
 
       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;
-       }
+       RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+                                        rel, relend, howto, contents);
 
       if (info->relocatable)
        continue;
@@ -2879,7 +2862,7 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
          continue;
 
        case R_390_TLS_LDO32:
-         if (info->shared)
+         if (info->shared || (input_section->flags & SEC_DEBUGGING))
            relocation -= dtpoff_base (info);
          else
            /* When converting LDO to LE, we must negate.  */
@@ -2936,11 +2919,18 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
 
              insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
              if ((insn & 0xff000fff) != 0x4d000000 &&
-                 (insn & 0xffff0000) != 0xc0e50000)
+                 (insn & 0xffff0000) != 0xc0e50000 &&
+                 (insn & 0xff000000) != 0x0d000000)
                invalid_tls_insn (input_bfd, input_section, rel);
              if (!info->shared && (h == NULL || h->dynindx == -1))
                {
-                 if ((insn & 0xff000000) == 0x4d000000)
+                 if ((insn & 0xff000000) == 0x0d000000)
+                   {
+                     /* GD->LE transition.
+                        basr rx, ry -> nopr r7 */
+                     insn = 0x07070000 | (insn & 0xffff);
+                   }
+                 else if ((insn & 0xff000000) == 0x4d000000)
                    {
                      /* GD->LE transition.
                         bas %r14,0(%rx,%r13) -> bc 0,0  */
@@ -2949,7 +2939,7 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
                  else
                    {
                      /* GD->LE transition.
-                        brasl %r14,_tls_get_addr@plt -> brcl 0,.  */
+                        brasl %r14,_tls_get_offset@plt -> brcl 0,.  */
                      insn = 0xc0040000;
                      bfd_put_16 (output_bfd, 0x0000,
                                  contents + rel->r_offset + 4);
@@ -2957,6 +2947,11 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
                }
              else
                {
+                 /* If basr is used in the pic case to invoke
+                    _tls_get_offset, something went wrong before.  */
+                 if ((insn & 0xff000000) == 0x0d000000)
+                   invalid_tls_insn (input_bfd, input_section, rel);
+
                  if ((insn & 0xff000000) == 0x4d000000)
                    {
                      /* GD->IE transition.
@@ -2983,9 +2978,17 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
 
                  insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
                  if ((insn & 0xff000fff) != 0x4d000000 &&
-                     (insn & 0xffff0000) != 0xc0e50000)
+                     (insn & 0xffff0000) != 0xc0e50000 &&
+                     (insn & 0xff000000) != 0x0d000000)
                    invalid_tls_insn (input_bfd, input_section, rel);
-                 if ((insn & 0xff000000) == 0x4d000000)
+
+                 if ((insn & 0xff000000) == 0x0d000000)
+                   {
+                     /* LD->LE transition.
+                        basr rx, ry -> nopr r7 */
+                     insn = 0x07070000 | (insn & 0xffff);
+                   }
+                 else if ((insn & 0xff000000) == 0x4d000000)
                    {
                      /* LD->LE transition.
                         bas %r14,0(%rx,%r13) -> bc 0,0  */
@@ -2994,7 +2997,7 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
                  else
                    {
                      /* LD->LE transition.
-                        brasl %r14,__tls_get_addr@plt -> brcl 0,. */
+                        brasl %r14,__tls_get_offset@plt -> brcl 0,. */
                      insn = 0xc0040000;
                      bfd_put_16 (output_bfd, 0x0000,
                                  contents + rel->r_offset + 4);
@@ -3013,7 +3016,9 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
         not process them.  */
       if (unresolved_reloc
          && !((input_section->flags & SEC_DEBUGGING) != 0
-              && h->def_dynamic))
+              && h->def_dynamic)
+         && _bfd_elf_section_offset (output_bfd, info, input_section,
+                                     rel->r_offset) != (bfd_vma) -1)
        (*_bfd_error_handler)
          (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
           input_bfd,
@@ -3463,7 +3468,7 @@ elf_s390_grok_prstatus (abfd, note)
        elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
 
        /* pr_pid */
-       elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24);
+       elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 24);
 
        /* pr_reg */
        offset = 72;
@@ -3486,10 +3491,18 @@ elf_s390_plt_sym_val (bfd_vma i, const asection *plt,
   return plt->vma + PLT_FIRST_ENTRY_SIZE + i * PLT_ENTRY_SIZE;
 }
 
+static bfd_boolean
+elf32_s390_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
+{
+  elf_elfheader (obfd)->e_flags |= elf_elfheader (ibfd)->e_flags;
+  return TRUE;
+}
+
 
 #define TARGET_BIG_SYM bfd_elf32_s390_vec
 #define TARGET_BIG_NAME        "elf32-s390"
 #define ELF_ARCH       bfd_arch_s390
+#define ELF_TARGET_ID  S390_ELF_DATA
 #define ELF_MACHINE_CODE EM_S390
 #define ELF_MACHINE_ALT1 EM_S390_OLD
 #define ELF_MAXPAGESIZE 0x1000
@@ -3509,6 +3522,8 @@ elf_s390_plt_sym_val (bfd_vma i, const asection *plt,
 #define bfd_elf32_bfd_reloc_type_lookup              elf_s390_reloc_type_lookup
 #define bfd_elf32_bfd_reloc_name_lookup elf_s390_reloc_name_lookup
 
+#define bfd_elf32_bfd_merge_private_bfd_data  elf32_s390_merge_private_bfd_data
+
 #define elf_backend_adjust_dynamic_symbol     elf_s390_adjust_dynamic_symbol
 #define elf_backend_check_relocs             elf_s390_check_relocs
 #define elf_backend_copy_indirect_symbol      elf_s390_copy_indirect_symbol
This page took 0.028872 seconds and 4 git commands to generate.