Copy several years of fixes from bfd/aoutx.h to bfd/pdp11.c.
[deliverable/binutils-gdb.git] / bfd / elf-s390-common.c
index dc6f55b0938357910440fcdb3d0acb6b0797581b..ebe881fcb6e587c299927aac741413272ea0225e 100644 (file)
@@ -1,5 +1,5 @@
 /* IBM S/390-specific support for ELF 32 and 64 bit functions
 /* IBM S/390-specific support for ELF 32 and 64 bit functions
-   Copyright (C) 2000-2015 Free Software Foundation, Inc.
+   Copyright (C) 2000-2020 Free Software Foundation, Inc.
    Contributed by Andreas Krebbel.
 
    This file is part of BFD, the Binary File Descriptor library.
    Contributed by Andreas Krebbel.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -30,6 +30,87 @@ s390_is_ifunc_symbol_p (struct elf_link_hash_entry *h)
   return h->type == STT_GNU_IFUNC || eh->ifunc_resolver_address != 0;
 }
 
   return h->type == STT_GNU_IFUNC || eh->ifunc_resolver_address != 0;
 }
 
+/* Return true if .got.plt is supposed to be emitted after .got.  */
+
+static inline bfd_boolean
+s390_gotplt_after_got_p (struct bfd_link_info *info)
+{
+  struct elf_s390_link_hash_table *htab = elf_s390_hash_table (info);
+
+  if (!htab->elf.sgot || !htab->elf.sgotplt)
+    return TRUE;
+
+  if (htab->elf.sgot->output_section == htab->elf.sgotplt->output_section)
+    {
+      if (htab->elf.sgot->output_offset < htab->elf.sgotplt->output_offset)
+       return TRUE;
+    }
+  else
+    {
+      if (htab->elf.sgot->output_section->vma
+         <= htab->elf.sgotplt->output_section->vma)
+       return TRUE;
+    }
+  return FALSE;
+}
+
+/* Return the value of the _GLOBAL_OFFSET_TABLE_ symbol.  */
+
+static inline bfd_vma
+s390_got_pointer (struct bfd_link_info *info)
+{
+  struct elf_s390_link_hash_table *htab = elf_s390_hash_table (info);
+  bfd_vma got_pointer;
+
+  BFD_ASSERT (htab && htab->elf.hgot);
+
+  got_pointer = (htab->elf.hgot->root.u.def.section->output_section->vma
+                + htab->elf.hgot->root.u.def.section->output_offset);
+  /* Our ABI requires the GOT pointer to point at the very beginning
+     of the global offset table.  */
+  BFD_ASSERT (got_pointer
+             <= (htab->elf.sgot->output_section->vma
+                 + htab->elf.sgot->output_offset));
+  BFD_ASSERT (got_pointer
+             <= (htab->elf.sgotplt->output_section->vma
+                 + htab->elf.sgotplt->output_offset));
+
+  return got_pointer;
+}
+
+
+/* Return the offset of the .got versus _GLOBAL_OFFSET_TABLE_.  */
+
+static inline bfd_vma
+s390_got_offset (struct bfd_link_info *info)
+{
+  struct elf_s390_link_hash_table *htab = elf_s390_hash_table (info);
+
+  /* The absolute address of the .got in the target image.  */
+  bfd_vma got_address = (htab->elf.sgot->output_section->vma
+                        + htab->elf.sgot->output_offset);
+
+  /* GOT offset must not be negative.  */
+  BFD_ASSERT (s390_got_pointer (info) <= got_address);
+  return got_address - s390_got_pointer (info);
+}
+
+/* Return the offset of the .got.plt versus _GLOBAL_OFFSET_TABLE_.  */
+
+static inline bfd_vma
+s390_gotplt_offset (struct bfd_link_info *info)
+{
+  struct elf_s390_link_hash_table *htab = elf_s390_hash_table (info);
+
+  /* The absolute address of the .got.plt in the target image.  */
+  bfd_vma gotplt_address = (htab->elf.sgotplt->output_section->vma
+                           + htab->elf.sgotplt->output_offset);
+
+  /* GOT offset must not be negative.  */
+  BFD_ASSERT (s390_got_pointer (info) <= gotplt_address);
+  return gotplt_address - s390_got_pointer (info);
+}
+
 /* Create sections needed by STT_GNU_IFUNC symbol.  */
 
 static bfd_boolean
 /* Create sections needed by STT_GNU_IFUNC symbol.  */
 
 static bfd_boolean
