* elf/sparc.h (R_SPARC_JMP_IREL, R_SPARC_IRELATIVE): Define.

bfd/

	* reloc.c (BFD_RELOC_SPARC_JMP_IREL): New.
	(BFD_RELOC_SPARC_IRELATIVE): Likewise.
	* bfd-in2.h: Regenerate.
	* libbfd.h: Regenerate.

	* elfxx-sparc.h (_bfd_sparc_elf_link_hash_table): Add loc_hash_table
	and loc_hash_memory.
	(_bfd_sparc_elf_link_hash_table_free): Declare.
	* elf32-sparc.c (elf32_sparc_add_symbol_hook): New.
	(elf_backend_add_symbol_hook, elf_backend_post_process_headers,
	bfd_elf32_bfd_link_hash_table_free): Define.
	* elf64-sparc.c (elf64_sparc_add_symbol_hook): Set
	has_ifunc_symbols if STT_GNU_IFUNC.
	(bfd_elf64_bfd_link_hash_table_free): Define.
	(elf_backend_post_process_headers): Define always.
	* elfxx-sparc.c (sparc_jmp_irel_howto, sparc_irelative_howto): New.
	(sparc_reloc_map): Add entries for new IFUNC relocs.
	(_bfd_sparc_elf_reloc_type_lookup): Handle new IFUNC relocs.
	(_bfd_sparc_elf_info_to_howto_ptr): Likewise.
	(elf_sparc_local_htab_hash, elf_sparc_local_htab_eq,
	elf_sparc_get_local_sym_hash): New.
	(_bfd_sparc_elf_create_dynamic_sections): Move PLT ops initialization
	from here...
	(_bfd_sparc_elf_link_hash_table_create): ... to here.  Allocate
	local hash table.
	(_bfd_sparc_elf_link_hash_table_free): New.
	(create_ifunc_sections): New.
	(_bfd_sparc_elf_check_relocs): Unconditionally assign htab->elf.dynobj
	and call create_ifunc_sections().  For local STT_GNU_IFUNC symbols
	cons up a fake local hash table entry for it.  Unconditionally add
	a PLT refcount for STT_GNU_IFUNC symbols when h->def_regular.  Count
	dyn relocs for ifunc.
	(_bfd_sparc_elf_adjust_dynamic_symbol): Handle ifunc.
	(allocate_dynrelocs):  Unconditionally emit a PLT entry when STT_GNU_IFUNC
	and h->def_regular.  Count GOT dyn relocs for ifunc.
	(allocate_local_dynrelocs): New function.
	(_bfd_sparc_elf_size_dynamic_sections): Invoke it over the local hash table.
	Emit dynamic relocs to irelplt when not shared.  Treat iplt like splt.
	(_bfd_sparc_elf_relocate_section): Handle ifunc relocations by hand.
	(_bfd_sparc_elf_finish_dynamic_symbol): Adjust for non-dynamic ifunc plt
	in iplt/irelplt.

ld/testsuite/

	* ld-ifunc/ifunc.exp: Run for sparc.
This commit is contained in:
David S. Miller 2010-02-08 20:28:43 +00:00
parent 72fbc6e5ab
commit d0c9aeb3fc
12 changed files with 579 additions and 64 deletions

View file

@ -32,6 +32,49 @@
* elfxx-sparc.c (_bfd_sparc_elf_adjust_dynamic_symbol): Handle
nocopyreloc.
* reloc.c (BFD_RELOC_SPARC_JMP_IREL): New.
(BFD_RELOC_SPARC_IRELATIVE): Likewise.
* bfd-in2.h: Regenerate.
* libbfd.h: Regenerate.
* elfxx-sparc.h (_bfd_sparc_elf_link_hash_table): Add loc_hash_table
and loc_hash_memory.
(_bfd_sparc_elf_link_hash_table_free): Declare.
* elf32-sparc.c (elf32_sparc_add_symbol_hook): New.
(elf_backend_add_symbol_hook, elf_backend_post_process_headers,
bfd_elf32_bfd_link_hash_table_free): Define.
* elf64-sparc.c (elf64_sparc_add_symbol_hook): Set
has_ifunc_symbols if STT_GNU_IFUNC.
(bfd_elf64_bfd_link_hash_table_free): Define.
(elf_backend_post_process_headers): Define always.
* elfxx-sparc.c (sparc_jmp_irel_howto, sparc_irelative_howto): New.
(sparc_reloc_map): Add entries for new IFUNC relocs.
(_bfd_sparc_elf_reloc_type_lookup): Handle new IFUNC relocs.
(_bfd_sparc_elf_info_to_howto_ptr): Likewise.
(elf_sparc_local_htab_hash, elf_sparc_local_htab_eq,
elf_sparc_get_local_sym_hash): New.
(_bfd_sparc_elf_create_dynamic_sections): Move PLT ops initialization
from here...
(_bfd_sparc_elf_link_hash_table_create): ... to here. Allocate
local hash table.
(_bfd_sparc_elf_link_hash_table_free): New.
(create_ifunc_sections): New.
(_bfd_sparc_elf_check_relocs): Unconditionally assign htab->elf.dynobj
and call create_ifunc_sections(). For local STT_GNU_IFUNC symbols
cons up a fake local hash table entry for it. Unconditionally add
a PLT refcount for STT_GNU_IFUNC symbols when h->def_regular. Count
dyn relocs for ifunc.
(_bfd_sparc_elf_adjust_dynamic_symbol): Handle ifunc.
(allocate_dynrelocs): Unconditionally emit a PLT entry when
STT_GNU_IFUNC and h->def_regular. Count GOT dyn relocs for ifunc.
(allocate_local_dynrelocs): New function.
(_bfd_sparc_elf_size_dynamic_sections): Invoke it over the local hash
table. Emit dynamic relocs to irelplt when not shared. Treat iplt
like splt.
(_bfd_sparc_elf_relocate_section): Handle ifunc relocations by hand.
(_bfd_sparc_elf_finish_dynamic_symbol): Adjust for non-dynamic ifunc
plt in iplt/irelplt.
2010-02-08 Richard Sandiford <r.sandiford@uk.ibm.com>
* xcofflink.c (_bfd_xcoff_bfd_final_link): When calculating

