1027 lines
28 KiB
C
1027 lines
28 KiB
C
/* SPARC-specific support for 64-bit ELF
|
||
Copyright (C) 1993-2022 Free Software Foundation, Inc.
|
||
|
||
This file is part of BFD, the Binary File Descriptor library.
|
||
|
||
This program is free software; you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License as published by
|
||
the Free Software Foundation; either version 3 of the License, or
|
||
(at your option) any later version.
|
||
|
||
This program is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
GNU General Public License for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with this program; if not, write to the Free Software
|
||
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
||
MA 02110-1301, USA. */
|
||
|
||
#include "sysdep.h"
|
||
#include <limits.h>
|
||
#include "bfd.h"
|
||
#include "libbfd.h"
|
||
#include "elf-bfd.h"
|
||
#include "elf/sparc.h"
|
||
#include "opcode/sparc.h"
|
||
#include "elfxx-sparc.h"
|
||
|
||
/* In case we're on a 32-bit machine, construct a 64-bit "-1" value. */
|
||
#define MINUS_ONE (~ (bfd_vma) 0)
|
||
|
||
/* Due to the way how we handle R_SPARC_OLO10, each entry in a SHT_RELA
|
||
section can represent up to two relocs, we must tell the user to allocate
|
||
more space. */
|
||
|
||
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 * 2L + 1) * sizeof (arelent *);
|
||
}
|
||
|
||
static long
|
||
elf64_sparc_get_dynamic_reloc_upper_bound (bfd *abfd)
|
||
{
|
||
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
|
||
them. We cannot use generic elf routines for this, because R_SPARC_OLO10
|
||
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 bool
|
||
elf64_sparc_slurp_one_reloc_table (bfd *abfd, asection *asect,
|
||
Elf_Internal_Shdr *rel_hdr,
|
||
asymbol **symbols, bool dynamic)
|
||
{
|
||
void * allocated = NULL;
|
||
bfd_byte *native_relocs;
|
||
arelent *relent;
|
||
unsigned int i;
|
||
int entsize;
|
||
bfd_size_type count;
|
||
arelent *relents;
|
||
|
||
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)
|
||
return false;
|
||
|
||
native_relocs = (bfd_byte *) allocated;
|
||
|
||
relents = asect->relocation + canon_reloc_count (asect);
|
||
|
||
entsize = rel_hdr->sh_entsize;
|
||
BFD_ASSERT (entsize == sizeof (Elf64_External_Rela));
|
||
|
||
count = rel_hdr->sh_size / entsize;
|
||
|
||
for (i = 0, relent = relents; i < count;
|
||
i++, relent++, native_relocs += entsize)
|
||
{
|
||
Elf_Internal_Rela rela;
|
||
unsigned int r_type;
|
||
|
||
bfd_elf64_swap_reloca_in (abfd, native_relocs, &rela);
|
||
|
||
/* The address of an ELF reloc is section relative for an object
|
||
file, and absolute for an executable file or shared library.
|
||
The address of a normal BFD reloc is always section relative,
|
||
and the address of a dynamic reloc is absolute.. */
|
||
if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0 || dynamic)
|
||
relent->address = rela.r_offset;
|
||
else
|
||
relent->address = rela.r_offset - asect->vma;
|
||
|
||
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;
|
||
|
||
ps = symbols + ELF64_R_SYM (rela.r_info) - 1;
|
||
s = *ps;
|
||
|
||
/* Canonicalize ELF section symbols. FIXME: Why? */
|
||
if ((s->flags & BSF_SECTION_SYM) == 0)
|
||
relent->sym_ptr_ptr = ps;
|
||
else
|
||
relent->sym_ptr_ptr = s->section->symbol_ptr_ptr;
|
||
}
|
||
|
||
relent->addend = rela.r_addend;
|
||
|
||
r_type = ELF64_R_TYPE_ID (rela.r_info);
|
||
if (r_type == R_SPARC_OLO10)
|
||
{
|
||
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 (abfd, R_SPARC_13);
|
||
}
|
||
else
|
||
{
|
||
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;
|
||
|
||
free (allocated);
|
||
return true;
|
||
|
||
error_return:
|
||
free (allocated);
|
||
return false;
|
||
}
|
||
|
||
/* Read in and swap the external relocs. */
|
||
|
||
static bool
|
||
elf64_sparc_slurp_reloc_table (bfd *abfd, asection *asect,
|
||
asymbol **symbols, bool dynamic)
|
||
{
|
||
struct bfd_elf_section_data * const d = elf_section_data (asect);
|
||
Elf_Internal_Shdr *rel_hdr;
|
||
Elf_Internal_Shdr *rel_hdr2;
|
||
bfd_size_type amt;
|
||
|
||
if (asect->relocation != NULL)
|
||
return true;
|
||
|
||
if (! dynamic)
|
||
{
|
||
if ((asect->flags & SEC_RELOC) == 0
|
||
|| asect->reloc_count == 0)
|
||
return true;
|
||
|
||
rel_hdr = d->rel.hdr;
|
||
rel_hdr2 = d->rela.hdr;
|
||
|
||
BFD_ASSERT ((rel_hdr && asect->rel_filepos == rel_hdr->sh_offset)
|
||
|| (rel_hdr2 && asect->rel_filepos == rel_hdr2->sh_offset));
|
||
}
|
||
else
|
||
{
|
||
/* Note that ASECT->RELOC_COUNT tends not to be accurate in this
|
||
case because relocations against this section may use the
|
||
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;
|
||
|
||
rel_hdr = &d->this_hdr;
|
||
asect->reloc_count = NUM_SHDR_ENTRIES (rel_hdr);
|
||
rel_hdr2 = NULL;
|
||
}
|
||
|
||
amt = asect->reloc_count;
|
||
amt *= 2 * sizeof (arelent);
|
||
asect->relocation = (arelent *) bfd_alloc (abfd, amt);
|
||
if (asect->relocation == NULL)
|
||
return false;
|
||
|
||
/* The elf64_sparc_slurp_one_reloc_table routine increments
|
||
canon_reloc_count. */
|
||
canon_reloc_count (asect) = 0;
|
||
|
||
if (rel_hdr
|
||
&& !elf64_sparc_slurp_one_reloc_table (abfd, asect, rel_hdr, symbols,
|
||
dynamic))
|
||
return false;
|
||
|
||
if (rel_hdr2
|
||
&& !elf64_sparc_slurp_one_reloc_table (abfd, asect, rel_hdr2, symbols,
|
||
dynamic))
|
||
return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
/* Canonicalize the relocs. */
|
||
|
||
static long
|
||
elf64_sparc_canonicalize_reloc (bfd *abfd, sec_ptr section,
|
||
arelent **relptr, asymbol **symbols)
|
||
{
|
||
arelent *tblptr;
|
||
unsigned int i;
|
||
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
|
||
|
||
if (! bed->s->slurp_reloc_table (abfd, section, symbols, false))
|
||
return -1;
|
||
|
||
tblptr = section->relocation;
|
||
for (i = 0; i < canon_reloc_count (section); i++)
|
||
*relptr++ = tblptr++;
|
||
|
||
*relptr = NULL;
|
||
|
||
return canon_reloc_count (section);
|
||
}
|
||
|
||
|
||
/* Canonicalize the dynamic relocation entries. Note that we return
|
||
the dynamic relocations as a single block, although they are
|
||
actually associated with particular sections; the interface, which
|
||
was designed for SunOS style shared libraries, expects that there
|
||
is only one set of dynamic relocs. Any section that was actually
|
||
installed in the BFD, and has type SHT_REL or SHT_RELA, and uses
|
||
the dynamic symbol table, is considered to be a dynamic reloc
|
||
section. */
|
||
|
||
static long
|
||
elf64_sparc_canonicalize_dynamic_reloc (bfd *abfd, arelent **storage,
|
||
asymbol **syms)
|
||
{
|
||
asection *s;
|
||
long ret;
|
||
|
||
if (elf_dynsymtab (abfd) == 0)
|
||
{
|
||
bfd_set_error (bfd_error_invalid_operation);
|
||
return -1;
|
||
}
|
||
|
||
ret = 0;
|
||
for (s = abfd->sections; s != NULL; s = s->next)
|
||
{
|
||
if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
|
||
&& (elf_section_data (s)->this_hdr.sh_type == SHT_RELA))
|
||
{
|
||
arelent *p;
|
||
long count, i;
|
||
|
||
if (! elf64_sparc_slurp_reloc_table (abfd, s, syms, true))
|
||
return -1;
|
||
count = canon_reloc_count (s);
|
||
p = s->relocation;
|
||
for (i = 0; i < count; i++)
|
||
*storage++ = p++;
|
||
ret += count;
|
||
}
|
||
}
|
||
|
||
*storage = NULL;
|
||
|
||
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
|
||
elf64_sparc_write_relocs (bfd *abfd, asection *sec, void * data)
|
||
{
|
||
bool *failedp = (bool *) data;
|
||
Elf_Internal_Shdr *rela_hdr;
|
||
bfd_vma addr_offset;
|
||
Elf64_External_Rela *outbound_relocas, *src_rela;
|
||
unsigned int idx, count;
|
||
asymbol *last_sym = 0;
|
||
int last_sym_idx = 0;
|
||
|
||
/* If we have already failed, don't do anything. */
|
||
if (*failedp)
|
||
return;
|
||
|
||
if ((sec->flags & SEC_RELOC) == 0)
|
||
return;
|
||
|
||
/* The linker backend writes the relocs out itself, and sets the
|
||
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 (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 < canon_reloc_count (sec); idx++)
|
||
{
|
||
bfd_vma addr;
|
||
|
||
++count;
|
||
|
||
addr = sec->orelocation[idx]->address;
|
||
if (sec->orelocation[idx]->howto->type == R_SPARC_LO10
|
||
&& idx < canon_reloc_count (sec) - 1)
|
||
{
|
||
arelent *r = sec->orelocation[idx + 1];
|
||
|
||
if (r->howto->type == R_SPARC_13
|
||
&& r->address == addr
|
||
&& bfd_is_abs_section ((*r->sym_ptr_ptr)->section)
|
||
&& (*r->sym_ptr_ptr)->value == 0)
|
||
++idx;
|
||
}
|
||
}
|
||
|
||
rela_hdr = elf_section_data (sec)->rela.hdr;
|
||
|
||
rela_hdr->sh_size = rela_hdr->sh_entsize * count;
|
||
rela_hdr->contents = bfd_alloc (abfd, rela_hdr->sh_size);
|
||
if (rela_hdr->contents == NULL)
|
||
{
|
||
*failedp = true;
|
||
return;
|
||
}
|
||
|
||
/* Figure out whether the relocations are RELA or REL relocations. */
|
||
if (rela_hdr->sh_type != SHT_RELA)
|
||
abort ();
|
||
|
||
/* The address of an ELF reloc is section relative for an object
|
||
file, and absolute for an executable file or shared library.
|
||
The address of a BFD reloc is always section relative. */
|
||
addr_offset = 0;
|
||
if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0)
|
||
addr_offset = sec->vma;
|
||
|
||
/* orelocation has the data, reloc_count has the count... */
|
||
outbound_relocas = (Elf64_External_Rela *) rela_hdr->contents;
|
||
src_rela = outbound_relocas;
|
||
|
||
for (idx = 0; idx < canon_reloc_count (sec); idx++)
|
||
{
|
||
Elf_Internal_Rela dst_rela;
|
||
arelent *ptr;
|
||
asymbol *sym;
|
||
int n;
|
||
|
||
ptr = sec->orelocation[idx];
|
||
sym = *ptr->sym_ptr_ptr;
|
||
if (sym == last_sym)
|
||
n = last_sym_idx;
|
||
else if (bfd_is_abs_section (sym->section) && sym->value == 0)
|
||
n = STN_UNDEF;
|
||
else
|
||
{
|
||
last_sym = sym;
|
||
n = _bfd_elf_symbol_from_bfd_symbol (abfd, &sym);
|
||
if (n < 0)
|
||
{
|
||
*failedp = true;
|
||
return;
|
||
}
|
||
last_sym_idx = n;
|
||
}
|
||
|
||
if ((*ptr->sym_ptr_ptr)->the_bfd != NULL
|
||
&& (*ptr->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec
|
||
&& ! _bfd_elf_validate_reloc (abfd, ptr))
|
||
{
|
||
*failedp = true;
|
||
return;
|
||
}
|
||
|
||
if (ptr->howto->type == R_SPARC_LO10
|
||
&& idx < canon_reloc_count (sec) - 1)
|
||
{
|
||
arelent *r = sec->orelocation[idx + 1];
|
||
|
||
if (r->howto->type == R_SPARC_13
|
||
&& r->address == ptr->address
|
||
&& bfd_is_abs_section ((*r->sym_ptr_ptr)->section)
|
||
&& (*r->sym_ptr_ptr)->value == 0)
|
||
{
|
||
idx++;
|
||
dst_rela.r_info
|
||
= ELF64_R_INFO (n, ELF64_R_TYPE_INFO (r->addend,
|
||
R_SPARC_OLO10));
|
||
}
|
||
else
|
||
dst_rela.r_info = ELF64_R_INFO (n, R_SPARC_LO10);
|
||
}
|
||
else
|
||
dst_rela.r_info = ELF64_R_INFO (n, ptr->howto->type);
|
||
|
||
dst_rela.r_offset = ptr->address + addr_offset;
|
||
dst_rela.r_addend = ptr->addend;
|
||
|
||
bfd_elf64_swap_reloca_out (abfd, &dst_rela, (bfd_byte *) src_rela);
|
||
++src_rela;
|
||
}
|
||
}
|
||
|
||
/* Hook called by the linker routine which adds symbols from an object
|
||
file. We use it for STT_REGISTER symbols. */
|
||
|
||
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,
|
||
asection **secp ATTRIBUTE_UNUSED,
|
||
bfd_vma *valp ATTRIBUTE_UNUSED)
|
||
{
|
||
static const char *const stt_types[] = { "NOTYPE", "OBJECT", "FUNCTION" };
|
||
|
||
if (ELF_ST_TYPE (sym->st_info) == STT_REGISTER)
|
||
{
|
||
int reg;
|
||
struct _bfd_sparc_elf_app_reg *p;
|
||
|
||
reg = (int)sym->st_value;
|
||
switch (reg & ~1)
|
||
{
|
||
case 2: reg -= 2; break;
|
||
case 6: reg -= 4; break;
|
||
default:
|
||
_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
|
||
/* 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 (p->name == NULL)
|
||
{
|
||
if (**namep)
|
||
{
|
||
struct elf_link_hash_entry *h;
|
||
|
||
h = (struct elf_link_hash_entry *)
|
||
bfd_link_hash_lookup (info->hash, *namep, false, false, false);
|
||
|
||
if (h != NULL)
|
||
{
|
||
unsigned char type = h->type;
|
||
|
||
if (type > STT_FUNC)
|
||
type = 0;
|
||
_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;
|
||
}
|
||
|
||
p->name = bfd_hash_allocate (&info->hash->table,
|
||
strlen (*namep) + 1);
|
||
if (!p->name)
|
||
return false;
|
||
|
||
strcpy (p->name, *namep);
|
||
}
|
||
else
|
||
p->name = "";
|
||
p->bind = ELF_ST_BIND (sym->st_info);
|
||
p->abfd = abfd;
|
||
p->shndx = sym->st_shndx;
|
||
}
|
||
else
|
||
{
|
||
if (p->bind == STB_WEAK
|
||
&& ELF_ST_BIND (sym->st_info) == STB_GLOBAL)
|
||
{
|
||
p->bind = STB_GLOBAL;
|
||
p->abfd = abfd;
|
||
}
|
||
}
|
||
*namep = NULL;
|
||
return true;
|
||
}
|
||
else if (*namep && **namep
|
||
&& info->output_bfd->xvec == abfd->xvec)
|
||
{
|
||
int i;
|
||
struct _bfd_sparc_elf_app_reg *p;
|
||
|
||
p = _bfd_sparc_elf_hash_table(info)->app_regs;
|
||
for (i = 0; i < 4; i++, p++)
|
||
if (p->name != NULL && ! strcmp (p->name, *namep))
|
||
{
|
||
unsigned char type = ELF_ST_TYPE (sym->st_info);
|
||
|
||
if (type > STT_FUNC)
|
||
type = 0;
|
||
_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;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
/* This function takes care of emitting STT_REGISTER symbols
|
||
which we cannot easily keep in the symbol hash table. */
|
||
|
||
static bool
|
||
elf64_sparc_output_arch_syms (bfd *output_bfd ATTRIBUTE_UNUSED,
|
||
struct bfd_link_info *info,
|
||
void * flaginfo,
|
||
int (*func) (void *, const char *,
|
||
Elf_Internal_Sym *,
|
||
asection *,
|
||
struct elf_link_hash_entry *))
|
||
{
|
||
int reg;
|
||
struct _bfd_sparc_elf_app_reg *app_regs =
|
||
_bfd_sparc_elf_hash_table(info)->app_regs;
|
||
Elf_Internal_Sym sym;
|
||
|
||
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)
|
||
continue;
|
||
|
||
sym.st_value = reg < 2 ? reg + 2 : reg + 4;
|
||
sym.st_size = 0;
|
||
sym.st_other = 0;
|
||
sym.st_info = ELF_ST_INFO (app_regs [reg].bind, STT_REGISTER);
|
||
sym.st_shndx = app_regs [reg].shndx;
|
||
sym.st_target_internal = 0;
|
||
if ((*func) (flaginfo, app_regs [reg].name, &sym,
|
||
sym.st_shndx == SHN_ABS
|
||
? bfd_abs_section_ptr : bfd_und_section_ptr,
|
||
NULL) != 1)
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
static int
|
||
elf64_sparc_get_symbol_type (Elf_Internal_Sym *elf_sym, int type)
|
||
{
|
||
if (ELF_ST_TYPE (elf_sym->st_info) == STT_REGISTER)
|
||
return STT_REGISTER;
|
||
else
|
||
return type;
|
||
}
|
||
|
||
/* A STB_GLOBAL,STT_REGISTER symbol should be BSF_GLOBAL
|
||
even in SHN_UNDEF section. */
|
||
|
||
static void
|
||
elf64_sparc_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, asymbol *asym)
|
||
{
|
||
elf_symbol_type *elfsym;
|
||
|
||
elfsym = (elf_symbol_type *) asym;
|
||
if (elfsym->internal_elf_sym.st_info
|
||
== ELF_ST_INFO (STB_GLOBAL, STT_REGISTER))
|
||
{
|
||
asym->flags |= BSF_GLOBAL;
|
||
}
|
||
}
|
||
|
||
|
||
/* Functions for dealing with the e_flags field. */
|
||
|
||
/* Merge backend specific data from an object file to the output
|
||
object file when linking. */
|
||
|
||
static bool
|
||
elf64_sparc_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
|
||
{
|
||
bfd *obfd = info->output_bfd;
|
||
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;
|
||
|
||
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_elfheader (obfd)->e_flags = new_flags;
|
||
}
|
||
|
||
else if (new_flags == old_flags) /* Compatible flags are ok */
|
||
;
|
||
|
||
else /* Incompatible flags */
|
||
{
|
||
error = false;
|
||
|
||
#define EF_SPARC_ISA_EXTENSIONS \
|
||
(EF_SPARC_SUN_US1 | EF_SPARC_SUN_US3 | EF_SPARC_HAL_R1)
|
||
|
||
if ((ibfd->flags & DYNAMIC) != 0)
|
||
{
|
||
/* We don't want dynamic objects memory ordering and
|
||
architecture to have any role. That's what dynamic linker
|
||
should do. */
|
||
new_flags &= ~(EF_SPARCV9_MM | EF_SPARC_ISA_EXTENSIONS);
|
||
new_flags |= (old_flags
|
||
& (EF_SPARCV9_MM | EF_SPARC_ISA_EXTENSIONS));
|
||
}
|
||
else
|
||
{
|
||
/* Choose the highest architecture requirements. */
|
||
old_flags |= (new_flags & EF_SPARC_ISA_EXTENSIONS);
|
||
new_flags |= (old_flags & EF_SPARC_ISA_EXTENSIONS);
|
||
if ((old_flags & (EF_SPARC_SUN_US1 | EF_SPARC_SUN_US3))
|
||
&& (old_flags & EF_SPARC_HAL_R1))
|
||
{
|
||
error = true;
|
||
_bfd_error_handler
|
||
(_("%pB: linking UltraSPARC specific with HAL specific code"),
|
||
ibfd);
|
||
}
|
||
/* Choose the most restrictive memory ordering. */
|
||
old_mm = (old_flags & EF_SPARCV9_MM);
|
||
new_mm = (new_flags & EF_SPARCV9_MM);
|
||
old_flags &= ~EF_SPARCV9_MM;
|
||
new_flags &= ~EF_SPARCV9_MM;
|
||
if (new_mm < old_mm)
|
||
old_mm = new_mm;
|
||
old_flags |= old_mm;
|
||
new_flags |= old_mm;
|
||
}
|
||
|
||
/* Warn about any other mismatches */
|
||
if (new_flags != 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;
|
||
}
|
||
}
|
||
return _bfd_sparc_elf_merge_private_bfd_data (ibfd, info);
|
||
}
|
||
|
||
/* MARCO: Set the correct entry size for the .stab section. */
|
||
|
||
static bool
|
||
elf64_sparc_fake_sections (bfd *abfd ATTRIBUTE_UNUSED,
|
||
Elf_Internal_Shdr *hdr ATTRIBUTE_UNUSED,
|
||
asection *sec)
|
||
{
|
||
const char *name;
|
||
|
||
name = bfd_section_name (sec);
|
||
|
||
if (strcmp (name, ".stab") == 0)
|
||
{
|
||
/* Even in the 64bit case the stab entries are only 12 bytes long. */
|
||
elf_section_data (sec)->this_hdr.sh_entsize = 12;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/* Print a STT_REGISTER symbol to file FILE. */
|
||
|
||
static const char *
|
||
elf64_sparc_print_symbol_all (bfd *abfd ATTRIBUTE_UNUSED, void * filep,
|
||
asymbol *symbol)
|
||
{
|
||
FILE *file = (FILE *) filep;
|
||
int reg, type;
|
||
|
||
if (ELF_ST_TYPE (((elf_symbol_type *) symbol)->internal_elf_sym.st_info)
|
||
!= STT_REGISTER)
|
||
return NULL;
|
||
|
||
reg = ((elf_symbol_type *) symbol)->internal_elf_sym.st_value;
|
||
type = symbol->flags;
|
||
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' : ' ');
|
||
if (symbol->name == NULL || symbol->name [0] == '\0')
|
||
return "#scratch";
|
||
else
|
||
return symbol->name;
|
||
}
|
||
|
||
/* 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,
|
||
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:
|
||
return reloc_class_plt;
|
||
case R_SPARC_COPY:
|
||
return reloc_class_copy;
|
||
default:
|
||
return reloc_class_normal;
|
||
}
|
||
}
|
||
|
||
/* Relocations in the 64 bit SPARC ELF ABI are more complex than in
|
||
standard ELF, because R_SPARC_OLO10 has secondary addend in
|
||
ELF64_R_TYPE_DATA field. This structure is used to redirect the
|
||
relocation handling routines. */
|
||
|
||
const struct elf_size_info elf64_sparc_size_info =
|
||
{
|
||
sizeof (Elf64_External_Ehdr),
|
||
sizeof (Elf64_External_Phdr),
|
||
sizeof (Elf64_External_Shdr),
|
||
sizeof (Elf64_External_Rel),
|
||
sizeof (Elf64_External_Rela),
|
||
sizeof (Elf64_External_Sym),
|
||
sizeof (Elf64_External_Dyn),
|
||
sizeof (Elf_External_Note),
|
||
4, /* hash-table entry size. */
|
||
/* Internal relocations per external relocations.
|
||
For link purposes we use just 1 internal per
|
||
1 external, for assembly and slurp symbol table
|
||
we use 2. */
|
||
1,
|
||
64, /* arch_size. */
|
||
3, /* log_file_align. */
|
||
ELFCLASS64,
|
||
EV_CURRENT,
|
||
bfd_elf64_write_out_phdrs,
|
||
bfd_elf64_write_shdrs_and_ehdr,
|
||
bfd_elf64_checksum_contents,
|
||
elf64_sparc_write_relocs,
|
||
bfd_elf64_swap_symbol_in,
|
||
bfd_elf64_swap_symbol_out,
|
||
elf64_sparc_slurp_reloc_table,
|
||
bfd_elf64_slurp_symbol_table,
|
||
bfd_elf64_swap_dyn_in,
|
||
bfd_elf64_swap_dyn_out,
|
||
bfd_elf64_swap_reloc_in,
|
||
bfd_elf64_swap_reloc_out,
|
||
bfd_elf64_swap_reloca_in,
|
||
bfd_elf64_swap_reloca_out
|
||
};
|
||
|
||
#define TARGET_BIG_SYM sparc_elf64_vec
|
||
#define TARGET_BIG_NAME "elf64-sparc"
|
||
#define ELF_ARCH bfd_arch_sparc
|
||
#define ELF_MAXPAGESIZE 0x100000
|
||
#define ELF_COMMONPAGESIZE 0x2000
|
||
|
||
/* This is the official ABI value. */
|
||
#define ELF_MACHINE_CODE EM_SPARCV9
|
||
|
||
/* This is the value that we used before the ABI was released. */
|
||
#define ELF_MACHINE_ALT1 EM_OLD_SPARCV9
|
||
|
||
#define elf_backend_reloc_type_class \
|
||
elf64_sparc_reloc_type_class
|
||
#define bfd_elf64_get_reloc_upper_bound \
|
||
elf64_sparc_get_reloc_upper_bound
|
||
#define bfd_elf64_get_dynamic_reloc_upper_bound \
|
||
elf64_sparc_get_dynamic_reloc_upper_bound
|
||
#define bfd_elf64_canonicalize_reloc \
|
||
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 \
|
||
elf64_sparc_get_symbol_type
|
||
#define elf_backend_symbol_processing \
|
||
elf64_sparc_symbol_processing
|
||
#define elf_backend_print_symbol_all \
|
||
elf64_sparc_print_symbol_all
|
||
#define elf_backend_output_arch_syms \
|
||
elf64_sparc_output_arch_syms
|
||
#define bfd_elf64_bfd_merge_private_bfd_data \
|
||
elf64_sparc_merge_private_bfd_data
|
||
#define elf_backend_fake_sections \
|
||
elf64_sparc_fake_sections
|
||
#define elf_backend_size_info \
|
||
elf64_sparc_size_info
|
||
|
||
#define elf_backend_plt_sym_val \
|
||
_bfd_sparc_elf_plt_sym_val
|
||
#define bfd_elf64_bfd_link_hash_table_create \
|
||
_bfd_sparc_elf_link_hash_table_create
|
||
#define elf_info_to_howto \
|
||
_bfd_sparc_elf_info_to_howto
|
||
#define elf_backend_copy_indirect_symbol \
|
||
_bfd_sparc_elf_copy_indirect_symbol
|
||
#define bfd_elf64_bfd_reloc_type_lookup \
|
||
_bfd_sparc_elf_reloc_type_lookup
|
||
#define bfd_elf64_bfd_reloc_name_lookup \
|
||
_bfd_sparc_elf_reloc_name_lookup
|
||
#define bfd_elf64_bfd_relax_section \
|
||
_bfd_sparc_elf_relax_section
|
||
#define bfd_elf64_new_section_hook \
|
||
_bfd_sparc_elf_new_section_hook
|
||
|
||
#define elf_backend_create_dynamic_sections \
|
||
_bfd_sparc_elf_create_dynamic_sections
|
||
#define elf_backend_relocs_compatible \
|
||
_bfd_elf_relocs_compatible
|
||
#define elf_backend_check_relocs \
|
||
_bfd_sparc_elf_check_relocs
|
||
#define elf_backend_adjust_dynamic_symbol \
|
||
_bfd_sparc_elf_adjust_dynamic_symbol
|
||
#define elf_backend_omit_section_dynsym \
|
||
_bfd_sparc_elf_omit_section_dynsym
|
||
#define elf_backend_size_dynamic_sections \
|
||
_bfd_sparc_elf_size_dynamic_sections
|
||
#define elf_backend_relocate_section \
|
||
_bfd_sparc_elf_relocate_section
|
||
#define elf_backend_finish_dynamic_symbol \
|
||
_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
|
||
#define elf_backend_object_p \
|
||
_bfd_sparc_elf_object_p
|
||
#define elf_backend_gc_mark_hook \
|
||
_bfd_sparc_elf_gc_mark_hook
|
||
#define elf_backend_init_index_section \
|
||
_bfd_elf_init_1_index_section
|
||
|
||
#define elf_backend_can_gc_sections 1
|
||
#define elf_backend_can_refcount 1
|
||
#define elf_backend_want_got_plt 0
|
||
#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. */
|
||
#define elf_backend_plt_alignment 8
|
||
|
||
#include "elf64-target.h"
|
||
|
||
/* FreeBSD support */
|
||
#undef TARGET_BIG_SYM
|
||
#define TARGET_BIG_SYM sparc_elf64_fbsd_vec
|
||
#undef TARGET_BIG_NAME
|
||
#define TARGET_BIG_NAME "elf64-sparc-freebsd"
|
||
#undef ELF_OSABI
|
||
#define ELF_OSABI ELFOSABI_FREEBSD
|
||
|
||
#undef elf64_bed
|
||
#define elf64_bed elf64_sparc_fbsd_bed
|
||
|
||
#include "elf64-target.h"
|
||
|
||
/* Solaris 2. */
|
||
|
||
#undef TARGET_BIG_SYM
|
||
#define TARGET_BIG_SYM sparc_elf64_sol2_vec
|
||
#undef TARGET_BIG_NAME
|
||
#define TARGET_BIG_NAME "elf64-sparc-sol2"
|
||
|
||
/* Restore default: we cannot use ELFOSABI_SOLARIS, otherwise ELFOSABI_NONE
|
||
objects won't be recognized. */
|
||
#undef ELF_OSABI
|
||
|
||
#undef elf64_bed
|
||
#define elf64_bed elf64_sparc_sol2_bed
|
||
|
||
/* The 64-bit static TLS arena size is rounded to the nearest 16-byte
|
||
boundary. */
|
||
#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
|