@@ -45,13 +126,12 @@ s390_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info)
 
   flags = bed->dynamic_sec_flags;
 
 
   flags = bed->dynamic_sec_flags;
 
-  if (info->shared)
+  if (bfd_link_pic (info))
     {
       s = bfd_make_section_with_flags (abfd, ".rela.ifunc",
                                       flags | SEC_READONLY);
       if (s == NULL
     {
       s = bfd_make_section_with_flags (abfd, ".rela.ifunc",
                                       flags | SEC_READONLY);
       if (s == NULL
-         || ! bfd_set_section_alignment (abfd, s,
-                                         bed->s->log_file_align))
+         || !bfd_set_section_alignment (s, bed->s->log_file_align))
        return FALSE;
       htab->irelifunc = s;
     }
        return FALSE;
       htab->irelifunc = s;
     }
@@ -60,21 +140,19 @@ s390_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info)
   s = bfd_make_section_with_flags (abfd, ".iplt",
                                   flags | SEC_CODE | SEC_READONLY);
   if (s == NULL
   s = bfd_make_section_with_flags (abfd, ".iplt",
                                   flags | SEC_CODE | SEC_READONLY);
   if (s == NULL
-      || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
+      || !bfd_set_section_alignment (s, bed->plt_alignment))
     return FALSE;
   htab->iplt = s;
 
   s = bfd_make_section_with_flags (abfd, ".rela.iplt", flags | SEC_READONLY);
   if (s == NULL
     return FALSE;
   htab->iplt = s;
 
   s = bfd_make_section_with_flags (abfd, ".rela.iplt", flags | SEC_READONLY);
   if (s == NULL
-      || ! bfd_set_section_alignment (abfd, s,
-                                     bed->s->log_file_align))
+      || !bfd_set_section_alignment (s, bed->s->log_file_align))
     return FALSE;
   htab->irelplt = s;
 
   s = bfd_make_section_with_flags (abfd, ".igot.plt", flags);
   if (s == NULL
     return FALSE;
   htab->irelplt = s;
 
   s = bfd_make_section_with_flags (abfd, ".igot.plt", flags);
   if (s == NULL
-      || !bfd_set_section_alignment (abfd, s,
-                                    bed->s->log_file_align))
+      || !bfd_set_section_alignment (s, bed->s->log_file_align))
     return FALSE;
   htab->igotplt = s;
 
     return FALSE;
   htab->igotplt = s;
 
@@ -87,12 +165,12 @@ s390_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info)
 
 static bfd_boolean
 s390_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info,
 
 static bfd_boolean
 s390_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info,