View file

@ -2496,6 +2496,8 @@ relocation types already defined. */
BFD_RELOC_SPARC_GOTDATA_OP_HIX22,
BFD_RELOC_SPARC_GOTDATA_OP_LOX10,
BFD_RELOC_SPARC_GOTDATA_OP,
BFD_RELOC_SPARC_JMP_IREL,
BFD_RELOC_SPARC_IRELATIVE,
/* I think these are specific to SPARC a.out (e.g., Sun 4). */
BFD_RELOC_SPARC_BASE13,

View file

@ -167,6 +167,23 @@ elf32_sparc_reloc_type_class (const Elf_Internal_Rela *rela)
}
}
/* Hook called by the linker routine which adds symbols from an object
file. */
static bfd_boolean
elf32_sparc_add_symbol_hook (bfd * abfd ATTRIBUTE_UNUSED,
struct bfd_link_info * info ATTRIBUTE_UNUSED,
Elf_Internal_Sym * sym,
const char ** namep ATTRIBUTE_UNUSED,
flagword * flagsp ATTRIBUTE_UNUSED,
asection ** secp ATTRIBUTE_UNUSED,
bfd_vma * valp ATTRIBUTE_UNUSED)
{
if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
return TRUE;
}
#define TARGET_BIG_SYM bfd_elf32_sparc_vec
#define TARGET_BIG_NAME "elf32-sparc"
#define ELF_ARCH bfd_arch_sparc
@ -188,6 +205,8 @@ elf32_sparc_reloc_type_class (const Elf_Internal_Rela *rela)
_bfd_sparc_elf_reloc_name_lookup
#define bfd_elf32_bfd_link_hash_table_create \
_bfd_sparc_elf_link_hash_table_create
#define bfd_elf32_bfd_link_hash_table_free \
_bfd_sparc_elf_link_hash_table_free
#define bfd_elf32_bfd_relax_section _bfd_sparc_elf_relax_section
#define bfd_elf32_new_section_hook _bfd_sparc_elf_new_section_hook
#define elf_backend_copy_indirect_symbol \
@ -220,6 +239,9 @@ elf32_sparc_reloc_type_class (const Elf_Internal_Rela *rela)
#define elf_backend_got_header_size 4
#define elf_backend_rela_normal 1
#define elf_backend_post_process_headers _bfd_elf_set_osabi
#define elf_backend_add_symbol_hook elf32_sparc_add_symbol_hook
#include "elf32-target.h"
/* A wrapper around _bfd_sparc_elf_link_hash_table_create that identifies

View file

@ -424,6 +424,9 @@ 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)
elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
if (ELF_ST_TYPE (sym->st_info) == STT_REGISTER)
{
int reg;
@ -856,6 +859,8 @@ const struct elf_size_info elf64_sparc_size_info =
_bfd_sparc_elf_plt_sym_val
#define bfd_elf64_bfd_link_hash_table_create \
_bfd_sparc_elf_link_hash_table_create
#define bfd_elf64_bfd_link_hash_table_free \
_bfd_sparc_elf_link_hash_table_free
#define elf_info_to_howto \
_bfd_sparc_elf_info_to_howto
#define elf_backend_copy_indirect_symbol \
@ -910,6 +915,8 @@ const struct elf_size_info elf64_sparc_size_info =
/* Section 5.2.4 of the ABI specifies a 256-byte boundary for the table. */
#define elf_backend_plt_alignment 8
#define elf_backend_post_process_headers _bfd_elf_set_osabi
#include "elf64-target.h"
/* FreeBSD support */
@ -920,8 +927,6 @@ const struct elf_size_info elf64_sparc_size_info =
#undef ELF_OSABI
#define ELF_OSABI ELFOSABI_FREEBSD
#undef elf_backend_post_process_headers
#define elf_backend_post_process_headers _bfd_elf_set_osabi
#undef elf64_bed
#define elf64_bed elf64_sparc_fbsd_bed

View file

