/* SPARC-specific support for 64-bit ELF
- Copyright (C) 1993-2015 Free Software Foundation, Inc.
+ Copyright (C) 1993-2019 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
else
relent->address = rela.r_offset - asect->vma;
- if (ELF64_R_SYM (rela.r_info) == STN_UNDEF
- /* PR 17512: file: 996185f8. */
- || ELF64_R_SYM (rela.r_info) > bfd_get_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;
return ret;
}
+/* Install a new set of internal relocs. */
+
+static void
+elf64_sparc_set_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+ asection *asect,
+ arelent **location,
+ unsigned int count)
+{
+ asect->orelocation = location;
+ canon_reloc_count (asect) = count;
+}
+
/* Write out the relocs. */
static void
reloc_count field to zero to inhibit writing them here. Also,
sometimes the SEC_RELOC flag gets set even when there aren't any
relocs. */
- if (sec->reloc_count == 0)
+ if (canon_reloc_count (sec) == 0)
return;
/* We can combine two relocs that refer to the same address
into R_SPARC_OLO10 if first one is R_SPARC_LO10 and the
latter is R_SPARC_13 with no associated symbol. */
count = 0;
- for (idx = 0; idx < sec->reloc_count; idx++)
+ for (idx = 0; idx < canon_reloc_count (sec); idx++)
{
bfd_vma addr;
addr = sec->orelocation[idx]->address;
if (sec->orelocation[idx]->howto->type == R_SPARC_LO10
- && idx < sec->reloc_count - 1)
+ && idx < canon_reloc_count (sec) - 1)
{
arelent *r = sec->orelocation[idx + 1];
outbound_relocas = (Elf64_External_Rela *) rela_hdr->contents;
src_rela = outbound_relocas;
- for (idx = 0; idx < sec->reloc_count; idx++)
+ for (idx = 0; idx < canon_reloc_count (sec); idx++)
{
Elf_Internal_Rela dst_rela;
arelent *ptr;
}
if (ptr->howto->type == R_SPARC_LO10
- && idx < sec->reloc_count - 1)
+ && idx < canon_reloc_count (sec) - 1)
{
arelent *r = sec->orelocation[idx + 1];
{
static const char *const stt_types[] = { "NOTYPE", "OBJECT", "FUNCTION" };
- 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;
-
if (ELF_ST_TYPE (sym->st_info) == STT_REGISTER)
{
int reg;
case 2: reg -= 2; break;
case 6: reg -= 4; break;
default:
- (*_bfd_error_handler)
- (_("%B: Only registers %%g[2367] can be declared using STT_REGISTER"),
- abfd);
+ _bfd_error_handler
+ (_("%pB: only registers %%g[2367] can be declared using STT_REGISTER"),
+ abfd);
return FALSE;
}
if (info->output_bfd->xvec != abfd->xvec
|| (abfd->flags & DYNAMIC) != 0)
- {
+ {
/* STT_REGISTER only works when linking an elf64_sparc object.
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;
- }
+ }
p = _bfd_sparc_elf_hash_table(info)->app_regs + reg;
if (p->name != NULL && strcmp (p->name, *namep))
{
- (*_bfd_error_handler)
- (_("Register %%g%d used incompatibly: %s in %B, previously %s in %B"),
- abfd, p->abfd, (int) sym->st_value,
- **namep ? *namep : "#scratch",
- *p->name ? p->name : "#scratch");
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("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;
}
if (type > STT_FUNC)
type = 0;
- (*_bfd_error_handler)
- (_("Symbol `%s' has differing types: REGISTER in %B, previously %s in %B"),
- abfd, p->abfd, *namep, stt_types[type]);
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("symbol `%s' has differing types: REGISTER in %pB,"
+ " previously %s in %pB"),
+ *namep, abfd, stt_types[type], p->abfd);
return FALSE;
}
if (type > STT_FUNC)
type = 0;
- (*_bfd_error_handler)
- (_("Symbol `%s' has differing types: %s in %B, previously REGISTER in %B"),
- abfd, p->abfd, *namep, stt_types[type]);
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("Symbol `%s' has differing types: %s in %pB,"
+ " previously REGISTER in %pB"),
+ *namep, stt_types[type], abfd, p->abfd);
return FALSE;
}
}
_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)
{
object file when linking. */
static bfd_boolean
-elf64_sparc_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
+elf64_sparc_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
{
+ bfd *obfd = info->output_bfd;
bfd_boolean error;
flagword new_flags, old_flags;
int new_mm, old_mm;
else if (new_flags == old_flags) /* Compatible flags are ok */
;
- else /* Incompatible flags */
+ else /* Incompatible flags */
{
error = FALSE;
&& (old_flags & EF_SPARC_HAL_R1))
{
error = TRUE;
- (*_bfd_error_handler)
- (_("%B: linking UltraSPARC specific with HAL specific code"),
+ _bfd_error_handler
+ (_("%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;
- (*_bfd_error_handler)
- (_("%B: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"),
- ibfd, (long) new_flags, (long) old_flags);
- }
+ {
+ error = TRUE;
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: uses different e_flags (%#x) fields than previous modules (%#x)"),
+ ibfd, new_flags, old_flags);
+ }
elf_elfheader (obfd)->e_flags = old_flags;
if (error)
- {
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
- }
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
}
- return _bfd_sparc_elf_merge_private_bfd_data (ibfd, obfd);
+ return _bfd_sparc_elf_merge_private_bfd_data (ibfd, info);
}
/* MARCO: Set the correct entry size for the .stab section. */
{
const char *name;
- name = bfd_get_section_name (abfd, sec);
+ name = bfd_section_name (sec);
if (strcmp (name, ".stab") == 0)
{
fprintf (file, "REG_%c%c%11s%c%c R", "GOLI" [reg / 8], '0' + (reg & 7), "",
((type & BSF_LOCAL)
? (type & BSF_GLOBAL) ? '!' : 'l'
- : (type & BSF_GLOBAL) ? 'g' : ' '),
- (type & BSF_WEAK) ? 'w' : ' ');
+ : (type & BSF_GLOBAL) ? 'g' : ' '),
+ (type & BSF_WEAK) ? 'w' : ' ');
if (symbol->name == NULL || symbol->name [0] == '\0')
return "#scratch";
else
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:
elf64_sparc_canonicalize_reloc
#define bfd_elf64_canonicalize_dynamic_reloc \
elf64_sparc_canonicalize_dynamic_reloc
+#define bfd_elf64_set_reloc \
+ elf64_sparc_set_reloc
#define elf_backend_add_symbol_hook \
elf64_sparc_add_symbol_hook
#define elf_backend_get_symbol_type \
_bfd_sparc_elf_finish_dynamic_symbol
#define elf_backend_finish_dynamic_sections \
_bfd_sparc_elf_finish_dynamic_sections
+#define elf_backend_fixup_symbol \
+ _bfd_sparc_elf_fixup_symbol
#define bfd_elf64_mkobject \
_bfd_sparc_elf_mkobject
_bfd_sparc_elf_object_p
#define elf_backend_gc_mark_hook \
_bfd_sparc_elf_gc_mark_hook
-#define elf_backend_gc_sweep_hook \
- _bfd_sparc_elf_gc_sweep_hook
#define elf_backend_init_index_section \
_bfd_elf_init_1_index_section
#define elf_backend_plt_readonly 0
#define elf_backend_want_plt_sym 1
#define elf_backend_got_header_size 8
+#define elf_backend_want_dynrelro 1
#define elf_backend_rela_normal 1
/* Section 5.2.4 of the ABI specifies a 256-byte boundary for the table. */