Automatic date update in version.in
[deliverable/binutils-gdb.git] / bfd / elf64-sparc.c
index a9671e29b1330cb56201eb948346a5a5860498c9..035ebdd45ce6139820d95c3e4dbbc352eaf4c912 100644 (file)
@@ -1,5 +1,5 @@
 /* SPARC-specific support for 64-bit ELF
-   Copyright (C) 1993-2018 Free Software Foundation, Inc.
+   Copyright (C) 1993-2021 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -19,6 +19,7 @@
    MA 02110-1301, USA.  */
 
 #include "sysdep.h"
+#include <limits.h>
 #include "bfd.h"
 #include "libbfd.h"
 #include "elf-bfd.h"
 static long
 elf64_sparc_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
 {
+#if SIZEOF_LONG == SIZEOF_INT
+  if (sec->reloc_count >= LONG_MAX / 2 / sizeof (arelent *))
+    {
+      bfd_set_error (bfd_error_file_too_big);
+      return -1;
+    }
+#endif
   return (sec->reloc_count * 2 + 1) * sizeof (arelent *);
 }
 
 static long
 elf64_sparc_get_dynamic_reloc_upper_bound (bfd *abfd)
 {
-  return _bfd_elf_get_dynamic_reloc_upper_bound (abfd) * 2;
+  long ret = _bfd_elf_get_dynamic_reloc_upper_bound (abfd);
+  if (ret > LONG_MAX / 2)
+    {
+      bfd_set_error (bfd_error_file_too_big);
+      ret = -1;
+    }
+  else if (ret > 0)
+    ret *= 2;
+  return ret;
 }
 
 /* Read  relocations for ASECT from REL_HDR.  There are RELOC_COUNT of
@@ -50,10 +66,10 @@ elf64_sparc_get_dynamic_reloc_upper_bound (bfd *abfd)
    has secondary addend in ELF64_R_TYPE_DATA.  We handle it as two relocations
    for the same location,  R_SPARC_LO10 and R_SPARC_13.  */
 