@ -31,6 +31,8 @@
#include "opcode/sparc.h"
#include "elfxx-sparc.h"
#include "elf-vxworks.h"
#include "objalloc.h"
#include "hashtab.h"
/* In case we're on a 32-bit machine, construct a 64-bit "-1" value. */
#define MINUS_ONE (~ (bfd_vma) 0)
@ -265,6 +267,10 @@ static reloc_howto_type _bfd_sparc_elf_howto_table[] =
HOWTO(R_SPARC_GOTDATA_OP_LOX10,0,2,0,FALSE,0,complain_overflow_dont, sparc_elf_lox10_reloc, "R_SPARC_GOTDATA_OP_LOX10",FALSE,0,0x000003ff, FALSE),
HOWTO(R_SPARC_GOTDATA_OP,0,0, 0,FALSE,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_GOTDATA_OP",FALSE,0,0x00000000,TRUE),
};
static reloc_howto_type sparc_jmp_irel_howto =
HOWTO(R_SPARC_JMP_IREL, 0,0,00,FALSE,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_JMP_IREL",FALSE,0,0x00000000,TRUE);
static reloc_howto_type sparc_irelative_howto =
HOWTO(R_SPARC_IRELATIVE, 0,0,00,FALSE,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_IRELATIVE",FALSE,0,0x00000000,TRUE);
static reloc_howto_type sparc_vtinherit_howto =
HOWTO (R_SPARC_GNU_VTINHERIT, 0,2,0,FALSE,0,complain_overflow_dont, NULL, "R_SPARC_GNU_VTINHERIT", FALSE,0, 0, FALSE);
static reloc_howto_type sparc_vtentry_howto =
@ -360,6 +366,8 @@ static const struct elf_reloc_map sparc_reloc_map[] =
{ BFD_RELOC_SPARC_GOTDATA_OP_LOX10, R_SPARC_GOTDATA_OP_LOX10 },
{ BFD_RELOC_SPARC_GOTDATA_OP, R_SPARC_GOTDATA_OP },
{ BFD_RELOC_SPARC_REGISTER, R_SPARC_REGISTER },
{ BFD_RELOC_SPARC_JMP_IREL, R_SPARC_JMP_IREL },
{ BFD_RELOC_SPARC_IRELATIVE, R_SPARC_IRELATIVE },
{ BFD_RELOC_VTABLE_INHERIT, R_SPARC_GNU_VTINHERIT },
{ BFD_RELOC_VTABLE_ENTRY, R_SPARC_GNU_VTENTRY },
{ BFD_RELOC_SPARC_REV32, R_SPARC_REV32 },
@ -373,6 +381,12 @@ _bfd_sparc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
switch (code)
{
case BFD_RELOC_SPARC_JMP_IREL:
return &sparc_jmp_irel_howto;
case BFD_RELOC_SPARC_IRELATIVE:
return &sparc_irelative_howto;
case BFD_RELOC_VTABLE_INHERIT:
return &sparc_vtinherit_howto;
@ -425,6 +439,12 @@ _bfd_sparc_elf_info_to_howto_ptr (unsigned int r_type)
{
switch (r_type)
{
case R_SPARC_JMP_IREL:
return &sparc_jmp_irel_howto;
case R_SPARC_IRELATIVE:
return &sparc_irelative_howto;
case R_SPARC_GNU_VTINHERIT:
return &sparc_vtinherit_howto;
@ -831,6 +851,78 @@ link_hash_newfunc (struct bfd_hash_entry *entry,
#define ELF32_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1"
#define ELF64_DYNAMIC_INTERPRETER "/usr/lib/sparcv9/ld.so.1"
/* Compute a hash of a local hash entry. We use elf_link_hash_entry
for local symbol so that we can handle local STT_GNU_IFUNC symbols
as global symbol. We reuse indx and dynstr_index for local symbol
hash since they aren't used by global symbols in this backend. */
static hashval_t
elf_sparc_local_htab_hash (const void *ptr)
{
struct elf_link_hash_entry *h
= (struct elf_link_hash_entry *) ptr;
return ELF_LOCAL_SYMBOL_HASH (h->indx, h->dynstr_index);
}
/* Compare local hash entries. */
static int
elf_sparc_local_htab_eq (const void *ptr1, const void *ptr2)
{
struct elf_link_hash_entry *h1
= (struct elf_link_hash_entry *) ptr1;
struct elf_link_hash_entry *h2
= (struct elf_link_hash_entry *) ptr2;
return h1->indx == h2->indx && h1->dynstr_index == h2->dynstr_index;
}
/* Find and/or create a hash entry for local symbol. */
static struct elf_link_hash_entry *
elf_sparc_get_local_sym_hash (struct _bfd_sparc_elf_link_hash_table *htab,
bfd *abfd, const Elf_Internal_Rela *rel,
bfd_boolean create)
{
struct _bfd_sparc_elf_link_hash_entry e, *ret;
asection *sec = abfd->sections;
unsigned long r_symndx;
hashval_t h;
void **slot;
r_symndx = SPARC_ELF_R_SYMNDX (htab, rel->r_info);
h = ELF_LOCAL_SYMBOL_HASH (sec->id, r_symndx);
e.elf.indx = sec->id;
e.elf.dynstr_index = r_symndx;
slot = htab_find_slot_with_hash (htab->loc_hash_table, &e, h,
create ? INSERT : NO_INSERT);
if (!slot)
return NULL;
if (*slot)
{
ret = (struct _bfd_sparc_elf_link_hash_entry *) *slot;
return &ret->elf;
}
ret = (struct _bfd_sparc_elf_link_hash_entry *)
objalloc_alloc ((struct objalloc *) htab->loc_hash_memory,
sizeof (struct _bfd_sparc_elf_link_hash_entry));
if (ret)
{
memset (ret, 0, sizeof (*ret));
ret->elf.indx = sec->id;
ret->elf.dynstr_index = r_symndx;
ret->elf.dynindx = -1;
ret->elf.plt.offset = (bfd_vma) -1;
ret->elf.got.offset = (bfd_vma) -1;
*slot = ret;
}
return &ret->elf;
}
/* Create a SPARC ELF linker hash table. */
struct bfd_link_hash_table *
@ -857,6 +949,10 @@ _bfd_sparc_elf_link_hash_table_create (bfd *abfd)
ret->bytes_per_rela = sizeof (Elf64_External_Rela);
ret->dynamic_interpreter = ELF64_DYNAMIC_INTERPRETER;
ret->dynamic_interpreter_size = sizeof ELF64_DYNAMIC_INTERPRETER;
ret->build_plt_entry = sparc64_plt_entry_build;
ret->plt_header_size = PLT64_HEADER_SIZE;
ret->plt_entry_size = PLT64_ENTRY_SIZE;
}
else
{
@ -872,6 +968,10 @@ _bfd_sparc_elf_link_hash_table_create (bfd *abfd)
ret->bytes_per_rela = sizeof (Elf32_External_Rela);
ret->dynamic_interpreter = ELF32_DYNAMIC_INTERPRETER;
ret->dynamic_interpreter_size = sizeof ELF32_DYNAMIC_INTERPRETER;
ret->build_plt_entry = sparc32_plt_entry_build;
ret->plt_header_size = PLT32_HEADER_SIZE;
ret->plt_entry_size = PLT32_ENTRY_SIZE;
}
if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc,
@ -882,9 +982,35 @@ _bfd_sparc_elf_link_hash_table_create (bfd *abfd)
return NULL;
}
ret->loc_hash_table = htab_try_create (1024,
elf_sparc_local_htab_hash,
elf_sparc_local_htab_eq,
NULL);
ret->loc_hash_memory = objalloc_create ();
if (!ret->loc_hash_table || !ret->loc_hash_memory)
{
free (ret);
return NULL;
}
return &ret->elf.root;
}
/* Destroy a SPARC ELF linker hash table. */
void
_bfd_sparc_elf_link_hash_table_free (struct bfd_link_hash_table *hash)
{
struct _bfd_sparc_elf_link_hash_table *htab
= (struct _bfd_sparc_elf_link_hash_table *) hash;
if (htab->loc_hash_table)
htab_delete (htab->loc_hash_table);
if (htab->loc_hash_memory)
objalloc_free ((struct objalloc *) htab->loc_hash_memory);
_bfd_generic_link_hash_table_free (hash);
}
/* Create .plt, .rela.plt, .got, .rela.got, .dynbss, and
.rela.bss sections in DYNOBJ, and set up shortcuts to them in our
hash table. */
@ -924,21 +1050,6 @@ _bfd_sparc_elf_create_dynamic_sections (bfd *dynobj,
= 4 * ARRAY_SIZE (sparc_vxworks_exec_plt_entry);
}
}
else
{
if (ABI_64_P (dynobj))
{
htab->build_plt_entry = sparc64_plt_entry_build;
htab->plt_header_size = PLT64_HEADER_SIZE;
htab->plt_entry_size = PLT64_ENTRY_SIZE;
}
else
{
htab->build_plt_entry = sparc32_plt_entry_build;
htab->plt_header_size = PLT32_HEADER_SIZE;
htab->plt_entry_size = PLT32_ENTRY_SIZE;
}
}
if (!htab->elf.splt || !htab->elf.srelplt || !htab->sdynbss
|| (!info->shared && !htab->srelbss))
@ -947,6 +1058,37 @@ _bfd_sparc_elf_create_dynamic_sections (bfd *dynobj,
return TRUE;
}
static bfd_boolean
create_ifunc_sections (bfd *abfd, struct bfd_link_info *info)
{
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
struct elf_link_hash_table *htab = elf_hash_table (info);
flagword flags, pltflags;
asection *s;
if (htab->irelifunc != NULL || htab->iplt != NULL)
return TRUE;
flags = bed->dynamic_sec_flags;
pltflags = flags | SEC_ALLOC | SEC_CODE | SEC_LOAD;
s = bfd_make_section_with_flags (abfd, ".iplt", pltflags);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
return FALSE;
htab->iplt = s;
s = bfd_make_section_with_flags (abfd, ".rela.iplt",
flags | SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s,
bed->s->log_file_align))
return FALSE;
htab->irelplt = s;
return TRUE;
}
/* Copy the extra info we tack onto an elf_link_hash_entry. */
void
@ -1074,12 +1216,18 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
BFD_ASSERT (is_sparc_elf (abfd) || num_relocs == 0);
if (htab->elf.dynobj == NULL)
htab->elf.dynobj = abfd;
if (!create_ifunc_sections (htab->elf.dynobj, info))
return FALSE;
rel_end = relocs + num_relocs;
for (rel = relocs; rel < rel_end; rel++)
{
unsigned int r_type;
unsigned long r_symndx;
struct elf_link_hash_entry *h;
Elf_Internal_Sym *isym;
r_symndx = SPARC_ELF_R_SYMNDX (htab, rel->r_info);
r_type = SPARC_ELF_R_TYPE (rel->r_info);
@ -1091,8 +1239,33 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
return FALSE;
}
isym = NULL;
if (r_symndx < symtab_hdr->sh_info)
h = NULL;
{
/* A local symbol. */
isym = bfd_sym_from_r_symndx (&htab->sym_cache,
abfd, r_symndx);
if (isym == NULL)
return FALSE;
/* Check relocation against local STT_GNU_IFUNC symbol. */
if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
{
h = elf_sparc_get_local_sym_hash (htab, abfd, rel,
TRUE);
if (h == NULL)
return FALSE;
/* Fake a STT_GNU_IFUNC symbol. */
h->type = STT_GNU_IFUNC;
h->def_regular = 1;
h->ref_regular = 1;
h->forced_local = 1;
h->root.type = bfd_link_hash_defined;
}
else
h = NULL;
}
else
{
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
@ -1101,6 +1274,12 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
h = (struct elf_link_hash_entry *) h->root.u.i.link;
}
if (h && h->type == STT_GNU_IFUNC)
{
if (h->def_regular)
h->plt.refcount += 1;
}
/* Compatibility with old R_SPARC_REV32 reloc conflicting
with R_SPARC_TLS_GD_HI22. */
if (! ABI_64_P (abfd) && ! checked_tlsgd)
@ -1239,8 +1418,6 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
if (htab->elf.sgot == NULL)
{
if (htab->elf.dynobj == NULL)
htab->elf.dynobj = abfd;
if (!_bfd_elf_create_got_section (htab->elf.dynobj, info))
return FALSE;
}
@ -1403,7 +1580,10 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
&& (sec->flags & SEC_ALLOC) != 0
&& h != NULL
&& (h->root.type == bfd_link_hash_defweak
|| !h->def_regular)))
|| !h->def_regular))
|| (!info->shared
&& h != NULL
&& h->type == STT_GNU_IFUNC))
{
struct _bfd_sparc_elf_dyn_relocs *p;
struct _bfd_sparc_elf_dyn_relocs **head;
@ -1413,9 +1593,6 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
section in dynobj and make room for the reloc. */
if (sreloc == NULL)
{
if (htab->elf.dynobj == NULL)
htab->elf.dynobj = abfd;
sreloc = _bfd_elf_make_dynamic_reloc_section
(sec, htab->elf.dynobj, htab->word_align_power,
abfd, /*rela?*/ TRUE);
@ -1435,13 +1612,8 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
easily. Oh well. */
asection *s;
void *vpp;
Elf_Internal_Sym *isym;
isym = bfd_sym_from_r_symndx (&htab->sym_cache,
abfd, r_symndx);
if (isym == NULL)
return FALSE;
BFD_ASSERT (isym != NULL);
s = bfd_section_from_elf_index (abfd, isym->st_shndx);
if (s == NULL)
s = sec;
@ -1684,6 +1856,7 @@ _bfd_sparc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
/* Make sure we know what is going on here. */
BFD_ASSERT (htab->elf.dynobj != NULL
&& (h->needs_plt
|| h->type == STT_GNU_IFUNC
|| h->u.weakdef != NULL
|| (h->def_dynamic
&& h->ref_regular
@ -1697,6 +1870,7 @@ _bfd_sparc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
some of their functions as STT_NOTYPE when they really should be
STT_FUNC. */
if (h->type == STT_FUNC
|| h->type == STT_GNU_IFUNC
|| h->needs_plt
|| (h->type == STT_NOTYPE
&& (h->root.type == bfd_link_hash_defined
@ -1704,9 +1878,10 @@ _bfd_sparc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
&& (h->root.u.def.section->flags & SEC_CODE) != 0))
{
if (h->plt.refcount <= 0
|| SYMBOL_CALLS_LOCAL (info, h)
|| (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
&& h->root.type == bfd_link_hash_undefweak))
|| (h->type != STT_GNU_IFUNC
&& (SYMBOL_CALLS_LOCAL (info, h)
|| (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
&& h->root.type == bfd_link_hash_undefweak))))
{
/* This case can occur if we saw a WPLT30 reloc in an input
file, but the symbol was never referred to by a dynamic
@ -1828,8 +2003,10 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf)
htab = _bfd_sparc_elf_hash_table (info);
BFD_ASSERT (htab != NULL);
if (htab->elf.dynamic_sections_created
&& h->plt.refcount > 0)
if ((htab->elf.dynamic_sections_created
&& h->plt.refcount > 0)
|| (h->type == STT_GNU_IFUNC
&& h->def_regular))
{
/* Make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic. */
@ -1840,10 +2017,14 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf)
return FALSE;
}
if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info->shared, h))
if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info->shared, h)
|| h->type == STT_GNU_IFUNC)
{
asection *s = htab->elf.splt;
if (s == NULL)
s = htab->elf.iplt;
/* Allocate room for the header. */
if (s->size == 0)
{
@ -1892,7 +2073,10 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf)
s->size += htab->plt_entry_size;
/* We also need to make an entry in the .rela.plt section. */
htab->elf.srelplt->size += SPARC_ELF_RELA_BYTES (htab);
if (s == htab->elf.splt)
htab->elf.srelplt->size += SPARC_ELF_RELA_BYTES (htab);
else
htab->elf.irelplt->size += SPARC_ELF_RELA_BYTES (htab);
if (htab->is_vxworks)
{
@ -1949,7 +2133,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf)
R_SPARC_TLS_GD_{HI22,LO10} needs one if local symbol and two if
global. */
if ((tls_type == GOT_TLS_GD && h->dynindx == -1)
|| tls_type == GOT_TLS_IE)
|| tls_type == GOT_TLS_IE
|| h->type == STT_GNU_IFUNC)
htab->elf.srelgot->size += SPARC_ELF_RELA_BYTES (htab);
else if (tls_type == GOT_TLS_GD)
htab->elf.srelgot->size += 2 * SPARC_ELF_RELA_BYTES (htab);
@ -2060,6 +2245,25 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf)
return TRUE;
}
/* Allocate space in .plt, .got and associated reloc sections for
local dynamic relocs. */
static bfd_boolean
allocate_local_dynrelocs (void **slot, void *inf)
{
struct elf_link_hash_entry *h
= (struct elf_link_hash_entry *) *slot;
if (h->type != STT_GNU_IFUNC
|| !h->def_regular
|| !h->ref_regular
|| !h->forced_local
|| h->root.type != bfd_link_hash_defined)
abort ();
return allocate_dynrelocs (h, inf);
}
/* Find any dynamic relocs that apply to read-only sections. */
static bfd_boolean
@ -2172,6 +2376,8 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd,
else if (p->count != 0)
{
srel = elf_section_data (p->sec)->sreloc;
if (!htab->elf.dynamic_sections_created)
srel = htab->elf.irelplt;
srel->size += p->count * SPARC_ELF_RELA_BYTES (htab);
if ((p->sec->output_section->flags & SEC_READONLY) != 0)
info->flags |= DF_TEXTREL;
@ -2222,6 +2428,9 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd,
sym dynamic relocs. */
elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, (PTR) info);
/* Allocate .plt and .got entries, and space for local symbols. */
htab_traverse (htab->loc_hash_table, allocate_local_dynrelocs, info);
if (! ABI_64_P (output_bfd)
&& !htab->is_vxworks
&& elf_hash_table (info)->dynamic_sections_created)
@ -2251,6 +2460,7 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd,
if (s == htab->elf.splt
|| s == htab->elf.sgot
|| s == htab->sdynbss
|| s == htab->elf.iplt
|| s == htab->elf.sgotplt)
{
/* Strip this section if we don't need it; see the
@ -2544,6 +2754,20 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd,
sym = local_syms + r_symndx;
sec = local_sections[r_symndx];
relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
if (!info->relocatable
&& ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
{
/* Relocate against local STT_GNU_IFUNC symbol. */
h = elf_sparc_get_local_sym_hash (htab, input_bfd,
rel, FALSE);
if (h == NULL)
abort ();
/* Set STT_GNU_IFUNC symbol value. */
h->root.u.def.value = sym->st_value;
h->root.u.def.section = sec;
}
}
else
{
@ -2580,6 +2804,111 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd,
if (info->relocatable)
continue;
if (h != NULL
&& h->type == STT_GNU_IFUNC
&& h->def_regular)
{
asection *plt_sec;
const char *name;
if ((input_section->flags & SEC_ALLOC) == 0
|| h->plt.offset == (bfd_vma) -1)
abort ();
plt_sec = htab->elf.splt;
if (! plt_sec)
plt_sec =htab->elf.iplt;
switch (r_type)
{
case R_SPARC_GOTDATA_HIX22:
case R_SPARC_GOTDATA_LOX10:
case R_SPARC_GOTDATA_OP_HIX22:
case R_SPARC_GOTDATA_OP_LOX10:
case R_SPARC_GOT10:
case R_SPARC_GOT13:
case R_SPARC_GOT22:
if (htab->elf.sgot == NULL)
abort ();
off = h->got.offset;
if (off == (bfd_vma) -1)
abort();
relocation = htab->elf.sgot->output_offset + off - got_base;
goto do_relocation;
case R_SPARC_WPLT30:
case R_SPARC_WDISP30:
relocation = (plt_sec->output_section->vma
+ plt_sec->output_offset + h->plt.offset);
goto do_relocation;
case R_SPARC_32:
case R_SPARC_64:
if (info->shared && h->non_got_ref)
{
Elf_Internal_Rela outrel;
bfd_vma offset;
offset = _bfd_elf_section_offset (output_bfd, info,
input_section,
rel->r_offset);
if (offset == (bfd_vma) -1
|| offset == (bfd_vma) -2)
abort();
outrel.r_offset = (input_section->output_section->vma
+ input_section->output_offset
+ offset);
if (h->dynindx == -1
|| h->forced_local
|| info->executable)
{
outrel.r_info = SPARC_ELF_R_INFO (htab, NULL,
0, R_SPARC_IRELATIVE);
outrel.r_addend = relocation + rel->r_addend;
}
else
{
if (h->dynindx == -1)
abort();
outrel.r_info = SPARC_ELF_R_INFO (htab, rel, h->dynindx, r_type);
outrel.r_addend = rel->r_addend;
}
sparc_elf_append_rela (output_bfd, sreloc, &outrel);
continue;
}
relocation = (plt_sec->output_section->vma
+ plt_sec->output_offset + h->plt.offset);
goto do_relocation;
case R_SPARC_HI22:
case R_SPARC_LO10:
/* We should only see such relocs in static links. */
if (info->shared)
abort();
relocation = (plt_sec->output_section->vma
+ plt_sec->output_offset + h->plt.offset);
goto do_relocation;
default:
if (h->root.root.string)
name = h->root.root.string;
else
name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym,
NULL);
(*_bfd_error_handler)
(_("%B: relocation %s against STT_GNU_IFUNC "
"symbol `%s' isn't handled by %s"), input_bfd,
_bfd_sparc_elf_howto_table[r_type].name,
name, __FUNCTION__);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
}
switch (r_type)
{
case R_SPARC_GOTDATA_HIX22:
@ -3496,10 +3825,12 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd,
}
if (r == bfd_reloc_continue)
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
contents, rel->r_offset,
relocation, rel->r_addend);
{
do_relocation:
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
contents, rel->r_offset,
relocation, rel->r_addend);
}
if (r != bfd_reloc_ok)
{
switch (r)
@ -3681,13 +4012,21 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd,
bfd_vma r_offset, got_offset;
int rela_index;
/* This symbol has an entry in the PLT. Set it up. */
/* When building a static executable, use .iplt and
.rela.iplt sections for STT_GNU_IFUNC symbols. */
if (htab->elf.splt != NULL)
{
splt = htab->elf.splt;
srela = htab->elf.srelplt;
}
else
{
splt = htab->elf.iplt;
srela = htab->elf.irelplt;
}
BFD_ASSERT (h->dynindx != -1);
splt = htab->elf.splt;
srela = htab->elf.srelplt;
BFD_ASSERT (splt != NULL && srela != NULL);
if (splt == NULL || srela == NULL)
abort ();
/* Fill in the entry in the .rela.plt section. */
if (htab->is_vxworks)
@ -3710,29 +4049,73 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd,
+ htab->elf.sgotplt->output_offset
+ got_offset);
rela.r_addend = 0;
rela.r_info = SPARC_ELF_R_INFO (htab, NULL, h->dynindx,
R_SPARC_JMP_SLOT);
}
else
{
bfd_boolean ifunc = FALSE;
/* Fill in the entry in the procedure linkage table. */
rela_index = SPARC_ELF_BUILD_PLT_ENTRY (htab, output_bfd, splt,
h->plt.offset, splt->size,
&r_offset);
if (h == NULL
|| h->dynindx == -1
|| ((info->executable
|| ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
&& h->def_regular
&& h->type == STT_GNU_IFUNC))
{
ifunc = TRUE;
BFD_ASSERT (h == NULL
|| (h->type == STT_GNU_IFUNC
&& h->def_regular
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)));
}
rela.r_offset = r_offset
+ (splt->output_section->vma + splt->output_offset);
if (! ABI_64_P (output_bfd)
|| h->plt.offset < (PLT64_LARGE_THRESHOLD * PLT64_ENTRY_SIZE))
if (ABI_64_P (output_bfd)
&& h->plt.offset >= (PLT64_LARGE_THRESHOLD * PLT64_ENTRY_SIZE))
{
rela.r_addend = 0;
if (ifunc)
{
rela.r_addend = (h->root.u.def.section->output_section->vma
+ h->root.u.def.section->output_offset
+ h->root.u.def.value);
rela.r_info = SPARC_ELF_R_INFO (htab, NULL, 0,
R_SPARC_IRELATIVE);
}
else
{
rela.r_addend = (-(h->plt.offset + 4)
- splt->output_section->vma
- splt->output_offset);
rela.r_info = SPARC_ELF_R_INFO (htab, NULL, h->dynindx,
R_SPARC_JMP_SLOT);
}
}
else
{
rela.r_addend = (-(h->plt.offset + 4)
- splt->output_section->vma
- splt->output_offset);
if (ifunc)
{
rela.r_addend = (h->root.u.def.section->output_section->vma
+ h->root.u.def.section->output_offset
+ h->root.u.def.value);
rela.r_info = SPARC_ELF_R_INFO (htab, NULL, 0,
R_SPARC_JMP_IREL);
}
else
{
rela.r_addend = 0;
rela.r_info = SPARC_ELF_R_INFO (htab, NULL, h->dynindx,
R_SPARC_JMP_SLOT);
}
}
}
rela.r_info = SPARC_ELF_R_INFO (htab, NULL, h->dynindx, R_SPARC_JMP_SLOT);
/* Adjust for the first 4 reserved elements in the .plt section
when setting the offset in the .rela.plt section.
@ -3780,11 +4163,29 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd,
the symbol was forced to be local because of a version file.
The entry in the global offset table will already have been
initialized in the relocate_section function. */
if (info->shared
&& SYMBOL_REFERENCES_LOCAL (info, h))
if (! info->shared
&& h->type == STT_GNU_IFUNC
&& h->def_regular)
{
asection *plt;
/* We load the GOT entry with the PLT entry. */
plt = htab->elf.splt ? htab->elf.splt : htab->elf.iplt;
SPARC_ELF_PUT_WORD (htab, output_bfd,
(plt->output_section->vma
+ plt->output_offset + h->plt.offset),
htab->elf.sgot->contents
+ (h->got.offset & ~(bfd_vma) 1));
return TRUE;
}
else if (info->shared
&& SYMBOL_REFERENCES_LOCAL (info, h))
{
asection *sec = h->root.u.def.section;
rela.r_info = SPARC_ELF_R_INFO (htab, NULL, 0, R_SPARC_RELATIVE);
if (h->type == STT_GNU_IFUNC)
rela.r_info = SPARC_ELF_R_INFO (htab, NULL, 0, R_SPARC_IRELATIVE);
else
rela.r_info = SPARC_ELF_R_INFO (htab, NULL, 0, R_SPARC_RELATIVE);
rela.r_addend = (h->root.u.def.value
+ sec->output_section->vma
+ sec->output_offset);
@ -3823,9 +4224,10 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd,
/* Mark some specially defined symbols as absolute. On VxWorks,
_GLOBAL_OFFSET_TABLE_ is not absolute: it is relative to the
".got" section. Likewise _PROCEDURE_LINKAGE_TABLE_ and ".plt". */
if (strcmp (h->root.root.string, "_DYNAMIC") == 0
|| (!htab->is_vxworks
&& (h == htab->elf.hgot || h == htab->elf.hplt)))
if (sym != NULL
&& (strcmp (h->root.root.string, "_DYNAMIC") == 0
|| (!htab->is_vxworks
&& (h == htab->elf.hgot || h == htab->elf.hplt))))
sym->st_shndx = SHN_ABS;
return TRUE;
@ -4021,6 +4423,21 @@ sparc_vxworks_finish_shared_plt (bfd *output_bfd, struct bfd_link_info *info)
htab->elf.splt->contents + i * 4);
}
/* Finish up local dynamic symbol handling. We set the contents of
various dynamic sections here. */
static bfd_boolean
finish_local_dynamic_symbol (void **slot, void *inf)
{
struct elf_link_hash_entry *h
= (struct elf_link_hash_entry *) *slot;
struct bfd_link_info *info
= (struct bfd_link_info *) inf;
return _bfd_sparc_elf_finish_dynamic_symbol (info->output_bfd, info,
h, NULL);
}
bfd_boolean
_bfd_sparc_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
{
@ -4083,6 +4500,9 @@ _bfd_sparc_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *i
elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize =
SPARC_ELF_WORD_BYTES (htab);
/* Fill PLT and GOT entries for local STT_GNU_IFUNC symbols. */
htab_traverse (htab->loc_hash_table, finish_local_dynamic_symbol, info);
return TRUE;
}

