Fix size of external_reloc for pe-aarch64
[binutils-gdb.git] / bfd / elf-s390-common.c
index 61241dc81d50c94d2862b7e106d59868ec0d8f95..c0145bfbab8fb7b6cb57a11c98f7db1836f0818a 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-2016 Free Software Foundation, Inc.
+   Copyright (C) 2000-2023 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.
 /* Return TRUE if H is an IFUNC symbol.  Simply checking for the
    symbol type might not be enough since it might get changed to
    STT_FUNC for pointer equality reasons.  */
 /* Return TRUE if H is an IFUNC symbol.  Simply checking for the
    symbol type might not be enough since it might get changed to
    STT_FUNC for pointer equality reasons.  */
-static inline bfd_boolean
+static inline bool
 s390_is_ifunc_symbol_p (struct elf_link_hash_entry *h)
 {
   struct elf_s390_link_hash_entry *eh = (struct elf_s390_link_hash_entry*)h;
   return h->type == STT_GNU_IFUNC || eh->ifunc_resolver_address != 0;
 }
 
 s390_is_ifunc_symbol_p (struct elf_link_hash_entry *h)
 {
   struct elf_s390_link_hash_entry *eh = (struct elf_s390_link_hash_entry*)h;
   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 bool
+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.  */
 
 /* Create sections needed by STT_GNU_IFUNC symbol.  */
 
-static bfd_boolean
+static bool
 s390_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info)
 {
   flagword flags;
 s390_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info)
 {
   flagword flags;
@@ -41,7 +122,7 @@ s390_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info)
   struct elf_link_hash_table *htab = elf_hash_table (info);
 
   if (htab->iplt != NULL)
   struct elf_link_hash_table *htab = elf_hash_table (info);
 
   if (htab->iplt != NULL)
-    return TRUE;
+    return true;
 
   flags = bed->dynamic_sec_flags;
 
 
   flags = bed->dynamic_sec_flags;
 
@@ -50,9 +131,8 @@ s390_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *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))
-       return FALSE;
+         || !bfd_set_section_alignment (s, bed->s->log_file_align))
+       return false;
       htab->irelifunc = s;
     }
 
       htab->irelifunc = s;
     }
 
@@ -60,39 +140,37 @@ 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))
-    return FALSE;
+      || !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
   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))
-    return FALSE;
+      || !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
   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))
-    return FALSE;
+      || !bfd_set_section_alignment (s, bed->s->log_file_align))
+    return false;
   htab->igotplt = s;
 
   htab->igotplt = s;
 
-  return TRUE;
+  return true;
 }
 
 
 /* Allocate space in .plt, .got and associated reloc sections for
    dynamic relocs against a STT_GNU_IFUNC symbol definition.  */
 
 }
 
 
 /* Allocate space in .plt, .got and associated reloc sections for
    dynamic relocs against a STT_GNU_IFUNC symbol definition.  */
 
-static bfd_boolean
+static bool
 s390_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info,
                                    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;
 s390_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info,
                                    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 **head = &eh->dyn_relocs;
+  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,7 +180,7 @@ 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.  */
       if (bfd_link_pic (info)
         reference.  It may happen if we didn't see STT_GNU_IFUNC
         symbol at the time when checking relocations.  */
       if (bfd_link_pic (info)
@@ -118,7 +196,7 @@ s390_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info,
       h->got = htab->init_got_offset;
       h->plt = htab->init_plt_offset;
       *head = NULL;
       h->got = htab->init_got_offset;
       h->plt = htab->init_plt_offset;
       *head = NULL;
-      return TRUE;
+      return true;
     }
 
   /* Return and discard space for dynamic relocations against it if
     }
 
   /* Return and discard space for dynamic relocations against it if
@@ -131,10 +209,10 @@ s390_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info,
       h->got = htab->init_got_offset;
       h->plt = htab->init_plt_offset;
       *head = NULL;
       h->got = htab->init_got_offset;
       h->plt = htab->init_plt_offset;
       *head = NULL;
-      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.  */
@@ -161,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 (!bfd_link_pic (info) || !h->non_got_ref)
+  if (!bfd_link_pic (info))
     *head = NULL;
 
   /* Finally, allocate space.  */
     *head = NULL;
 
   /* Finally, allocate space.  */
@@ -200,48 +276,29 @@ keep:
        htab->srelgot->size += RELA_ENTRY_SIZE;
     }
 
        htab->srelgot->size += RELA_ENTRY_SIZE;
     }
 
