/* SPARC-specific support for 64-bit ELF
- Copyright (C) 1993-2017 Free Software Foundation, Inc.
+ Copyright (C) 1993-2021 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
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
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;
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;
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;
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;
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;
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);
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. */
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. */
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;
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;
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;
rela_hdr->contents = bfd_alloc (abfd, rela_hdr->sh_size);
if (rela_hdr->contents == NULL)
{
- *failedp = TRUE;
+ *failedp = true;
return;
}
n = _bfd_elf_symbol_from_bfd_symbol (abfd, &sym);
if (n < 0)
{
- *failedp = TRUE;
+ *failedp = true;
return;
}
last_sym_idx = n;
&& (*ptr->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec
&& ! _bfd_elf_validate_reloc (abfd, ptr))
{
- *failedp = TRUE;
+ *failedp = true;
return;
}
/* 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,
{
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;
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;
+ return false;
}
if (info->output_bfd->xvec != abfd->xvec
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;
{
_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;
+ return false;
}
if (p->name == NULL)
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)
{
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;
+ return false;
}
p->name = bfd_hash_allocate (&info->hash->table,
strlen (*namep) + 1);
if (!p->name)
- return FALSE;
+ return false;
strcpy (p->name, *namep);
}
}
}
*namep = NULL;
- return TRUE;
+ return true;
}
else if (*namep && **namep
&& info->output_bfd->xvec == abfd->xvec)
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;
+ 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,
_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;
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
/* 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;
}
else /* Incompatible flags */
{
- error = FALSE;
+ error = false;
#define EF_SPARC_ISA_EXTENSIONS \
(EF_SPARC_SUN_US1 | EF_SPARC_SUN_US3 | EF_SPARC_HAL_R1)
if ((old_flags & (EF_SPARC_SUN_US1 | EF_SPARC_SUN_US3))
&& (old_flags & EF_SPARC_HAL_R1))
{
- error = TRUE;
+ 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. */
/* Warn about any other mismatches */
if (new_flags != old_flags)
{
- error = TRUE;
+ 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);
}
if (error)
{
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return false;
}
}
return _bfd_sparc_elf_merge_private_bfd_data (ibfd, 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)
{
elf_section_data (sec)->this_hdr.sh_entsize = 12;
}
- return TRUE;
+ return true;
}
\f
/* Print a STT_REGISTER symbol to file FILE. */
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:
#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