gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / bfd / elf64-sparc.c
index f1f567567d5c422c5991e0045bb071ff0be5efc2..8d352252b63aba8278f8764f5e4d746e1edf5b5e 100644 (file)
@@ -1,5 +1,5 @@
 /* SPARC-specific support for 64-bit ELF
-   Copyright (C) 1993-2017 Free Software Foundation, Inc.
+   Copyright (C) 1993-2020 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
@@ -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,27 +144,28 @@ 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);
-
+  free (allocated);
   return TRUE;
 
  error_return:
-  if (allocated != NULL)
-    free (allocated);
+  free (allocated);
   return FALSE;
 }
 
@@ -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,7 +475,7 @@ elf64_sparc_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
        case 6: reg -= 4; break;
        default:
          _bfd_error_handler
-           (_("%B: Only registers %%g[2367] can be declared using STT_REGISTER"),
+           (_("%pB: only registers %%g[2367] can be declared using STT_REGISTER"),
             abfd);
          return FALSE;
        }
@@ -478,8 +496,8 @@ 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 %B,"
-              " previously %s in %B"),
+           (_("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;
@@ -502,8 +520,8 @@ 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 %B,"
-                      " previously %s in %B"),
+                   (_("symbol `%s' has differing types: REGISTER in %pB,"
+                      " previously %s in %pB"),
                     *namep, abfd, stt_types[type], p->abfd);
                  return FALSE;
                }
@@ -549,8 +567,8 @@ 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: %s in %B,"
-                " previously REGISTER in %B"),
+             (_("Symbol `%s' has differing types: %s in %pB,"
+                " previously REGISTER in %pB"),
               *namep, stt_types[type], abfd, p->abfd);
            return FALSE;
          }
@@ -575,29 +593,6 @@ 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)
       {
@@ -704,7 +699,7 @@ elf64_sparc_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
            {
              error = TRUE;
              _bfd_error_handler
-               (_("%B: linking UltraSPARC specific with HAL specific code"),
+               (_("%pB: linking UltraSPARC specific with HAL specific code"),
                 ibfd);
            }
          /* Choose the most restrictive memory ordering.  */
@@ -724,7 +719,7 @@ elf64_sparc_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
          error = TRUE;
          _bfd_error_handler
            /* xgettext:c-format */
-           (_("%B: uses different e_flags (%#x) fields than previous modules (%#x)"),
+           (_("%pB: uses different e_flags (%#x) fields than previous modules (%#x)"),
             ibfd, new_flags, old_flags);
        }
 
@@ -748,7 +743,7 @@ elf64_sparc_fake_sections (bfd *abfd ATTRIBUTE_UNUSED,
 {
   const char *name;
 
-  name = bfd_get_section_name (abfd, sec);
+  name = bfd_section_name (sec);
 
   if (strcmp (name, ".stab") == 0)
     {
@@ -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:
This page took 0.026793 seconds and 4 git commands to generate.