-  return TRUE;
+  return true;
 }
 
 }
 
-static bfd_boolean
+static bool
 elf_s390_allocate_local_syminfo (bfd *abfd, Elf_Internal_Shdr *symtab_hdr)
 {
   bfd_size_type size;
 
   size = symtab_hdr->sh_info;
 elf_s390_allocate_local_syminfo (bfd *abfd, Elf_Internal_Shdr *symtab_hdr)
 {
   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)
-    return FALSE;
+    return false;
   elf_s390_local_plt (abfd)
     = (struct plt_entry*)(elf_local_got_refcounts (abfd)
                          + symtab_hdr->sh_info);
   elf_s390_local_got_tls_type (abfd)
     = (char *) (elf_s390_local_plt (abfd) + symtab_hdr->sh_info);
 
   elf_s390_local_plt (abfd)
     = (struct plt_entry*)(elf_local_got_refcounts (abfd)
                          + symtab_hdr->sh_info);
   elf_s390_local_got_tls_type (abfd)
     = (char *) (elf_s390_local_plt (abfd) + symtab_hdr->sh_info);
 
-  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
-      && (abfd->flags & DYNAMIC) == 0
-      && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
-    elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc;
-
-  return TRUE;
+  return true;
 }
 
 /* Whether to sort relocs output by ld -r or ld --emit-relocs, by
 }
 
 /* Whether to sort relocs output by ld -r or ld --emit-relocs, by
@@ -250,7 +307,7 @@ elf_s390_add_symbol_hook (bfd *abfd,
    hand, elf-eh-frame.c processing requires .eh_frame relocs to be
    sorted.  */
 
    hand, elf-eh-frame.c processing requires .eh_frame relocs to be
    sorted.  */
 
-static bfd_boolean
+static bool
 elf_s390_elf_sort_relocs_p (asection *sec)
 {
   return (sec->flags & SEC_CODE) == 0;
 elf_s390_elf_sort_relocs_p (asection *sec)
 {
   return (sec->flags & SEC_CODE) == 0;
@@ -258,7 +315,7 @@ elf_s390_elf_sort_relocs_p (asection *sec)
 
 /* Merge object attributes from IBFD into OBFD.  Raise an error if
    there are conflicting attributes.  */
 
 /* Merge object attributes from IBFD into OBFD.  Raise an error if
    there are conflicting attributes.  */
-static bfd_boolean
+static bool
 elf_s390_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
 {
   bfd *obfd = info->output_bfd;
 elf_s390_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
 {
   bfd *obfd = info->output_bfd;
@@ -274,7 +331,7 @@ elf_s390_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
         initialized.  */
       elf_known_obj_attributes_proc (obfd)[0].i = 1;
 
         initialized.  */
       elf_known_obj_attributes_proc (obfd)[0].i = 1;
 
-      return TRUE;
+      return true;
     }
 
   in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
     }
 
   in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
@@ -287,11 +344,13 @@ elf_s390_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
 
   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)
     {
@@ -302,8 +361,9 @@ elf_s390_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
          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;
        }
       if (in_attr->i > out_attr->i)
        out_attr->i = in_attr->i;
@@ -312,5 +372,5 @@ elf_s390_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
   /* Merge Tag_compatibility attributes and any common GNU ones.  */
   _bfd_elf_merge_object_attributes (ibfd, info);
 
   /* Merge Tag_compatibility attributes and any common GNU ones.  */
   _bfd_elf_merge_object_attributes (ibfd, info);
 
-  return TRUE;
+  return true;
 }
 }