-static bfd_boolean
+static bool
 elf64_sparc_slurp_one_reloc_table (bfd *abfd, asection *asect,
                                   Elf_Internal_Shdr *rel_hdr,
-                                  asymbol **symbols, bfd_boolean dynamic)
+                                  asymbol **symbols, bool dynamic)
 {
   void * allocated = NULL;
   bfd_byte *native_relocs;
@@ -63,13 +79,11 @@ elf64_sparc_slurp_one_reloc_table (bfd *abfd, asection *asect,
   bfd_size_type count;
   arelent *relents;
 
-  allocated = bfd_malloc (rel_hdr->sh_size);
+  if (bfd_seek (abfd, rel_hdr->sh_offset, SEEK_SET) != 0)
+    return false;
+  allocated = _bfd_malloc_and_read (abfd, rel_hdr->sh_size, rel_hdr->sh_size);
   if (allocated == NULL)
-    goto error_return;
-
-  if (bfd_seek (abfd, rel_hdr->sh_offset, SEEK_SET) != 0
-      || bfd_bread (allocated, rel_hdr->sh_size, abfd) != rel_hdr->sh_size)
-    goto error_return;
+    return false;
 
   native_relocs = (bfd_byte *) allocated;
 
@@ -97,12 +111,20 @@ elf64_sparc_slurp_one_reloc_table (bfd *abfd, asection *asect,
       else
        relent->address = rela.r_offset - asect->vma;
 
-      if (ELF64_R_SYM (rela.r_info) == STN_UNDEF
-         /* PR 17512: file: 996185f8.  */
-         || (!dynamic && ELF64_R_SYM(rela.r_info) > bfd_get_symcount(abfd))
-         || (dynamic
-             && ELF64_R_SYM(rela.r_info) > bfd_get_dynamic_symcount(abfd)))
+      if (ELF64_R_SYM (rela.r_info) == STN_UNDEF)
        relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
+      else if (/* PR 17512: file: 996185f8.  */
+              ELF64_R_SYM (rela.r_info) > (dynamic
+                                           ? bfd_get_dynamic_symcount (abfd)
+                                           : bfd_get_symcount (abfd)))
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB(%pA): relocation %d has invalid symbol index %ld"),
+            abfd, asect, i, (long) ELF64_R_SYM (rela.r_info));
+         bfd_set_error (bfd_error_bad_value);
+         relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
+       }
       else
        {
          asymbol **ps, *s;
@@ -122,35 +144,36 @@ elf64_sparc_slurp_one_reloc_table (bfd *abfd, asection *asect,
       r_type = ELF64_R_TYPE_ID (rela.r_info);
       if (r_type == R_SPARC_OLO10)
        {
-         relent->howto = _bfd_sparc_elf_info_to_howto_ptr (R_SPARC_LO10);
+         relent->howto = _bfd_sparc_elf_info_to_howto_ptr (abfd, R_SPARC_LO10);
          relent[1].address = relent->address;
          relent++;
          relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
          relent->addend = ELF64_R_TYPE_DATA (rela.r_info);
-         relent->howto = _bfd_sparc_elf_info_to_howto_ptr (R_SPARC_13);
+         relent->howto = _bfd_sparc_elf_info_to_howto_ptr (abfd, R_SPARC_13);
        }
       else
-       relent->howto = _bfd_sparc_elf_info_to_howto_ptr (r_type);
+       {
+         relent->howto = _bfd_sparc_elf_info_to_howto_ptr (abfd, r_type);
+         if (relent->howto == NULL)
+           goto error_return;
+       }
     }
 
   canon_reloc_count (asect) += relent - relents;
 
-  if (allocated != NULL)
-    free (allocated);
-
-  return TRUE;
+  free (allocated);
+  return true;
 
  error_return:
-  if (allocated != NULL)
-    free (allocated);
-  return FALSE;
+  free (allocated);
+  return false;
 }
 
 /* Read in and swap the external relocs.  */
 
-static bfd_boolean
+static bool
 elf64_sparc_slurp_reloc_table (bfd *abfd, asection *asect,
-                              asymbol **symbols, bfd_boolean dynamic)
+                              asymbol **symbols, bool dynamic)
 {
   struct bfd_elf_section_data * const d = elf_section_data (asect);
   Elf_Internal_Shdr *rel_hdr;
@@ -158,13 +181,13 @@ elf64_sparc_slurp_reloc_table (bfd *abfd, asection *asect,
   bfd_size_type amt;
 
   if (asect->relocation != NULL)
-    return TRUE;
+    return true;
 
   if (! dynamic)
     {
       if ((asect->flags & SEC_RELOC) == 0
          || asect->reloc_count == 0)
-       return TRUE;
+       return true;
 
       rel_hdr = d->rel.hdr;
       rel_hdr2 = d->rela.hdr;
@@ -179,7 +202,7 @@ elf64_sparc_slurp_reloc_table (bfd *abfd, asection *asect,
         dynamic symbol table, and in that case bfd_section_from_shdr
         in elf.c does not update the RELOC_COUNT.  */
       if (asect->size == 0)
-       return TRUE;
+       return true;
 
       rel_hdr = &d->this_hdr;
       asect->reloc_count = NUM_SHDR_ENTRIES (rel_hdr);
@@ -190,7 +213,7 @@ elf64_sparc_slurp_reloc_table (bfd *abfd, asection *asect,
   amt *= 2 * sizeof (arelent);
   asect->relocation = (arelent *) bfd_alloc (abfd, amt);
   if (asect->relocation == NULL)
-    return FALSE;
+    return false;
 
   /* The elf64_sparc_slurp_one_reloc_table routine increments
      canon_reloc_count.  */
@@ -199,14 +222,14 @@ elf64_sparc_slurp_reloc_table (bfd *abfd, asection *asect,
   if (rel_hdr
       && !elf64_sparc_slurp_one_reloc_table (abfd, asect, rel_hdr, symbols,
                                             dynamic))
-    return FALSE;
+    return false;
 
   if (rel_hdr2
       && !elf64_sparc_slurp_one_reloc_table (abfd, asect, rel_hdr2, symbols,
                                             dynamic))
-    return FALSE;
+    return false;
 
-  return TRUE;
+  return true;
 }
 
 /* Canonicalize the relocs.  */
@@ -219,7 +242,7 @@ elf64_sparc_canonicalize_reloc (bfd *abfd, sec_ptr section,
   unsigned int i;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
-  if (! bed->s->slurp_reloc_table (abfd, section, symbols, FALSE))
+  if (! bed->s->slurp_reloc_table (abfd, section, symbols, false))
     return -1;
 
   tblptr = section->relocation;
@@ -263,7 +286,7 @@ elf64_sparc_canonicalize_dynamic_reloc (bfd *abfd, arelent **storage,
          arelent *p;
          long count, i;
 
-         if (! elf64_sparc_slurp_reloc_table (abfd, s, syms, TRUE))
+         if (! elf64_sparc_slurp_reloc_table (abfd, s, syms, true))
            return -1;
          count = canon_reloc_count (s);
          p = s->relocation;
@@ -295,7 +318,7 @@ elf64_sparc_set_reloc (bfd *abfd ATTRIBUTE_UNUSED,
 static void
 elf64_sparc_write_relocs (bfd *abfd, asection *sec, void * data)
 {
-  bfd_boolean *failedp = (bfd_boolean *) data;
+  bool *failedp = (bool *) data;
   Elf_Internal_Shdr *rela_hdr;
   bfd_vma addr_offset;
   Elf64_External_Rela *outbound_relocas, *src_rela;
@@ -347,7 +370,7 @@ elf64_sparc_write_relocs (bfd *abfd, asection *sec, void * data)
   rela_hdr->contents = bfd_alloc (abfd, rela_hdr->sh_size);
   if (rela_hdr->contents == NULL)
     {
-      *failedp = TRUE;
+      *failedp = true;
       return;
     }
 
@@ -385,7 +408,7 @@ elf64_sparc_write_relocs (bfd *abfd, asection *sec, void * data)
          n = _bfd_elf_symbol_from_bfd_symbol (abfd, &sym);
          if (n < 0)
            {
-             *failedp = TRUE;
+             *failedp = true;
              return;
            }
          last_sym_idx = n;
@@ -395,7 +418,7 @@ elf64_sparc_write_relocs (bfd *abfd, asection *sec, void * data)
          && (*ptr->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec
          && ! _bfd_elf_validate_reloc (abfd, ptr))
        {
-         *failedp = TRUE;
+         *failedp = true;
          return;
        }
 
@@ -431,7 +454,7 @@ elf64_sparc_write_relocs (bfd *abfd, asection *sec, void * data)
 /* Hook called by the linker routine which adds symbols from an object
    file.  We use it for STT_REGISTER symbols.  */
 
-static bfd_boolean
+static bool
 elf64_sparc_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
                             Elf_Internal_Sym *sym, const char **namep,
                             flagword *flagsp ATTRIBUTE_UNUSED,
@@ -440,11 +463,6 @@ elf64_sparc_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
 {
   static const char *const stt_types[] = { "NOTYPE", "OBJECT", "FUNCTION" };
 
-  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;
-
   if (ELF_ST_TYPE (sym->st_info) == STT_REGISTER)
     {
       int reg;
@@ -457,9 +475,9 @@ elf64_sparc_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
        case 6: reg -= 4; break;
        default:
          _bfd_error_handler
-           (_("%pB: Only registers %%g[2367] can be declared using STT_REGISTER"),
+           (_("%pB: only registers %%g[2367] can be declared using STT_REGISTER"),
             abfd);
-         return FALSE;
+         return false;
        }
 
       if (info->output_bfd->xvec != abfd->xvec
@@ -469,7 +487,7 @@ elf64_sparc_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
             If STT_REGISTER comes from a dynamic object, don't put it into
             the output bfd.  The dynamic linker will recheck it.  */
          *namep = NULL;
-         return TRUE;
+         return true;
        }
 
       p = _bfd_sparc_elf_hash_table(info)->app_regs + reg;
@@ -478,11 +496,11 @@ elf64_sparc_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
        {
          _bfd_error_handler
            /* xgettext:c-format */
-           (_("Register %%g%d used incompatibly: %s in %pB,"
+           (_("register %%g%d used incompatibly: %s in %pB,"
               " previously %s in %pB"),
             (int) sym->st_value, **namep ? *namep : "#scratch", abfd,
             *p->name ? p->name : "#scratch", p->abfd);
-         return FALSE;
+         return false;
        }
 
       if (p->name == NULL)
@@ -492,7 +510,7 @@ elf64_sparc_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
              struct elf_link_hash_entry *h;
 
              h = (struct elf_link_hash_entry *)
-               bfd_link_hash_lookup (info->hash, *namep, FALSE, FALSE, FALSE);
+               bfd_link_hash_lookup (info->hash, *namep, false, false, false);
 
              if (h != NULL)
                {
@@ -502,16 +520,16 @@ elf64_sparc_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
                    type = 0;
                  _bfd_error_handler
                    /* xgettext:c-format */
-                   (_("Symbol `%s' has differing types: REGISTER in %pB,"
+                   (_("symbol `%s' has differing types: REGISTER in %pB,"
                       " previously %s in %pB"),
                     *namep, abfd, stt_types[type], p->abfd);
-                 return FALSE;
+                 return false;
                }
 
              p->name = bfd_hash_allocate (&info->hash->table,
                                           strlen (*namep) + 1);
              if (!p->name)
-               return FALSE;
+               return false;
 
              strcpy (p->name, *namep);
            }
@@ -531,7 +549,7 @@ elf64_sparc_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
            }
        }
       *namep = NULL;
-      return TRUE;
+      return true;
     }
   else if (*namep && **namep
           && info->output_bfd->xvec == abfd->xvec)
@@ -552,16 +570,16 @@ elf64_sparc_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
              (_("Symbol `%s' has differing types: %s in %pB,"
                 " previously REGISTER in %pB"),
               *namep, stt_types[type], abfd, p->abfd);
-           return FALSE;
+           return false;
          }
     }
-  return TRUE;
+  return true;
 }
 
 /* This function takes care of emitting STT_REGISTER symbols
    which we cannot easily keep in the symbol hash table.  */
 
-static bfd_boolean
+static bool
 elf64_sparc_output_arch_syms (bfd *output_bfd ATTRIBUTE_UNUSED,
                              struct bfd_link_info *info,
                              void * flaginfo,
@@ -575,36 +593,13 @@ elf64_sparc_output_arch_syms (bfd *output_bfd ATTRIBUTE_UNUSED,
     _bfd_sparc_elf_hash_table(info)->app_regs;
   Elf_Internal_Sym sym;
 
-  /* We arranged in size_dynamic_sections to put the STT_REGISTER entries
-     at the end of the dynlocal list, so they came at the end of the local
-     symbols in the symtab.  Except that they aren't STB_LOCAL, so we need
-     to back up symtab->sh_info.  */
-  if (elf_hash_table (info)->dynlocal)
-    {
-      bfd * dynobj = elf_hash_table (info)->dynobj;
-      asection *dynsymsec = bfd_get_linker_section (dynobj, ".dynsym");
-      struct elf_link_local_dynamic_entry *e;
-
-      for (e = elf_hash_table (info)->dynlocal; e ; e = e->next)
-       if (e->input_indx == -1)
-         break;
-      if (e)
-       {
-         elf_section_data (dynsymsec->output_section)->this_hdr.sh_info
-           = e->dynindx;
-       }
-    }
-
-  if (info->strip == strip_all)
-    return TRUE;
-
   for (reg = 0; reg < 4; reg++)
     if (app_regs [reg].name != NULL)
       {
        if (info->strip == strip_some
            && bfd_hash_lookup (info->keep_hash,
                                app_regs [reg].name,
-                               FALSE, FALSE) == NULL)
+                               false, false) == NULL)
          continue;
 
        sym.st_value = reg < 2 ? reg + 2 : reg + 4;
@@ -617,10 +612,10 @@ elf64_sparc_output_arch_syms (bfd *output_bfd ATTRIBUTE_UNUSED,
                     sym.st_shndx == SHN_ABS
                     ? bfd_abs_section_ptr : bfd_und_section_ptr,
                     NULL) != 1)
-         return FALSE;
+         return false;
       }
 
-  return TRUE;
+  return true;
 }
 
 static int
@@ -654,24 +649,24 @@ elf64_sparc_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, asymbol *asym)
 /* Merge backend specific data from an object file to the output
    object file when linking.  */
 
-static bfd_boolean
+static bool
 elf64_sparc_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
 {
   bfd *obfd = info->output_bfd;
-  bfd_boolean error;
+  bool error;
   flagword new_flags, old_flags;
   int new_mm, old_mm;
 
   if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
       || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
-    return TRUE;
+    return true;
 
   new_flags = elf_elfheader (ibfd)->e_flags;
   old_flags = elf_elfheader (obfd)->e_flags;
 
   if (!elf_flags_init (obfd))   /* First call, no flags set */
     {
-      elf_flags_init (obfd) = TRUE;
+      elf_flags_init (obfd) = true;
       elf_elfheader (obfd)->e_flags = new_flags;
     }
 
@@ -680,7 +675,7 @@ elf64_sparc_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
 
   else                                 /* Incompatible flags */
     {
-      error = FALSE;
+      error = false;
 
 #define EF_SPARC_ISA_EXTENSIONS \
   (EF_SPARC_SUN_US1 | EF_SPARC_SUN_US3 | EF_SPARC_HAL_R1)
@@ -702,7 +697,7 @@ elf64_sparc_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
          if ((old_flags & (EF_SPARC_SUN_US1 | EF_SPARC_SUN_US3))
              && (old_flags & EF_SPARC_HAL_R1))
            {
-             error = TRUE;
+             error = true;
              _bfd_error_handler
                (_("%pB: linking UltraSPARC specific with HAL specific code"),
                 ibfd);
@@ -721,7 +716,7 @@ elf64_sparc_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
       /* Warn about any other mismatches */
       if (new_flags != old_flags)
        {
-         error = TRUE;
+         error = true;
          _bfd_error_handler
            /* xgettext:c-format */
            (_("%pB: uses different e_flags (%#x) fields than previous modules (%#x)"),
@@ -733,7 +728,7 @@ elf64_sparc_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
       if (error)
        {
          bfd_set_error (bfd_error_bad_value);
-         return FALSE;
+         return false;
        }
     }
   return _bfd_sparc_elf_merge_private_bfd_data (ibfd, info);
@@ -741,14 +736,14 @@ elf64_sparc_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
 
 /* MARCO: Set the correct entry size for the .stab section.  */
 
-static bfd_boolean
+static bool
 elf64_sparc_fake_sections (bfd *abfd ATTRIBUTE_UNUSED,
                           Elf_Internal_Shdr *hdr ATTRIBUTE_UNUSED,
                           asection *sec)
 {
   const char *name;
 
-  name = bfd_get_section_name (abfd, sec);
+  name = bfd_section_name (sec);
 
   if (strcmp (name, ".stab") == 0)
     {
@@ -756,7 +751,7 @@ elf64_sparc_fake_sections (bfd *abfd ATTRIBUTE_UNUSED,
       elf_section_data (sec)->this_hdr.sh_entsize = 12;
     }
 
-  return TRUE;
+  return true;
 }
 \f
 /* Print a STT_REGISTER symbol to file FILE.  */
@@ -785,13 +780,44 @@ elf64_sparc_print_symbol_all (bfd *abfd ATTRIBUTE_UNUSED, void * filep,
     return symbol->name;
 }
 \f
+/* Used to decide how to sort relocs in an optimal manner for the
+   dynamic linker, before writing them out.  */
+
 static enum elf_reloc_type_class
-elf64_sparc_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED,
+elf64_sparc_reloc_type_class (const struct bfd_link_info *info,
                              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 _bfd_sparc_elf_link_hash_table *htab
+    = _bfd_sparc_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+
+  if (htab->elf.dynsym != NULL
+      && htab->elf.dynsym->contents != NULL)
+    {
+      /* Check relocation against STT_GNU_IFUNC symbol if there are
+        dynamic symbols.  */
+      unsigned long r_symndx = htab->r_symndx (rela->r_info);
+      if (r_symndx != STN_UNDEF)
+       {
+         Elf_Internal_Sym sym;
+         if (!bed->s->swap_symbol_in (abfd,
+                                      (htab->elf.dynsym->contents
+                                       + r_symndx * bed->s->sizeof_sym),
+                                      0, &sym))
+           abort ();
+
+         if (ELF_ST_TYPE (sym.st_info) == STT_GNU_IFUNC)
+           return reloc_class_ifunc;
+       }
+    }
+
   switch ((int) ELF64_R_TYPE (rela->r_info))
     {
+    case R_SPARC_IRELATIVE:
+      return reloc_class_ifunc;
     case R_SPARC_RELATIVE:
       return reloc_class_relative;
     case R_SPARC_JMP_SLOT:
@@ -978,4 +1004,24 @@ const struct elf_size_info elf64_sparc_size_info =
 #undef elf_backend_static_tls_alignment
 #define elf_backend_static_tls_alignment       16
 
+#undef  elf_backend_strtab_flags
+#define elf_backend_strtab_flags       SHF_STRINGS
+
+static bool
+elf64_sparc_copy_solaris_special_section_fields (const bfd *ibfd ATTRIBUTE_UNUSED,
+                                  bfd *obfd ATTRIBUTE_UNUSED,
+                                  const Elf_Internal_Shdr *isection ATTRIBUTE_UNUSED,
+                                  Elf_Internal_Shdr *osection ATTRIBUTE_UNUSED)
+{
+  /* PR 19938: FIXME: Need to add code for setting the sh_info
+     and sh_link fields of Solaris specific section types.  */
+  return false;
+}
+
+#undef  elf_backend_copy_special_section_fields
+#define elf_backend_copy_special_section_fields elf64_sparc_copy_solaris_special_section_fields
+
 #include "elf64-target.h"
+
+#undef  elf_backend_strtab_flags
+#undef  elf_backend_copy_special_section_fields
This page took 0.03352 seconds and 4 git commands to generate.