-                                   struct elf_link_hash_entry *h,
-                                   struct elf_dyn_relocs **head)
+                                   struct elf_link_hash_entry *h)
 {
   struct elf_dyn_relocs *p;
   struct elf_link_hash_table *htab;
   struct elf_s390_link_hash_entry *eh = (struct elf_s390_link_hash_entry*)h;
 {
   struct elf_dyn_relocs *p;
   struct elf_link_hash_table *htab;
   struct elf_s390_link_hash_entry *eh = (struct elf_s390_link_hash_entry*)h;
+  struct elf_dyn_relocs **head = &h->dyn_relocs;
 
   htab = elf_hash_table (info);
   eh->ifunc_resolver_address = h->root.u.def.value;
 
   htab = elf_hash_table (info);
   eh->ifunc_resolver_address = h->root.u.def.value;
@@ -102,10 +180,10 @@ s390_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info,
   if (h->plt.refcount <= 0 && h->got.refcount <= 0)
     {
       /* When building shared library, we need to handle the case
   if (h->plt.refcount <= 0 && h->got.refcount <= 0)
     {
       /* When building shared library, we need to handle the case
-         where it is marked with regular reference, but not non-GOT
+        where it is marked with regular reference, but not non-GOT
         reference.  It may happen if we didn't see STT_GNU_IFUNC
         symbol at the time when checking relocations.  */
         reference.  It may happen if we didn't see STT_GNU_IFUNC
         symbol at the time when checking relocations.  */
-      if (info->shared
+      if (bfd_link_pic (info)
          && !h->non_got_ref
          && h->ref_regular)
        for (p = *head; p != NULL; p = p->next)
          && !h->non_got_ref
          && h->ref_regular)
        for (p = *head; p != NULL; p = p->next)
@@ -134,7 +212,7 @@ s390_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info,
       return TRUE;
     }
 
       return TRUE;
     }
 
-keep:
+ keep:
   /* Without checking h->plt.refcount here we allocate a PLT slot.
      When setting plt.refcount in check_relocs it might not have been
      known that this will be an IFUNC symol.  */
   /* Without checking h->plt.refcount here we allocate a PLT slot.
      When setting plt.refcount in check_relocs it might not have been
      known that this will be an IFUNC symol.  */
@@ -151,7 +229,9 @@ keep:
      point to the IPLT slot.  That way the referencing shared lib will
      always get the PLT slot address when resolving the respective
      R_390_GLOB_DAT/R_390_64 relocs on that symbol.  */
      point to the IPLT slot.  That way the referencing shared lib will
      always get the PLT slot address when resolving the respective
      R_390_GLOB_DAT/R_390_64 relocs on that symbol.  */
-  if (info->executable && !info->shared && h->def_regular && h->ref_dynamic)
+  if (bfd_link_pde (info)
+      && h->def_regular
+      && h->ref_dynamic)
     {
       h->root.u.def.section = htab->iplt;
       h->root.u.def.value = h->plt.offset;
     {
       h->root.u.def.section = htab->iplt;
       h->root.u.def.value = h->plt.offset;
@@ -159,9 +239,7 @@ keep:
       h->type = STT_FUNC;
     }
 
       h->type = STT_FUNC;
     }
 
-  /* We need dynamic relocation for STT_GNU_IFUNC symbol only when
-     there is a non-GOT reference in a shared object.  */
-  if (!info->shared || !h->non_got_ref)
+  if (!bfd_link_pic (info))
     *head = NULL;
 
   /* Finally, allocate space.  */
     *head = NULL;
 
   /* Finally, allocate space.  */
@@ -182,9 +260,9 @@ keep:
      avoided if the values in the GOT slots could differ for pointer
      equality reasons.  */
   if (h->got.refcount <= 0
      avoided if the values in the GOT slots could differ for pointer
      equality reasons.  */
   if (h->got.refcount <= 0
-      || (info->shared
+      || (bfd_link_pic (info)
          && (h->dynindx == -1 || h->forced_local))
          && (h->dynindx == -1 || h->forced_local))
-      || (info->executable && info->shared)
+      || bfd_link_pie (info)
       || htab->sgot == NULL)
     {
       /* Use .got.iplt.  */
       || htab->sgot == NULL)
     {
       /* Use .got.iplt.  */
@@ -194,7 +272,7 @@ keep:
     {
       h->got.offset = htab->sgot->size;
       htab->sgot->size += GOT_ENTRY_SIZE;
     {
       h->got.offset = htab->sgot->size;
       htab->sgot->size += GOT_ENTRY_SIZE;
-      if (info->shared)
+      if (bfd_link_pic (info))
        htab->srelgot->size += RELA_ENTRY_SIZE;
     }
 
        htab->srelgot->size += RELA_ENTRY_SIZE;
     }
 
@@ -207,9 +285,9 @@ elf_s390_allocate_local_syminfo (bfd *abfd, Elf_Internal_Shdr *symtab_hdr)
   bfd_size_type size;
 
   size = symtab_hdr->sh_info;
   bfd_size_type size;
 
   size = symtab_hdr->sh_info;
-  size *= (sizeof (bfd_signed_vma)       /* local got */
-          + sizeof (struct plt_entry)   /* local plt */
-          + sizeof(char));              /* local tls type */
+  size *= (sizeof (bfd_signed_vma)      /* local got */
+          + sizeof (struct plt_entry)   /* local plt */
+          + sizeof(char));              /* local tls type */
   elf_local_got_refcounts (abfd) = ((bfd_signed_vma *)
                                    bfd_zalloc (abfd, size));
   if (elf_local_got_refcounts (abfd) == NULL)
   elf_local_got_refcounts (abfd) = ((bfd_signed_vma *)
                                    bfd_zalloc (abfd, size));
   if (elf_local_got_refcounts (abfd) == NULL)
@@ -223,26 +301,6 @@ elf_s390_allocate_local_syminfo (bfd *abfd, Elf_Internal_Shdr *symtab_hdr)
   return TRUE;
 }
 
   return TRUE;
 }
 
-/* Pick ELFOSABI_GNU if IFUNC symbols are used.  */
-
-static bfd_boolean
-elf_s390_add_symbol_hook (bfd *abfd,
-                         struct bfd_link_info *info,
-                         Elf_Internal_Sym *sym,
-                         const char **namep ATTRIBUTE_UNUSED,
-                         flagword *flagsp ATTRIBUTE_UNUSED,
-                         asection **secp ATTRIBUTE_UNUSED,
-                         bfd_vma *valp ATTRIBUTE_UNUSED)
-{
-  if ((ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
-       || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE)
-      && (abfd->flags & DYNAMIC) == 0
-      && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
-    elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
-
-  return TRUE;
-}
-
 /* Whether to sort relocs output by ld -r or ld --emit-relocs, by
    r_offset.  Don't do so for code sections.  We want to keep ordering
    of GDCALL / PLT32DBL for TLS optimizations as is.  On the other
 /* Whether to sort relocs output by ld -r or ld --emit-relocs, by
    r_offset.  Don't do so for code sections.  We want to keep ordering
    of GDCALL / PLT32DBL for TLS optimizations as is.  On the other
@@ -258,8 +316,9 @@ elf_s390_elf_sort_relocs_p (asection *sec)
 /* Merge object attributes from IBFD into OBFD.  Raise an error if
    there are conflicting attributes.  */
 static bfd_boolean
 /* Merge object attributes from IBFD into OBFD.  Raise an error if
    there are conflicting attributes.  */
 static bfd_boolean
-elf_s390_merge_obj_attributes (bfd *ibfd, bfd *obfd)
+elf_s390_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
 {
 {
+  bfd *obfd = info->output_bfd;
   obj_attribute *in_attr, *in_attrs;
   obj_attribute *out_attr, *out_attrs;
 
   obj_attribute *in_attr, *in_attrs;
   obj_attribute *out_attr, *out_attrs;
 
@@ -285,11 +344,13 @@ elf_s390_merge_obj_attributes (bfd *ibfd, bfd *obfd)
 
   if (in_attr->i > 2)
     _bfd_error_handler
 
   if (in_attr->i > 2)
     _bfd_error_handler
-      (_("Warning: %B uses unknown vector ABI %d"), ibfd,
+      /* xgettext:c-format */
+      (_("warning: %pB uses unknown vector ABI %d"), ibfd,
        in_attr->i);
   else if (out_attr->i > 2)
     _bfd_error_handler
        in_attr->i);
   else if (out_attr->i > 2)
     _bfd_error_handler
-      (_("Warning: %B uses unknown vector ABI %d"), obfd,
+      /* xgettext:c-format */
+      (_("warning: %pB uses unknown vector ABI %d"), obfd,
        out_attr->i);
   else if (in_attr->i != out_attr->i)
     {
        out_attr->i);
   else if (in_attr->i != out_attr->i)
     {
@@ -300,15 +361,16 @@ elf_s390_merge_obj_attributes (bfd *ibfd, bfd *obfd)
          const char abi_str[3][9] = { "none", "software", "hardware" };
 
          _bfd_error_handler
          const char abi_str[3][9] = { "none", "software", "hardware" };
 
          _bfd_error_handler
-           (_("Warning: %B uses vector %s ABI, %B uses %s ABI"),
-            ibfd, obfd, abi_str[in_attr->i], abi_str[out_attr->i]);
+           /* xgettext:c-format */
+           (_("warning: %pB uses vector %s ABI, %pB uses %s ABI"),
+            ibfd, abi_str[in_attr->i], obfd, abi_str[out_attr->i]);
        }
       if (in_attr->i > out_attr->i)
        out_attr->i = in_attr->i;
     }
 
   /* Merge Tag_compatibility attributes and any common GNU ones.  */
        }
       if (in_attr->i > out_attr->i)
        out_attr->i = in_attr->i;
     }
 
   /* Merge Tag_compatibility attributes and any common GNU ones.  */
-  _bfd_elf_merge_object_attributes (ibfd, obfd);
+  _bfd_elf_merge_object_attributes (ibfd, info);
 
   return TRUE;
 }
 
   return TRUE;
 }
This page took 0.028867 seconds and 4 git commands to generate.