View file

@ -59,6 +59,10 @@ struct _bfd_sparc_elf_link_hash_table
/* Small local sym cache. */
struct sym_cache sym_cache;
/* Used by local STT_GNU_IFUNC symbols. */
htab_t loc_hash_table;
void *loc_hash_memory;
/* True if the target system is VxWorks. */
int is_vxworks;
@ -102,6 +106,8 @@ extern bfd_boolean _bfd_sparc_elf_mkobject
(bfd *);
extern struct bfd_link_hash_table *_bfd_sparc_elf_link_hash_table_create
(bfd *);
extern void _bfd_sparc_elf_link_hash_table_free
(struct bfd_link_hash_table *);
extern bfd_boolean _bfd_sparc_elf_create_dynamic_sections
(bfd *, struct bfd_link_info *);
extern void _bfd_sparc_elf_copy_indirect_symbol

View file

@ -928,6 +928,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_SPARC_GOTDATA_OP_HIX22",
"BFD_RELOC_SPARC_GOTDATA_OP_LOX10",
"BFD_RELOC_SPARC_GOTDATA_OP",
"BFD_RELOC_SPARC_JMP_IREL",
"BFD_RELOC_SPARC_IRELATIVE",
"BFD_RELOC_SPARC_BASE13",
"BFD_RELOC_SPARC_BASE22",
"BFD_RELOC_SPARC_10",

