S/390: Add support for pgste marker
[deliverable/binutils-gdb.git] / bfd / elf64-s390.c
index 1c3769976e65b20b84bf1bf454f66ba0057de32a..1af1200f6cdf4cc6653f1de2e1586b1092338b4d 100644 (file)
@@ -1,5 +1,5 @@
 /* IBM S/390-specific support for 64-bit ELF
-   Copyright (C) 2000-2015 Free Software Foundation, Inc.
+   Copyright (C) 2000-2017 Free Software Foundation, Inc.
    Contributed Martin Schwidefsky (schwidefsky@de.ibm.com).
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -25,6 +25,8 @@
 #include "libbfd.h"
 #include "elf-bfd.h"
 #include "elf/s390.h"
+#include "elf-s390.h"
+#include <stdarg.h>
 
 /* In case we're on a 32-bit machine, construct a 64-bit "-1" value
    from smaller values.  Start with zero, widen, *then* decrement.  */
@@ -337,10 +339,10 @@ elf_s390_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
        && strcasecmp (elf_howto_table[i].name, r_name) == 0)
       return &elf_howto_table[i];
 
-    if (strcasecmp (elf64_s390_vtinherit_howto.name, r_name) == 0)
-      return &elf64_s390_vtinherit_howto;
-    if (strcasecmp (elf64_s390_vtentry_howto.name, r_name) == 0)
-      return &elf64_s390_vtentry_howto;
+  if (strcasecmp (elf64_s390_vtinherit_howto.name, r_name) == 0)
+    return &elf64_s390_vtinherit_howto;
+  if (strcasecmp (elf64_s390_vtentry_howto.name, r_name) == 0)
+    return &elf64_s390_vtentry_howto;
 
   return NULL;
 }
@@ -367,8 +369,9 @@ elf_s390_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
     default:
       if (r_type >= sizeof (elf_howto_table) / sizeof (elf_howto_table[0]))
        {
-         (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
-                                abfd, (int) r_type);
+         /* xgettext:c-format */
+         _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];
@@ -492,8 +495,8 @@ elf_s390_is_local_label_name (bfd *abfd, const char *name)
 
    The GOT holds the address in the PLT to be executed.
    The loader then gets:
-   24(15) =  Pointer to the structure describing the object.
-   28(15) =  Offset in symbol table
+   48(15) =  Pointer to the structure describing the object.
+   56(15) =  Offset in symbol table
    The loader  must  then find the module where the function is
    and insert the address in the GOT.
 
@@ -649,8 +652,6 @@ struct elf_s390_link_hash_table
   struct elf_link_hash_table elf;
 
   /* Short-cuts to get to dynamic linker sections.  */
-  asection *sdynbss;
-  asection *srelbss;
   asection *irelifunc;
 
   union {
@@ -660,13 +661,16 @@ struct elf_s390_link_hash_table
 
   /* Small local sym cache.  */
   struct sym_cache sym_cache;
+
+  /* Options passed from the linker.  */
+  struct s390_elf_params *params;
 };
 
 /* Get the s390 ELF linker hash table from a link_info structure.  */
 
-#define elf_s390_hash_table(p) \
-  (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
-  == S390_ELF_DATA ? ((struct elf_s390_link_hash_table *) ((p)->hash)) : NULL)
+#define elf_s390_hash_table(p)                                         \
+  (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash))      \
+   == S390_ELF_DATA ? ((struct elf_s390_link_hash_table *) ((p)->hash)) : NULL)
 
 #define ELF64 1
 #include "elf-s390-common.c"
@@ -728,63 +732,6 @@ elf_s390_link_hash_table_create (bfd *abfd)
   return &ret->elf.root;
 }
 
-/* Create .got, .gotplt, and .rela.got sections in DYNOBJ, and set up
-   shortcuts to them in our hash table.  */
-
-static bfd_boolean
-create_got_section (bfd *dynobj,
-                   struct bfd_link_info *info)
-{
-  struct elf_s390_link_hash_table *htab;
-
-  if (! _bfd_elf_create_got_section (dynobj, info))
-    return FALSE;
-
-  htab = elf_s390_hash_table (info);
-  if (htab == NULL)
-    return FALSE;
-
-  htab->elf.sgot = bfd_get_linker_section (dynobj, ".got");
-  htab->elf.sgotplt = bfd_get_linker_section (dynobj, ".got.plt");
-  htab->elf.srelgot = bfd_get_linker_section (dynobj, ".rela.got");
-  if (!htab->elf.sgot || !htab->elf.sgotplt || !htab->elf.srelgot)
-    abort ();
-  return TRUE;
-}
-
-/* Create .plt, .rela.plt, .got, .got.plt, .rela.got, .dynbss, and
-   .rela.bss sections in DYNOBJ, and set up shortcuts to them in our
-   hash table.  */
-
-static bfd_boolean
-elf_s390_create_dynamic_sections (bfd *dynobj,
-                                 struct bfd_link_info *info)
-{
-  struct elf_s390_link_hash_table *htab;
-
-  htab = elf_s390_hash_table (info);
-  if (htab == NULL)
-    return FALSE;
-
-  if (!htab->elf.sgot && !create_got_section (dynobj, info))
-    return FALSE;
-
-  if (!_bfd_elf_create_dynamic_sections (dynobj, info))
-    return FALSE;
-
-  htab->elf.splt = bfd_get_linker_section (dynobj, ".plt");
-  htab->elf.srelplt = bfd_get_linker_section (dynobj, ".rela.plt");
-  htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss");
-  if (!bfd_link_pic (info))
-    htab->srelbss = bfd_get_linker_section (dynobj, ".rela.bss");
-
-  if (!htab->elf.splt || !htab->elf.srelplt || !htab->sdynbss
-      || (!bfd_link_pic (info) && !htab->srelbss))
-    abort ();
-
-  return TRUE;
-}
-
 /* Copy the extra info we tack onto an elf_link_hash_entry.  */
 
 static void