View file

@ -1870,6 +1870,10 @@ ENUMX
BFD_RELOC_SPARC_GOTDATA_OP_LOX10
ENUMX
BFD_RELOC_SPARC_GOTDATA_OP
ENUMX
BFD_RELOC_SPARC_JMP_IREL
ENUMX
BFD_RELOC_SPARC_IRELATIVE
ENUMDOC
SPARC ELF relocations. There is probably some overlap with other
relocation types already defined.

View file

@ -1,3 +1,7 @@
2010-02-08 David S. Miller <davem@davemloft.net>
* elf/sparc.h (R_SPARC_JMP_IREL, R_SPARC_IRELATIVE): Define.
2010-01-13 Joel Brobecker <brobecker@adacore.com>
Add new DW_AT_use_GNAT_descriptive_type CU attribute.

View file

@ -164,6 +164,8 @@ START_RELOC_NUMBERS (elf_sparc_reloc_type)
EMPTY_RELOC (R_SPARC_max_std)
RELOC_NUMBER (R_SPARC_JMP_IREL, 248)
RELOC_NUMBER (R_SPARC_IRELATIVE, 249)
RELOC_NUMBER (R_SPARC_GNU_VTINHERIT, 250)
RELOC_NUMBER (R_SPARC_GNU_VTENTRY, 251)
RELOC_NUMBER (R_SPARC_REV32, 252)

View file

@ -1,3 +1,7 @@
2010-02-08 David S. Miller <davem@davemloft.net>
* ld-ifunc/ifunc.exp: Run for sparc.
2010-02-08 Nathan Sidwell <nathan@codesourcery.com>
* ld-powerpc/apuinfo-nul.s: New.

View file

@ -23,11 +23,12 @@
# Written by Nick Clifton <nickc@redhat.com>
# IFUNC support has only been implemented for the ix86, x86_64 and powerpc
# so far.
# IFUNC support has only been implemented for the ix86, x86_64, powerpc,
# and sparc so far.
if {!(([istarget "i?86-*-*"]
|| [istarget "x86_64-*-*"]
|| [istarget "powerpc*-*-*"])
|| [istarget "powerpc*-*-*"]
|| [istarget "sparc*-*-*"])
&& ([istarget "*-*-elf*"]
|| ([istarget "*-*-linux*"]
&& ![istarget "*-*-*aout*"]