@@ -842,7 +789,8 @@ elf_s390_copy_indirect_symbol (struct bfd_link_info *info,
       /* If called to transfer flags for a weakdef during processing
         of elf_adjust_dynamic_symbol, don't copy non_got_ref.
         We clear it ourselves for ELIMINATE_COPY_RELOCS.  */
-      dir->ref_dynamic |= ind->ref_dynamic;
+      if (dir->versioned != versioned_hidden)
+       dir->ref_dynamic |= ind->ref_dynamic;
       dir->ref_regular |= ind->ref_regular;
       dir->ref_regular_nonweak |= ind->ref_regular_nonweak;
       dir->needs_plt |= ind->needs_plt;
@@ -923,9 +871,9 @@ elf_s390_check_relocs (bfd *abfd,
 
       if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
        {
-         (*_bfd_error_handler) (_("%B: bad symbol index: %d"),
-                                abfd,
-                                r_symndx);
+         /* xgettext:c-format */
+         _bfd_error_handler (_("%B: bad symbol index: %d"),
+                             abfd, r_symndx);
          return FALSE;
        }
 
@@ -967,7 +915,7 @@ elf_s390_check_relocs (bfd *abfd,
 
          /* PR15323, ref flags aren't set for references in the same
             object.  */
-         h->root.non_ir_ref = 1;
+         h->root.non_ir_ref_regular = 1;
        }
 
       /* Create got section and local_got_refcounts array if they
@@ -1014,7 +962,7 @@ elf_s390_check_relocs (bfd *abfd,
            {
              if (htab->elf.dynobj == NULL)
                htab->elf.dynobj = abfd;
-             if (!create_got_section (htab->elf.dynobj, info))
+             if (!_bfd_elf_create_got_section (htab->elf.dynobj, info))
                return FALSE;
            }
        }
@@ -1040,9 +988,6 @@ elf_s390_check_relocs (bfd *abfd,
 
       switch (r_type)
        {
-       case R_390_GOTOFF16:
-       case R_390_GOTOFF32:
-       case R_390_GOTOFF64:
        case R_390_GOTPC:
        case R_390_GOTPCDBL:
          /* These relocs do not need a GOT slot.  They just load the
@@ -1050,6 +995,12 @@ elf_s390_check_relocs (bfd *abfd,
             the GOT.  Since the GOT pointer has been set up above we
             are done.  */
          break;
+       case R_390_GOTOFF16:
+       case R_390_GOTOFF32:
+       case R_390_GOTOFF64:
+         if (h == NULL || !s390_is_ifunc_symbol_p (h) || !h->def_regular)
+           break;
+         /* Fall through.  */
 
        case R_390_PLT12DBL:
        case R_390_PLT16DBL:
@@ -1161,7 +1112,8 @@ elf_s390_check_relocs (bfd *abfd,
            {
              if (old_tls_type == GOT_NORMAL || tls_type == GOT_NORMAL)
                {
-                 (*_bfd_error_handler)
+                 _bfd_error_handler
+                   /* xgettext:c-format */
                    (_("%B: `%s' accessed both as normal and thread local symbol"),
                     abfd, h->root.root.string);
                  return FALSE;
@@ -1205,7 +1157,7 @@ elf_s390_check_relocs (bfd *abfd,
        case R_390_PC32:
        case R_390_PC32DBL:
        case R_390_PC64:
-         if (h != NULL)
+         if (h != NULL && bfd_link_executable (info))
            {
              /* If this reloc is in a read-only section, we might
                 need a copy reloc.  We can't check reliably at this
@@ -1462,6 +1414,18 @@ elf_s390_gc_sweep_hook (bfd *abfd,
          if (htab->tls_ldm_got.refcount > 0)
            htab->tls_ldm_got.refcount -= 1;
          break;
+       case R_390_GOTOFF16:
+       case R_390_GOTOFF32:
+       case R_390_GOTOFF64:
+         if (h != NULL && s390_is_ifunc_symbol_p (h) && h->def_regular)
+           {
+             h->plt.refcount--;
+             break;
+           }
+
+       case R_390_GOTPC:
+       case R_390_GOTPCDBL:
+         break;
 
        case R_390_TLS_GD64:
        case R_390_TLS_IE64:
@@ -1474,11 +1438,6 @@ elf_s390_gc_sweep_hook (bfd *abfd,
        case R_390_GOT20:
        case R_390_GOT32:
        case R_390_GOT64:
-       case R_390_GOTOFF16:
-       case R_390_GOTOFF32:
-       case R_390_GOTOFF64:
-       case R_390_GOTPC:
-       case R_390_GOTPCDBL:
        case R_390_GOTENT:
          if (h != NULL)
            {
@@ -1587,11 +1546,51 @@ elf_s390_adjust_dynamic_symbol (struct bfd_link_info *info,
                                struct elf_link_hash_entry *h)
 {
   struct elf_s390_link_hash_table *htab;
-  asection *s;
+  asection *s, *srel;
 
   /* STT_GNU_IFUNC symbol must go through PLT. */
   if (s390_is_ifunc_symbol_p (h))
-    return TRUE;
+    {
+      /* All local STT_GNU_IFUNC references must be treated as local
+        calls via local PLT.  */
+      if (h->ref_regular && SYMBOL_CALLS_LOCAL (info, h))
+       {
+         bfd_size_type pc_count = 0, count = 0;
+         struct elf_dyn_relocs **pp;
+         struct elf_s390_link_hash_entry *eh;
+         struct elf_dyn_relocs *p;
+
+         eh = (struct elf_s390_link_hash_entry *) h;
+         for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+           {
+             pc_count += p->pc_count;
+             p->count -= p->pc_count;
+             p->pc_count = 0;
+             count += p->count;
+             if (p->count == 0)
+               *pp = p->next;
+             else
+               pp = &p->next;
+           }
+
+         if (pc_count || count)
+           {
+             h->needs_plt = 1;
+             h->non_got_ref = 1;
+             if (h->plt.refcount <= 0)
+               h->plt.refcount = 1;
+             else
+               h->plt.refcount += 1;
+           }
+       }
+
+      if (h->plt.refcount <= 0)
+       {
+         h->plt.offset = (bfd_vma) -1;
+         h->needs_plt = 0;
+       }
+      return TRUE;
+    }
 
   /* If this is a function, put it in the procedure linkage table.  We
      will fill in the contents of the procedure linkage table later
@@ -1699,14 +1698,22 @@ elf_s390_adjust_dynamic_symbol (struct bfd_link_info *info,
   /* We must generate a R_390_COPY reloc to tell the dynamic linker to
      copy the initial value out of the dynamic object and into the
      runtime process image.  */
+  if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
+    {
+      s = htab->elf.sdynrelro;
+      srel = htab->elf.sreldynrelro;
+    }
+  else
+    {
+      s = htab->elf.sdynbss;
+      srel = htab->elf.srelbss;
+    }
   if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
     {
-      htab->srelbss->size += sizeof (Elf64_External_Rela);
+      srel->size += sizeof (Elf64_External_Rela);
       h->needs_copy = 1;
     }
 
-  s = htab->sdynbss;
-
   return _bfd_elf_adjust_dynamic_copy (info, h, s);
 }
 
@@ -1733,8 +1740,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h,
   /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it
      here if it is defined and referenced in a non-shared object.  */
   if (s390_is_ifunc_symbol_p (h) && h->def_regular)
-    return s390_elf_allocate_ifunc_dyn_relocs (info, h,
-                                              &eh->dyn_relocs);
+    return s390_elf_allocate_ifunc_dyn_relocs (info, h);
   else if (htab->elf.dynamic_sections_created
           && h->plt.refcount > 0)
     {
@@ -2105,7 +2111,8 @@ elf_s390_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
       if (s == htab->elf.splt
          || s == htab->elf.sgot
          || s == htab->elf.sgotplt
-         || s == htab->sdynbss
+         || s == htab->elf.sdynbss
+         || s == htab->elf.sdynrelro
          || s == htab->elf.iplt
          || s == htab->elf.igotplt
          || s == htab->irelifunc)
@@ -2245,7 +2252,8 @@ invalid_tls_insn (bfd *input_bfd,
   reloc_howto_type *howto;
 
   howto = elf_howto_table + ELF64_R_TYPE (rel->r_info);
-  (*_bfd_error_handler)
+  _bfd_error_handler
+    /* xgettext:c-format */
     (_("%B(%A+0x%lx): invalid instruction for TLS relocation %s"),
      input_bfd,
      input_section,
@@ -2431,7 +2439,7 @@ elf_s390_relocate_section (bfd *output_bfd,
                    PLT_ENTRY_SIZE;
 
                  /* Offset in GOT is PLT index plus GOT headers(3)
-                    times 4, addr & GOT addr.  */
+                    times 8, addr & GOT addr.  */
                  relocation = (plt_index + 3) * GOT_ENTRY_SIZE;
                  if (r_type == R_390_GOTPLTENT)
                    relocation += htab->elf.sgot->output_section->vma;
@@ -2601,6 +2609,18 @@ elf_s390_relocate_section (bfd *output_bfd,
          /* Relocation is relative to the start of the global offset
             table.  */
 
+         if (h != NULL
+             && s390_is_ifunc_symbol_p (h)
+             && h->def_regular
+             && !bfd_link_executable (info))
+           {
+             relocation = (htab->elf.iplt->output_section->vma
+                           + htab->elf.iplt->output_offset
+                           + h->plt.offset
+                           - htab->elf.sgot->output_section->vma);
+             goto do_relocation;
+           }
+
          /* Note that sgot->output_offset is not involved in this
             calculation.  We always want the start of .got.  If we
             defined _GLOBAL_OFFSET_TABLE in a different way, as is
@@ -2678,10 +2698,6 @@ elf_s390_relocate_section (bfd *output_bfd,
          unresolved_reloc = FALSE;
          break;
 
-       case R_390_8:
-       case R_390_16:
-       case R_390_32:
-       case R_390_64:
        case R_390_PC16:
        case R_390_PC12DBL:
        case R_390_PC16DBL:
@@ -2689,15 +2705,47 @@ elf_s390_relocate_section (bfd *output_bfd,
        case R_390_PC32:
        case R_390_PC32DBL:
        case R_390_PC64:
+         if (h != NULL
+             && bfd_link_pie (info)
+             && !h->def_regular)
+           {
+             _bfd_error_handler (_("%B: `%s' non-PLT reloc for symbol defined "
+                                   "in shared library and accessed "
+                                   "from executable "
+                                   "(rebuild file with -fPIC ?)"),
+                                 input_bfd, h->root.root.string);
+             bfd_set_error (bfd_error_bad_value);
+             return FALSE;
+           }
+         /* The target of these relocs are instruction operands
+            residing in read-only sections.  We cannot emit a runtime
+            reloc for it.  */
+         if (h != NULL
+             && s390_is_ifunc_symbol_p (h)
+             && h->def_regular
+             && bfd_link_pic (info))
+           {
+             relocation = (htab->elf.iplt->output_section->vma
+                           + htab->elf.iplt->output_offset
+                           + h->plt.offset);
+             goto do_relocation;
+           }
+         /* Fall through.  */
+
+       case R_390_8:
+       case R_390_16:
+       case R_390_32:
+       case R_390_64:
 
          if (h != NULL
              && s390_is_ifunc_symbol_p (h)
              && h->def_regular)
            {
-             if (!bfd_link_pic (info) || !h->non_got_ref)
+             if (!bfd_link_pic (info))
                {
-                 /* For a non-shared object STT_GNU_IFUNC symbol must
-                    go through PLT.  */
+                 /* For a non-shared object the symbol will not
+                    change.  Hence we can write the address of the
+                    target IPLT slot now.  */
                  relocation = (htab->elf.iplt->output_section->vma
                                + htab->elf.iplt->output_offset
                                + h ->plt.offset);
@@ -3153,8 +3201,10 @@ elf_s390_relocate_section (bfd *output_bfd,
                  insn0 = bfd_get_32 (input_bfd, contents + rel->r_offset);
                  insn1 = bfd_get_16 (input_bfd, contents + rel->r_offset + 4);
                  if (insn1 != 0x0004)
-                   invalid_tls_insn (input_bfd, input_section, rel);
-                 ry = 0;
+                   {
+                     invalid_tls_insn (input_bfd, input_section, rel);
+                     return FALSE;
+                   }
                  if ((insn0 & 0xff00f000) == 0xe3000000)
                    /* lg %rx,0(%ry,0) -> sllg %rx,%ry,0  */
                    ry = (insn0 & 0x000f0000);
@@ -3168,7 +3218,10 @@ elf_s390_relocate_section (bfd *output_bfd,
                    /* lg %rx,0(%r12,%ry) -> sllg %rx,%ry,0  */
                    ry = (insn0 & 0x0000f000) << 4;
                  else
-                   invalid_tls_insn (input_bfd, input_section, rel);
+                   {
+                     invalid_tls_insn (input_bfd, input_section, rel);
+                     return FALSE;
+                   }
                  insn0 = 0xeb000000 | (insn0 & 0x00f00000) | ry;
                  insn1 = 0x000d;
                  bfd_put_32 (output_bfd, insn0, contents + rel->r_offset);
@@ -3182,7 +3235,10 @@ elf_s390_relocate_section (bfd *output_bfd,
              insn0 = bfd_get_32 (input_bfd, contents + rel->r_offset);
              insn1 = bfd_get_16 (input_bfd, contents + rel->r_offset + 4);
              if ((insn0 & 0xffff0000) != 0xc0e50000)
-               invalid_tls_insn (input_bfd, input_section, rel);
+               {
+                 invalid_tls_insn (input_bfd, input_section, rel);
+                 return FALSE;
+               }
              if (!bfd_link_pic (info) && (h == NULL || h->dynindx == -1))
                {
                  /* GD->LE transition.
@@ -3209,7 +3265,10 @@ elf_s390_relocate_section (bfd *output_bfd,
                  insn0 = bfd_get_32 (input_bfd, contents + rel->r_offset);
                  insn1 = bfd_get_16 (input_bfd, contents + rel->r_offset + 4);
                  if ((insn0 & 0xffff0000) != 0xc0e50000)
-                   invalid_tls_insn (input_bfd, input_section, rel);
+                   {
+                     invalid_tls_insn (input_bfd, input_section, rel);
+                     return FALSE;
+                   }
                  /* LD->LE transition.
                     brasl %r14,__tls_get_addr@plt -> brcl 0,. */
                  insn0 = 0xc0040000;
@@ -3232,7 +3291,8 @@ elf_s390_relocate_section (bfd *output_bfd,
               && h->def_dynamic)
          && _bfd_elf_section_offset (output_bfd, info, input_section,
                                      rel->r_offset) != (bfd_vma) -1)
-       (*_bfd_error_handler)
+       _bfd_error_handler
+         /* xgettext:c-format */
          (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
           input_bfd,
           input_section,
@@ -3283,17 +3343,13 @@ elf_s390_relocate_section (bfd *output_bfd,
            }
 
          if (r == bfd_reloc_overflow)
-           {
-
-             if (! ((*info->callbacks->reloc_overflow)
-                    (info, (h ? &h->root : NULL), name, howto->name,
-                     (bfd_vma) 0, input_bfd, input_section,
-                     rel->r_offset)))
-               return FALSE;
-           }
+           (*info->callbacks->reloc_overflow)
+             (info, (h ? &h->root : NULL), name, howto->name,
+              (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
          else
            {
-             (*_bfd_error_handler)
+             _bfd_error_handler
+               /* xgettext:c-format */
                (_("%B(%A+0x%lx): reloc against `%s': error %d"),
                 input_bfd, input_section,
                 (long) rel->r_offset, name, (int) r);
@@ -3416,17 +3472,16 @@ elf_s390_finish_dynamic_symbol (bfd *output_bfd,
 
       /* This symbol has an entry in the procedure linkage table.  Set
         it up.  */
-      if (s390_is_ifunc_symbol_p (h))
+      if (s390_is_ifunc_symbol_p (h) && h->def_regular)
        {
-         /* If we can resolve the IFUNC symbol locally we generate an
-            IRELATIVE reloc.  */
-         elf_s390_finish_ifunc_symbol (output_bfd, info, h, htab, h->plt.offset,
-                                       eh->ifunc_resolver_address +
-                                       eh->ifunc_resolver_section->output_offset +
-                                       eh->ifunc_resolver_section->output_section->vma);
-                                ;
-         /* Fallthrough.  Handling of explicit GOT slots of IFUNC
-            symbols is below.  */
+         elf_s390_finish_ifunc_symbol (output_bfd, info, h,
+           htab, h->plt.offset,
+           eh->ifunc_resolver_address +
+           eh->ifunc_resolver_section->output_offset +
+           eh->ifunc_resolver_section->output_section->vma);
+
+         /* Do not return yet.  Handling of explicit GOT slots of
+            IFUNC symbols is below.  */
        }
       else
        {
@@ -3535,7 +3590,7 @@ elf_s390_finish_dynamic_symbol (bfd *output_bfd,
            }
        }
       else if (bfd_link_pic (info)
-         && SYMBOL_REFERENCES_LOCAL (info, h))
+              && SYMBOL_REFERENCES_LOCAL (info, h))
        {
          /* If this is a static link, or it is a -Bsymbolic link and
             the symbol is defined locally or was forced to be local
@@ -3543,7 +3598,7 @@ elf_s390_finish_dynamic_symbol (bfd *output_bfd,
             RELATIVE reloc.  The entry in the global offset table
             will already have been initialized in the
             relocate_section function.  */
-         if (!h->def_regular)
+         if (!(h->def_regular || ELF_COMMON_DEF_P (h)))
            return FALSE;
          BFD_ASSERT((h->got.offset & 1) != 0);
          rela.r_info = ELF64_R_INFO (0, R_390_RELATIVE);
@@ -3554,7 +3609,7 @@ elf_s390_finish_dynamic_symbol (bfd *output_bfd,
       else
        {
          BFD_ASSERT((h->got.offset & 1) == 0);
-do_glob_dat:
+       do_glob_dat:
          bfd_put_64 (output_bfd, (bfd_vma) 0, htab->elf.sgot->contents + h->got.offset);
          rela.r_info = ELF64_R_INFO (h->dynindx, R_390_GLOB_DAT);
          rela.r_addend = 0;
@@ -3568,6 +3623,7 @@ do_glob_dat:
   if (h->needs_copy)
     {
       Elf_Internal_Rela rela;
+      asection *s;
       bfd_byte *loc;
 
       /* This symbols needs a copy reloc.  Set it up.  */
@@ -3575,7 +3631,7 @@ do_glob_dat:
       if (h->dynindx == -1
          || (h->root.type != bfd_link_hash_defined
              && h->root.type != bfd_link_hash_defweak)
-         || htab->srelbss == NULL)
+         || htab->elf.srelbss == NULL)
        abort ();
 
       rela.r_offset = (h->root.u.def.value
@@ -3583,8 +3639,11 @@ do_glob_dat:
                       + h->root.u.def.section->output_offset);
       rela.r_info = ELF64_R_INFO (h->dynindx, R_390_COPY);
       rela.r_addend = 0;
-      loc = htab->srelbss->contents;
-      loc += htab->srelbss->reloc_count++ * sizeof (Elf64_External_Rela);
+      if (h->root.u.def.section == htab->elf.sdynrelro)
+       s = htab->elf.sreldynrelro;
+      else
+       s = htab->elf.srelbss;
+      loc = s->contents + s->reloc_count++ * sizeof (Elf64_External_Rela);
       bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
     }
 
@@ -3605,6 +3664,23 @@ elf_s390_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED,
                           const asection *rel_sec ATTRIBUTE_UNUSED,
                           const Elf_Internal_Rela *rela)
 {
+  bfd *abfd = info->output_bfd;
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  struct elf_s390_link_hash_table *htab = elf_s390_hash_table (info);
+  unsigned long r_symndx = ELF64_R_SYM (rela->r_info);
+  Elf_Internal_Sym sym;
+
+  if (htab->elf.dynsym == NULL
+      || !bed->s->swap_symbol_in (abfd,
+                                 (htab->elf.dynsym->contents
+                                  + r_symndx * bed->s->sizeof_sym),
+                                 0, &sym))
+    abort ();
+
+  /* Check relocation against STT_GNU_IFUNC symbol.  */
+  if (ELF_ST_TYPE (sym.st_info) == STT_GNU_IFUNC)
+    return reloc_class_ifunc;
+
   switch ((int) ELF64_R_TYPE (rela->r_info))
     {
     case R_390_RELATIVE:
@@ -3659,16 +3735,17 @@ elf_s390_finish_dynamic_sections (bfd *output_bfd,
              continue;
 
            case DT_PLTGOT:
-             dyn.d_un.d_ptr = htab->elf.sgot->output_section->vma;
+             s = htab->elf.sgotplt;
+             dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
              break;
 
            case DT_JMPREL:
-             dyn.d_un.d_ptr = htab->elf.srelplt->output_section->vma;
+             s = htab->elf.srelplt;
+             dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
              break;
 
            case DT_PLTRELSZ:
-             s = htab->elf.srelplt->output_section;
-             dyn.d_un.d_val = s->size;
+             dyn.d_un.d_val = htab->elf.srelplt->size + htab->elf.irelplt->size;
              break;
 
            case DT_RELASZ:
@@ -3679,8 +3756,7 @@ elf_s390_finish_dynamic_sections (bfd *output_bfd,
                 linker script arranges for .rela.plt to follow all
                 other relocation sections, we don't have to worry
                 about changing the DT_RELA entry.  */
-             s = htab->elf.srelplt->output_section;
-             dyn.d_un.d_val -= s->size;
+             dyn.d_un.d_val -= htab->elf.srelplt->size + htab->elf.irelplt->size;
              break;
            }
 
@@ -3695,9 +3771,10 @@ elf_s390_finish_dynamic_sections (bfd *output_bfd,
                  PLT_FIRST_ENTRY_SIZE);
          /* Fixup relative address to start of GOT */
          bfd_put_32 (output_bfd,
-                     (htab->elf.sgotplt->output_section->vma +
-                      htab->elf.sgotplt->output_offset
-                      - htab->elf.splt->output_section->vma - 6)/2,
+                     (htab->elf.sgotplt->output_section->vma
+                      + htab->elf.sgotplt->output_offset
+                      - htab->elf.splt->output_section->vma
+                      - htab->elf.splt->output_offset - 6)/2,
                      htab->elf.splt->contents + 8);
        }
       if (elf_section_data (htab->elf.splt->output_section) != NULL)
@@ -3717,7 +3794,7 @@ elf_s390_finish_dynamic_sections (bfd *output_bfd,
          /* One entry for shared object struct ptr.  */
          bfd_put_64 (output_bfd, (bfd_vma) 0, htab->elf.sgotplt->contents + 8);
          /* One entry for _dl_runtime_resolve.  */
-         bfd_put_64 (output_bfd, (bfd_vma) 0, htab->elf.sgotplt->contents + 12);
+         bfd_put_64 (output_bfd, (bfd_vma) 0, htab->elf.sgotplt->contents + 16);
        }
 
       elf_section_data (htab->elf.sgot->output_section)
@@ -3757,7 +3834,120 @@ elf_s390_finish_dynamic_sections (bfd *output_bfd,
 
   return TRUE;
 }
+\f
+/* Support for core dump NOTE sections.  */
+
+static bfd_boolean
+elf_s390_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
+{
+  int offset;
+  size_t size;
+
+  switch (note->descsz)
+    {
+    default:
+      return FALSE;
+
+    case 336:                  /* sizeof(struct elf_prstatus) on s390x */
+      /* pr_cursig */
+      elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12);
+
+      /* pr_pid */
+      elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 32);
+
+      /* pr_reg */
+      offset = 112;
+      size = 216;
+      break;
+    }
+
+  /* Make a ".reg/999" section.  */
+  return _bfd_elfcore_make_pseudosection (abfd, ".reg",
+                                         size, note->descpos + offset);
+}
+
+static bfd_boolean
+elf_s390_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
+{
+  switch (note->descsz)
+    {
+    default:
+      return FALSE;
+
+    case 136:                  /* sizeof(struct elf_prpsinfo) on s390x */
+      elf_tdata (abfd)->core->pid
+       = bfd_get_32 (abfd, note->descdata + 24);
+      elf_tdata (abfd)->core->program
+       = _bfd_elfcore_strndup (abfd, note->descdata + 40, 16);
+      elf_tdata (abfd)->core->command
+       = _bfd_elfcore_strndup (abfd, note->descdata + 56, 80);
+    }
+
+  /* Note that for some reason, a spurious space is tacked
+     onto the end of the args in some (at least one anyway)
+     implementations, so strip it off if it exists.  */
+
+  {
+    char *command = elf_tdata (abfd)->core->command;
+    int n = strlen (command);
+
+    if (0 < n && command[n - 1] == ' ')
+      command[n - 1] = '\0';
+  }
+
+  return TRUE;
+}
+
+static char *
+elf_s390_write_core_note (bfd *abfd, char *buf, int *bufsiz,
+                         int note_type, ...)
+{
+  va_list ap;
+
+  switch (note_type)
+    {
+    default:
+      return NULL;
+
+    case NT_PRPSINFO:
+      {
+       char data[136] = { 0 };
+       const char *fname, *psargs;
+
+       va_start (ap, note_type);
+       fname = va_arg (ap, const char *);
+       psargs = va_arg (ap, const char *);
+       va_end (ap);
+
+       strncpy (data + 40, fname, 16);
+       strncpy (data + 56, psargs, 80);
+       return elfcore_write_note (abfd, buf, bufsiz, "CORE", note_type,
+                                  &data, sizeof (data));
+      }
 
+    case NT_PRSTATUS:
+      {
+       char data[336] = { 0 };
+       long pid;
+       int cursig;
+       const void *gregs;
+
+       va_start (ap, note_type);
+       pid = va_arg (ap, long);
+       cursig = va_arg (ap, int);
+       gregs = va_arg (ap, const void *);
+       va_end (ap);
+
+       bfd_put_16 (abfd, cursig, data + 12);
+       bfd_put_32 (abfd, pid, data + 32);
+       memcpy (data + 112, gregs, 216);
+       return elfcore_write_note (abfd, buf, bufsiz, "CORE", note_type,
+                                  &data, sizeof (data));
+      }
+    }
+  /* NOTREACHED */
+}
+\f
 /* Return address for Ith PLT stub in section PLT, for relocation REL
    or (bfd_vma) -1 if it should not be included.  */
 
@@ -3772,17 +3962,78 @@ elf_s390_plt_sym_val (bfd_vma i, const asection *plt,
    object file when linking.  */
 
 static bfd_boolean
-elf64_s390_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
+elf64_s390_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
+{
+  if (!is_s390_elf (ibfd) || !is_s390_elf (info->output_bfd))
+    return TRUE;
+
+  return elf_s390_merge_obj_attributes (ibfd, info);
+}
+
+/* We may add a PT_S390_PGSTE program header.  */
+
+static int
+elf_s390_additional_program_headers (bfd *abfd ATTRIBUTE_UNUSED,
+                                    struct bfd_link_info *info)
+{
+  struct elf_s390_link_hash_table *htab;
+
+  htab = elf_s390_hash_table (info);
+  return htab->params->pgste;
+}
+
+
+/* Add the PT_S390_PGSTE program header.  */
+
+static bfd_boolean
+elf_s390_modify_segment_map (bfd *abfd ATTRIBUTE_UNUSED,
+                            struct bfd_link_info *info)
 {
-  if (!is_s390_elf (ibfd) || !is_s390_elf (obfd))
+  struct elf_s390_link_hash_table *htab;
+  struct elf_segment_map *m, *pm = NULL;
+
+  htab = elf_s390_hash_table (info);
+  if (!htab->params->pgste)
+    return TRUE;
+
+  /* If there is already a PT_S390_PGSTE header, avoid adding
+     another.  */
+  m = elf_seg_map (abfd);
+  while (m && m->p_type != PT_S390_PGSTE)
+    {
+      pm = m;
+      m = m->next;
+    }
+
+  if (m)
     return TRUE;
 
-  if (!elf_s390_merge_obj_attributes (ibfd, obfd))
+  m = (struct elf_segment_map *)
+    bfd_zalloc (abfd, sizeof (struct elf_segment_map));
+  if (m == NULL)
     return FALSE;
+  m->p_type = PT_S390_PGSTE;
+  m->count = 0;
+  m->next = NULL;
+  if (pm)
+    pm->next = m;
+
+  return TRUE;
+}
+
+bfd_boolean
+bfd_elf_s390_set_options (struct bfd_link_info *info,
+                         struct s390_elf_params *params)
+{
+  struct elf_s390_link_hash_table *htab;
+
+  htab = elf_s390_hash_table (info);
+  htab->params = params;
 
   return TRUE;
 }
 
+
 /* Why was the hash table entry size definition changed from
    ARCH_SIZE/8 to 4? This breaks the 64 bit dynamic linker and
    this is the only reason for the s390_elf64_size_info structure.  */
@@ -3834,6 +4085,7 @@ const struct elf_size_info s390_elf64_size_info =
 #define elf_backend_plt_readonly       1
 #define elf_backend_want_plt_sym       0
 #define elf_backend_got_header_size    24
+#define elf_backend_want_dynrelro      1
 #define elf_backend_rela_normal                1
 
 #define elf_info_to_howto              elf_s390_info_to_howto
@@ -3847,7 +4099,7 @@ const struct elf_size_info s390_elf64_size_info =
 #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
-#define elf_backend_create_dynamic_sections   elf_s390_create_dynamic_sections
+#define elf_backend_create_dynamic_sections   _bfd_elf_create_dynamic_sections
 #define elf_backend_finish_dynamic_sections   elf_s390_finish_dynamic_sections
 #define elf_backend_finish_dynamic_symbol     elf_s390_finish_dynamic_symbol
 #define elf_backend_gc_mark_hook             elf_s390_gc_mark_hook
@@ -3856,26 +4108,16 @@ const struct elf_size_info s390_elf64_size_info =
 #define elf_backend_relocate_section         elf_s390_relocate_section
 #define elf_backend_size_dynamic_sections     elf_s390_size_dynamic_sections
 #define elf_backend_init_index_section       _bfd_elf_init_1_index_section
+#define elf_backend_grok_prstatus            elf_s390_grok_prstatus
+#define elf_backend_grok_psinfo                      elf_s390_grok_psinfo
+#define elf_backend_write_core_note          elf_s390_write_core_note
 #define elf_backend_plt_sym_val                      elf_s390_plt_sym_val
 #define elf_backend_add_symbol_hook           elf_s390_add_symbol_hook
 #define elf_backend_sort_relocs_p             elf_s390_elf_sort_relocs_p
+#define elf_backend_additional_program_headers elf_s390_additional_program_headers
+#define elf_backend_modify_segment_map       elf_s390_modify_segment_map
 
 #define bfd_elf64_mkobject             elf_s390_mkobject
 #define elf_backend_object_p           elf_s390_object_p
 
-/* Enable ELF64 archive functions.  */
-#define bfd_elf64_archive_functions
-extern bfd_boolean bfd_elf64_archive_slurp_armap (bfd *);
-extern bfd_boolean bfd_elf64_archive_write_armap (bfd *, unsigned int, struct orl *, unsigned int, int);
-
-#define bfd_elf64_archive_slurp_extended_name_table    _bfd_archive_coff_slurp_extended_name_table
-#define bfd_elf64_archive_construct_extended_name_table _bfd_archive_coff_construct_extended_name_table
-#define bfd_elf64_archive_truncate_arname              _bfd_archive_coff_truncate_arname
-#define bfd_elf64_archive_read_ar_hdr                  _bfd_archive_coff_read_ar_hdr
-#define bfd_elf64_archive_write_ar_hdr                 _bfd_archive_coff_write_ar_hdr
-#define bfd_elf64_archive_openr_next_archived_file     _bfd_archive_coff_openr_next_archived_file
-#define bfd_elf64_archive_get_elt_at_index             _bfd_archive_coff_get_elt_at_index
-#define bfd_elf64_archive_generic_stat_arch_elt        _bfd_archive_coff_generic_stat_arch_elt
-#define bfd_elf64_archive_update_armap_timestamp       _bfd_archive_coff_update_armap_timestamp
-
 #include "elf64-target.h"
This page took 0.036461 seconds and 4 git commands to generate.