2009-06-13  H.J. Lu  <hongjiu.lu@intel.com>

	PR ld/10269
	* elf32-i386.c: Include "objalloc.h" and "hashtab.h".
	(elf_i386_link_hash_table): Add loc_hash_table and
	loc_hash_memory.
	(elf_i386_local_hash): New.
	(elf_i386_local_htab_hash): Likewise.
	(elf_i386_local_htab_eq): Likewise.
	(elf_i386_get_local_sym_hash): Likewise.
	(elf_i386_link_hash_table_free): Likewise.
	(elf_i386_allocate_local_dynrelocs): Likewise.
	(elf_i386_finish_local_dynamic_symbol): Likewise.
	(bfd_elf64_bfd_link_hash_table_free): Likewise.
	(elf_i386_link_hash_table_create): Create loc_hash_table and
	loc_hash_memory.
	(elf_i386_check_relocs): Handle local STT_GNU_IFUNC symbols.
	(elf_i386_size_dynamic_sections): Likewise.
	(elf_i386_relocate_section): Likewise.
	(elf_i386_finish_dynamic_sections): Likewise.
	(elf_i386_finish_dynamic_symbol): Check _DYNAMIC only if sym
	isn't NULL.

	* elf64-x86-64.c: Include "objalloc.h" and "hashtab.h".
	(elf64_x86_64_link_hash_table): Add loc_hash_table and
	loc_hash_memory.
	(elf64_x86_64_local_hash): New.
	(elf64_x86_64_local_htab_hash): Likewise.
	(elf64_x86_64_local_htab_eq): Likewise.
	(elf64_x86_64_get_local_sym_hash): Likewise.
	(elf64_x86_64_link_hash_table_free): Likewise.
	(elf64_x86_64_allocate_local_dynrelocs): Likewise.
	(elf64_x86_64_finish_local_dynamic_symbol): Likewise.
	(bfd_elf64_bfd_link_hash_table_free): Likewise.
	(elf64_x86_64_link_hash_table_create): Create loc_hash_table
	and loc_hash_memory.
	(elf64_x86_64_check_relocs): Handle local STT_GNU_IFUNC
	symbols.
	(elf64_x86_64_size_dynamic_sections): Likewise.
	(elf64_x86_64_relocate_section): Likewise.
	(elf64_x86_64_finish_dynamic_sections): Likewise.
	(elf64_x86_64_finish_dynamic_symbol): Check _DYNAMIC only if
	sym isn't NULL.

gas/

2009-06-13  H.J. Lu  <hongjiu.lu@intel.com>

	PR ld/10269
	* config/tc-i386.c (md_apply_fix): Use TC_FORCE_RELOCATION
	instead of generic_force_reloc.

	* config/tc-i386.h (TC_FORCE_RELOCATION): New.

ld/testsuite/

2009-06-13  H.J. Lu  <hongjiu.lu@intel.com>

	PR ld/10269
	*: ld-ifunc/ifunc-1-local-x86.d: New.
	*: ld-ifunc/ifunc-1-local-x86.s: Likewise.
	*: ld-ifunc/ifunc-2-local-i386.d: Likewise.
	*: ld-ifunc/ifunc-2-local-i386.s: Likewise.
	*: ld-ifunc/ifunc-2-local-x86-64.d: Likewise.
	*: ld-ifunc/ifunc-2-local-x86-64.s: Likewise.
	*: ld-ifunc/ifunc-4-local-x86.d: Likewise.
	*: ld-ifunc/ifunc-4-local-x86.s: Likewise.
	*: ld-ifunc/ifunc-5-local-i386.s: Likewise.
	*: ld-ifunc/ifunc-5-local-x86-64.s: Likewise.
	*: ld-ifunc/ifunc-5a-local-i386.d: Likewise.
	*: ld-ifunc/ifunc-5a-local-x86-64.d: Likewise.
	*: ld-ifunc/ifunc-5b-local-i386.d: Likewise.
	*: ld-ifunc/ifunc-5b-local-x86-64.d: Likewise.
This commit is contained in:
H.J. Lu 2009-06-14 01:39:46 +00:00
parent 46ebc6b590
commit c25bc9fc0d
21 changed files with 684 additions and 16 deletions

View File

@ -1,3 +1,47 @@
2009-06-13 H.J. Lu <hongjiu.lu@intel.com>
PR ld/10269
* elf32-i386.c: Include "objalloc.h" and "hashtab.h".
(elf_i386_link_hash_table): Add loc_hash_table and
loc_hash_memory.
(elf_i386_local_hash): New.
(elf_i386_local_htab_hash): Likewise.
(elf_i386_local_htab_eq): Likewise.
(elf_i386_get_local_sym_hash): Likewise.
(elf_i386_link_hash_table_free): Likewise.
(elf_i386_allocate_local_dynrelocs): Likewise.
(elf_i386_finish_local_dynamic_symbol): Likewise.
(bfd_elf64_bfd_link_hash_table_free): Likewise.
(elf_i386_link_hash_table_create): Create loc_hash_table and
loc_hash_memory.
(elf_i386_check_relocs): Handle local STT_GNU_IFUNC symbols.
(elf_i386_size_dynamic_sections): Likewise.
(elf_i386_relocate_section): Likewise.
(elf_i386_finish_dynamic_sections): Likewise.
(elf_i386_finish_dynamic_symbol): Check _DYNAMIC only if sym
isn't NULL.
* elf64-x86-64.c: Include "objalloc.h" and "hashtab.h".
(elf64_x86_64_link_hash_table): Add loc_hash_table and
loc_hash_memory.
(elf64_x86_64_local_hash): New.
(elf64_x86_64_local_htab_hash): Likewise.
(elf64_x86_64_local_htab_eq): Likewise.
(elf64_x86_64_get_local_sym_hash): Likewise.
(elf64_x86_64_link_hash_table_free): Likewise.
(elf64_x86_64_allocate_local_dynrelocs): Likewise.
(elf64_x86_64_finish_local_dynamic_symbol): Likewise.
(bfd_elf64_bfd_link_hash_table_free): Likewise.
(elf64_x86_64_link_hash_table_create): Create loc_hash_table
and loc_hash_memory.
(elf64_x86_64_check_relocs): Handle local STT_GNU_IFUNC
symbols.
(elf64_x86_64_size_dynamic_sections): Likewise.
(elf64_x86_64_relocate_section): Likewise.
(elf64_x86_64_finish_dynamic_sections): Likewise.
(elf64_x86_64_finish_dynamic_symbol): Check _DYNAMIC only if
sym isn't NULL.
2009-06-10 Philip Blundell <philb@gnu.org> 2009-06-10 Philip Blundell <philb@gnu.org>
* elf32-arm.c (elf32_arm_fix_exidx_coverage): Avoid crash if * elf32-arm.c (elf32_arm_fix_exidx_coverage): Avoid crash if

View File

@ -26,6 +26,8 @@
#include "elf-bfd.h" #include "elf-bfd.h"
#include "elf-vxworks.h" #include "elf-vxworks.h"
#include "bfd_stdint.h" #include "bfd_stdint.h"
#include "objalloc.h"
#include "hashtab.h"
/* 386 uses REL relocations instead of RELA. */ /* 386 uses REL relocations instead of RELA. */
#define USE_REL 1 #define USE_REL 1
@ -706,6 +708,10 @@ struct elf_i386_link_hash_table
/* _TLS_MODULE_BASE_ symbol. */ /* _TLS_MODULE_BASE_ symbol. */
struct bfd_link_hash_entry *tls_module_base; struct bfd_link_hash_entry *tls_module_base;
/* Used by local STT_GNU_IFUNC symbols. */
htab_t loc_hash_table;
void *loc_hash_memory;
}; };
/* Get the i386 ELF linker hash table from a link_info structure. */ /* Get the i386 ELF linker hash table from a link_info structure. */
@ -748,6 +754,82 @@ elf_i386_link_hash_newfunc (struct bfd_hash_entry *entry,
return entry; return entry;
} }
static hashval_t
elf_i386_local_hash (int id, int r_sym)
{
return ((((id & 0xff) << 24) | ((id & 0xff00) << 8))
^ r_sym ^ (id >> 16));
}
/* 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_i386_local_htab_hash (const void *ptr)
{
struct elf_link_hash_entry *h
= (struct elf_link_hash_entry *) ptr;
return elf_i386_local_hash (h->indx, h->dynstr_index);
}
/* Compare local hash entries. */
static int
elf_i386_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_i386_get_local_sym_hash (struct elf_i386_link_hash_table *htab,
bfd *abfd, const Elf_Internal_Rela *rel,
bfd_boolean create)
{
struct elf_i386_link_hash_entry e, *ret;
asection *sec = abfd->sections;
hashval_t h = elf_i386_local_hash (sec->id,
ELF32_R_SYM (rel->r_info));
void **slot;
e.elf.indx = sec->id;
e.elf.dynstr_index = ELF32_R_SYM (rel->r_info);
slot = htab_find_slot_with_hash (htab->loc_hash_table, &e, h,
create ? INSERT : NO_INSERT);
if (!slot)
return NULL;
if (*slot)
{
ret = (struct elf_i386_link_hash_entry *) *slot;
return &ret->elf;
}
ret = (struct elf_i386_link_hash_entry *)
objalloc_alloc ((struct objalloc *) htab->loc_hash_memory,
sizeof (struct elf_i386_link_hash_entry));
if (ret)
{
memset (ret, 0, sizeof (*ret));
ret->elf.indx = sec->id;
ret->elf.dynstr_index = ELF32_R_SYM (rel->r_info);
ret->elf.dynindx = -1;
ret->elf.plt.offset = (bfd_vma) -1;
ret->elf.got.offset = (bfd_vma) -1;
*slot = ret;
}
return &ret->elf;
}
/* Create an i386 ELF linker hash table. */ /* Create an i386 ELF linker hash table. */
static struct bfd_link_hash_table * static struct bfd_link_hash_table *
@ -788,9 +870,38 @@ elf_i386_link_hash_table_create (bfd *abfd)
ret->plt0_pad_byte = 0; ret->plt0_pad_byte = 0;
ret->tls_module_base = NULL; ret->tls_module_base = NULL;
ret->loc_hash_table = htab_try_create (1024,
elf_i386_local_htab_hash,
elf_i386_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; return &ret->elf.root;
} }
/* Destroy an i386 ELF linker hash table. */
static void
elf_i386_link_hash_table_free (struct bfd_link_hash_table *hash)
{
struct elf_i386_link_hash_table *htab
= (struct elf_i386_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 .got, .gotplt, and .rela.got sections in DYNOBJ, and set up
shortcuts to them in our hash table. */
/* Create .got, .gotplt, and .rel.got sections in DYNOBJ, and set up /* Create .got, .gotplt, and .rel.got sections in DYNOBJ, and set up
shortcuts to them in our hash table. */ shortcuts to them in our hash table. */
@ -1228,6 +1339,7 @@ elf_i386_check_relocs (bfd *abfd,
const Elf_Internal_Rela *rel; const Elf_Internal_Rela *rel;
const Elf_Internal_Rela *rel_end; const Elf_Internal_Rela *rel_end;
asection *sreloc; asection *sreloc;
Elf_Internal_Sym *isymbuf;
if (info->relocatable) if (info->relocatable)
return TRUE; return TRUE;
@ -1236,6 +1348,7 @@ elf_i386_check_relocs (bfd *abfd,
htab = elf_i386_hash_table (info); htab = elf_i386_hash_table (info);
symtab_hdr = &elf_symtab_hdr (abfd); symtab_hdr = &elf_symtab_hdr (abfd);
isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
sym_hashes = elf_sym_hashes (abfd); sym_hashes = elf_sym_hashes (abfd);
sreloc = NULL; sreloc = NULL;
@ -1259,14 +1372,50 @@ elf_i386_check_relocs (bfd *abfd,
} }
if (r_symndx < symtab_hdr->sh_info) if (r_symndx < symtab_hdr->sh_info)
h = NULL; {
/* A local symbol. */
Elf_Internal_Sym *isym;
/* Read this BFD's local symbols. */
if (isymbuf == NULL)
{
if (isymbuf == NULL)
isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
symtab_hdr->sh_info, 0,
NULL, NULL, NULL);
if (isymbuf == NULL)
return FALSE;
}
/* Check relocation against local STT_GNU_IFUNC symbol. */
isym = isymbuf + r_symndx;
if (ELF32_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
{
h = elf_i386_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 else
{ {
h = sym_hashes[r_symndx - symtab_hdr->sh_info]; h = sym_hashes[r_symndx - symtab_hdr->sh_info];
while (h->root.type == bfd_link_hash_indirect while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning) || h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link; h = (struct elf_link_hash_entry *) h->root.u.i.link;
}
if (h != NULL)
{
/* Create the ifunc sections for static executables. If we /* Create the ifunc sections for static executables. If we
never see an indirect function symbol nor we are building never see an indirect function symbol nor we are building
a static executable, those sections will be empty and a static executable, those sections will be empty and
@ -1331,7 +1480,8 @@ elf_i386_check_relocs (bfd *abfd,
(_("%B: relocation %s against STT_GNU_IFUNC " (_("%B: relocation %s against STT_GNU_IFUNC "
"symbol `%s' isn't handled by %s"), abfd, "symbol `%s' isn't handled by %s"), abfd,
elf_howto_table[r_type].name, elf_howto_table[r_type].name,
h->root.root.string, __FUNCTION__); h != NULL ? h->root.root.string : "a local symbol",
__FUNCTION__);
bfd_set_error (bfd_error_bad_value); bfd_set_error (bfd_error_bad_value);
return FALSE; return FALSE;
@ -2337,6 +2487,25 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
return TRUE; return TRUE;
} }
/* Allocate space in .plt, .got and associated reloc sections for
local dynamic relocs. */
static bfd_boolean
elf_i386_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 elf_i386_allocate_dynrelocs (h, inf);
}
/* Find any dynamic relocs that apply to read-only sections. */ /* Find any dynamic relocs that apply to read-only sections. */
static bfd_boolean static bfd_boolean
@ -2511,6 +2680,11 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
sym dynamic relocs. */ sym dynamic relocs. */
elf_link_hash_traverse (&htab->elf, elf_i386_allocate_dynrelocs, info); elf_link_hash_traverse (&htab->elf, elf_i386_allocate_dynrelocs, info);
/* Allocate .plt and .got entries, and space for local symbols. */
htab_traverse (htab->loc_hash_table,
elf_i386_allocate_local_dynrelocs,
info);
/* For every jump slot reserved in the sgotplt, reloc_count is /* For every jump slot reserved in the sgotplt, reloc_count is
incremented. However, when we reserve space for TLS descriptors, incremented. However, when we reserve space for TLS descriptors,
it's not incremented, so in order to compute the space reserved it's not incremented, so in order to compute the space reserved
@ -2916,6 +3090,18 @@ elf_i386_relocate_section (bfd *output_bfd,
break; break;
} }
} }
else if (ELF32_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
{
/* Relocate against local STT_GNU_IFUNC symbol. */
h = elf_i386_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 else
{ {
@ -2990,8 +3176,8 @@ elf_i386_relocate_section (bfd *output_bfd,
asection *sreloc; asection *sreloc;
bfd_vma offset; bfd_vma offset;
/* Need a dynamic relocation get the the real /* Need a dynamic relocation to get the real function
function adddress. */ adddress. */
offset = _bfd_elf_section_offset (output_bfd, offset = _bfd_elf_section_offset (output_bfd,
info, info,
input_section, input_section,
@ -4310,16 +4496,34 @@ do_glob_dat:
bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
} }
/* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. SYM may
be NULL for local symbols.
On VxWorks, the _GLOBAL_OFFSET_TABLE_ symbol is not absolute: it On VxWorks, the _GLOBAL_OFFSET_TABLE_ symbol is not absolute: it
is relative to the ".got" section. */ is relative to the ".got" section. */
if (strcmp (h->root.root.string, "_DYNAMIC") == 0 if (sym != NULL
|| (!htab->is_vxworks && h == htab->elf.hgot)) && (strcmp (h->root.root.string, "_DYNAMIC") == 0
|| (!htab->is_vxworks && h == htab->elf.hgot)))
sym->st_shndx = SHN_ABS; sym->st_shndx = SHN_ABS;
return TRUE; return TRUE;
} }
/* Finish up local dynamic symbol handling. We set the contents of
various dynamic sections here. */
static bfd_boolean
elf_i386_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 elf_i386_finish_dynamic_symbol (info->output_bfd, info,
h, NULL);
}
/* Used to decide how to sort relocs in an optimal manner for the /* Used to decide how to sort relocs in an optimal manner for the
dynamic linker, before writing them out. */ dynamic linker, before writing them out. */
@ -4527,6 +4731,11 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd,
if (htab->sgot && htab->sgot->size > 0) if (htab->sgot && htab->sgot->size > 0)
elf_section_data (htab->sgot->output_section)->this_hdr.sh_entsize = 4; elf_section_data (htab->sgot->output_section)->this_hdr.sh_entsize = 4;
/* Fill PLT and GOT entries for local STT_GNU_IFUNC symbols. */
htab_traverse (htab->loc_hash_table,
elf_i386_finish_local_dynamic_symbol,
info);
return TRUE; return TRUE;
} }
@ -4592,6 +4801,7 @@ elf_i386_add_symbol_hook (bfd * abfd ATTRIBUTE_UNUSED,
#define bfd_elf32_bfd_is_local_label_name elf_i386_is_local_label_name #define bfd_elf32_bfd_is_local_label_name elf_i386_is_local_label_name
#define bfd_elf32_bfd_link_hash_table_create elf_i386_link_hash_table_create #define bfd_elf32_bfd_link_hash_table_create elf_i386_link_hash_table_create
#define bfd_elf32_bfd_link_hash_table_free elf_i386_link_hash_table_free
#define bfd_elf32_bfd_reloc_type_lookup elf_i386_reloc_type_lookup #define bfd_elf32_bfd_reloc_type_lookup elf_i386_reloc_type_lookup
#define bfd_elf32_bfd_reloc_name_lookup elf_i386_reloc_name_lookup #define bfd_elf32_bfd_reloc_name_lookup elf_i386_reloc_name_lookup

View File

@ -26,6 +26,8 @@
#include "libbfd.h" #include "libbfd.h"
#include "elf-bfd.h" #include "elf-bfd.h"
#include "bfd_stdint.h" #include "bfd_stdint.h"
#include "objalloc.h"
#include "hashtab.h"
#include "elf/x86-64.h" #include "elf/x86-64.h"
@ -520,6 +522,10 @@ struct elf64_x86_64_link_hash_table
/* _TLS_MODULE_BASE_ symbol. */ /* _TLS_MODULE_BASE_ symbol. */
struct bfd_link_hash_entry *tls_module_base; struct bfd_link_hash_entry *tls_module_base;
/* Used by local STT_GNU_IFUNC symbols. */
htab_t loc_hash_table;
void *loc_hash_memory;
}; };
/* Get the x86-64 ELF linker hash table from a link_info structure. */ /* Get the x86-64 ELF linker hash table from a link_info structure. */
@ -562,6 +568,82 @@ elf64_x86_64_link_hash_newfunc (struct bfd_hash_entry *entry,
return entry; return entry;
} }
static hashval_t
elf64_x86_64_local_hash (int id, int r_sym)
{
return ((((id & 0xff) << 24) | ((id & 0xff00) << 8))
^ r_sym ^ (id >> 16));
}
/* 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
elf64_x86_64_local_htab_hash (const void *ptr)
{
struct elf_link_hash_entry *h
= (struct elf_link_hash_entry *) ptr;
return elf64_x86_64_local_hash (h->indx, h->dynstr_index);
}
/* Compare local hash entries. */
static int
elf64_x86_64_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 *
elf64_x86_64_get_local_sym_hash (struct elf64_x86_64_link_hash_table *htab,
bfd *abfd, const Elf_Internal_Rela *rel,
bfd_boolean create)
{
struct elf64_x86_64_link_hash_entry e, *ret;
asection *sec = abfd->sections;
hashval_t h = elf64_x86_64_local_hash (sec->id,
ELF64_R_SYM (rel->r_info));
void **slot;
e.elf.indx = sec->id;
e.elf.dynstr_index = ELF64_R_SYM (rel->r_info);
slot = htab_find_slot_with_hash (htab->loc_hash_table, &e, h,
create ? INSERT : NO_INSERT);
if (!slot)
return NULL;
if (*slot)
{
ret = (struct elf64_x86_64_link_hash_entry *) *slot;
return &ret->elf;
}
ret = (struct elf64_x86_64_link_hash_entry *)
objalloc_alloc ((struct objalloc *) htab->loc_hash_memory,
sizeof (struct elf64_x86_64_link_hash_entry));
if (ret)
{
memset (ret, 0, sizeof (*ret));
ret->elf.indx = sec->id;
ret->elf.dynstr_index = ELF64_R_SYM (rel->r_info);
ret->elf.dynindx = -1;
ret->elf.plt.offset = (bfd_vma) -1;
ret->elf.got.offset = (bfd_vma) -1;
*slot = ret;
}
return &ret->elf;
}
/* Create an X86-64 ELF linker hash table. */ /* Create an X86-64 ELF linker hash table. */
static struct bfd_link_hash_table * static struct bfd_link_hash_table *
@ -600,9 +682,35 @@ elf64_x86_64_link_hash_table_create (bfd *abfd)
ret->sgotplt_jump_table_size = 0; ret->sgotplt_jump_table_size = 0;
ret->tls_module_base = NULL; ret->tls_module_base = NULL;
ret->loc_hash_table = htab_try_create (1024,
elf64_x86_64_local_htab_hash,
elf64_x86_64_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; return &ret->elf.root;
} }
/* Destroy an X86-64 ELF linker hash table. */
static void
elf64_x86_64_link_hash_table_free (struct bfd_link_hash_table *hash)
{
struct elf64_x86_64_link_hash_table *htab
= (struct elf64_x86_64_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 .got, .gotplt, and .rela.got sections in DYNOBJ, and set up /* Create .got, .gotplt, and .rela.got sections in DYNOBJ, and set up
shortcuts to them in our hash table. */ shortcuts to them in our hash table. */
@ -1012,6 +1120,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
const Elf_Internal_Rela *rel; const Elf_Internal_Rela *rel;
const Elf_Internal_Rela *rel_end; const Elf_Internal_Rela *rel_end;
asection *sreloc; asection *sreloc;
Elf_Internal_Sym *isymbuf;
if (info->relocatable) if (info->relocatable)
return TRUE; return TRUE;
@ -1020,6 +1129,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
htab = elf64_x86_64_hash_table (info); htab = elf64_x86_64_hash_table (info);
symtab_hdr = &elf_symtab_hdr (abfd); symtab_hdr = &elf_symtab_hdr (abfd);
isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
sym_hashes = elf_sym_hashes (abfd); sym_hashes = elf_sym_hashes (abfd);
sreloc = NULL; sreloc = NULL;
@ -1042,14 +1152,50 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
} }
if (r_symndx < symtab_hdr->sh_info) if (r_symndx < symtab_hdr->sh_info)
h = NULL; {
/* A local symbol. */
Elf_Internal_Sym *isym;
/* Read this BFD's local symbols. */
if (isymbuf == NULL)
{
if (isymbuf == NULL)
isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
symtab_hdr->sh_info, 0,
NULL, NULL, NULL);
if (isymbuf == NULL)
return FALSE;
}
/* Check relocation against local STT_GNU_IFUNC symbol. */
isym = isymbuf + r_symndx;
if (ELF64_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
{
h = elf64_x86_64_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 else
{ {
h = sym_hashes[r_symndx - symtab_hdr->sh_info]; h = sym_hashes[r_symndx - symtab_hdr->sh_info];
while (h->root.type == bfd_link_hash_indirect while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning) || h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link; h = (struct elf_link_hash_entry *) h->root.u.i.link;
}
if (h != NULL)
{
/* Create the ifunc sections for static executables. If we /* Create the ifunc sections for static executables. If we
never see an indirect function symbol nor we are building never see an indirect function symbol nor we are building
a static executable, those sections will be empty and a static executable, those sections will be empty and
@ -1117,7 +1263,8 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
(_("%B: relocation %s against STT_GNU_IFUNC " (_("%B: relocation %s against STT_GNU_IFUNC "
"symbol `%s' isn't handled by %s"), abfd, "symbol `%s' isn't handled by %s"), abfd,
x86_64_elf_howto_table[r_type].name, x86_64_elf_howto_table[r_type].name,
h->root.root.string, __FUNCTION__); h != NULL ? h->root.root.string : "a local symbol",
__FUNCTION__);
bfd_set_error (bfd_error_bad_value); bfd_set_error (bfd_error_bad_value);
return FALSE; return FALSE;
@ -2145,6 +2292,25 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
return TRUE; return TRUE;
} }
/* Allocate space in .plt, .got and associated reloc sections for
local dynamic relocs. */
static bfd_boolean
elf64_x86_64_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 elf64_x86_64_allocate_dynrelocs (h, inf);
}
/* Find any dynamic relocs that apply to read-only sections. */ /* Find any dynamic relocs that apply to read-only sections. */
static bfd_boolean static bfd_boolean
@ -2313,6 +2479,11 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
elf_link_hash_traverse (&htab->elf, elf64_x86_64_allocate_dynrelocs, elf_link_hash_traverse (&htab->elf, elf64_x86_64_allocate_dynrelocs,
info); info);
/* Allocate .plt and .got entries, and space for local symbols. */
htab_traverse (htab->loc_hash_table,
elf64_x86_64_allocate_local_dynrelocs,
info);
/* For every jump slot reserved in the sgotplt, reloc_count is /* For every jump slot reserved in the sgotplt, reloc_count is
incremented. However, when we reserve space for TLS descriptors, incremented. However, when we reserve space for TLS descriptors,
it's not incremented, so in order to compute the space reserved it's not incremented, so in order to compute the space reserved
@ -2630,7 +2801,21 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
sym = local_syms + r_symndx; sym = local_syms + r_symndx;
sec = local_sections[r_symndx]; sec = local_sections[r_symndx];
relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); relocation = _bfd_elf_rela_local_sym (output_bfd, sym,
&sec, rel);
/* Relocate against local STT_GNU_IFUNC symbol. */
if (ELF64_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
{
h = elf64_x86_64_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 else
{ {
@ -2710,8 +2895,8 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
bfd_byte *loc; bfd_byte *loc;
asection *sreloc; asection *sreloc;
/* Need a dynamic relocation get the the real /* Need a dynamic relocation to get the real function
function address. */ address. */
outrel.r_offset = _bfd_elf_section_offset (output_bfd, outrel.r_offset = _bfd_elf_section_offset (output_bfd,
info, info,
input_section, input_section,
@ -3941,14 +4126,31 @@ do_glob_dat:
bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
} }
/* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. SYM may
if (strcmp (h->root.root.string, "_DYNAMIC") == 0 be NULL for local symbols. */
|| h == htab->elf.hgot) if (sym != NULL
&& (strcmp (h->root.root.string, "_DYNAMIC") == 0
|| h == htab->elf.hgot))
sym->st_shndx = SHN_ABS; sym->st_shndx = SHN_ABS;
return TRUE; return TRUE;
} }
/* Finish up local dynamic symbol handling. We set the contents of
various dynamic sections here. */
static bfd_boolean
elf64_x86_64_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 elf64_x86_64_finish_dynamic_symbol (info->output_bfd,
info, h, NULL);
}
/* Used to decide how to sort relocs in an optimal manner for the /* Used to decide how to sort relocs in an optimal manner for the
dynamic linker, before writing them out. */ dynamic linker, before writing them out. */
@ -4139,6 +4341,11 @@ elf64_x86_64_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *inf
elf_section_data (htab->sgot->output_section)->this_hdr.sh_entsize elf_section_data (htab->sgot->output_section)->this_hdr.sh_entsize
= GOT_ENTRY_SIZE; = GOT_ENTRY_SIZE;
/* Fill PLT and GOT entries for local STT_GNU_IFUNC symbols. */
htab_traverse (htab->loc_hash_table,
elf64_x86_64_finish_local_dynamic_symbol,
info);
return TRUE; return TRUE;
} }
@ -4387,6 +4594,8 @@ static const struct bfd_elf_special_section
#define bfd_elf64_bfd_link_hash_table_create \ #define bfd_elf64_bfd_link_hash_table_create \
elf64_x86_64_link_hash_table_create elf64_x86_64_link_hash_table_create
#define bfd_elf64_bfd_link_hash_table_free \
elf64_x86_64_link_hash_table_free
#define bfd_elf64_bfd_reloc_type_lookup elf64_x86_64_reloc_type_lookup #define bfd_elf64_bfd_reloc_type_lookup elf64_x86_64_reloc_type_lookup
#define bfd_elf64_bfd_reloc_name_lookup \ #define bfd_elf64_bfd_reloc_name_lookup \
elf64_x86_64_reloc_name_lookup elf64_x86_64_reloc_name_lookup

View File

@ -1,3 +1,11 @@
2009-06-13 H.J. Lu <hongjiu.lu@intel.com>
PR ld/10269
* config/tc-i386.c (md_apply_fix): Use TC_FORCE_RELOCATION
instead of generic_force_reloc.
* config/tc-i386.h (TC_FORCE_RELOCATION): New.
2009-06-11 Anthony Green <green@moxielogic.com> 2009-06-11 Anthony Green <green@moxielogic.com>
* config/tc-moxie.c (md_chars_to_number): Define. * config/tc-moxie.c (md_chars_to_number): Define.

View File

@ -7235,7 +7235,7 @@ md_apply_fix (fixP, valP, seg)
if ((sym_seg == seg if ((sym_seg == seg
|| (symbol_section_p (fixP->fx_addsy) || (symbol_section_p (fixP->fx_addsy)
&& sym_seg != absolute_section)) && sym_seg != absolute_section))
&& !generic_force_reloc (fixP)) && !TC_FORCE_RELOCATION (fixP))
{ {
/* Yes, we add the values in twice. This is because /* Yes, we add the values in twice. This is because
bfd_install_relocation subtracts them out again. I think bfd_install_relocation subtracts them out again. I think

View File

@ -138,6 +138,12 @@ extern int tc_i386_fix_adjustable (struct fix *);
(OUTPUT_FLAVOR == bfd_target_elf_flavour) (OUTPUT_FLAVOR == bfd_target_elf_flavour)
#endif #endif
/* BSF_GNU_INDIRECT_FUNCTION symbols always need relocatoon. */
#define TC_FORCE_RELOCATION(FIX) \
((symbol_get_bfdsym ((FIX)->fx_addsy)->flags \
& BSF_GNU_INDIRECT_FUNCTION) \
|| generic_force_reloc (FIX))
/* This expression evaluates to true if the relocation is for a local /* This expression evaluates to true if the relocation is for a local
object for which we still want to do the relocation at runtime. object for which we still want to do the relocation at runtime.
False if we are willing to perform this relocation while building False if we are willing to perform this relocation while building

View File

@ -1,3 +1,21 @@
2009-06-13 H.J. Lu <hongjiu.lu@intel.com>
PR ld/10269
*: ld-ifunc/ifunc-1-local-x86.d: New.
*: ld-ifunc/ifunc-1-local-x86.s: Likewise.
*: ld-ifunc/ifunc-2-local-i386.d: Likewise.
*: ld-ifunc/ifunc-2-local-i386.s: Likewise.
*: ld-ifunc/ifunc-2-local-x86-64.d: Likewise.
*: ld-ifunc/ifunc-2-local-x86-64.s: Likewise.
*: ld-ifunc/ifunc-4-local-x86.d: Likewise.
*: ld-ifunc/ifunc-4-local-x86.s: Likewise.
*: ld-ifunc/ifunc-5-local-i386.s: Likewise.
*: ld-ifunc/ifunc-5-local-x86-64.s: Likewise.
*: ld-ifunc/ifunc-5a-local-i386.d: Likewise.
*: ld-ifunc/ifunc-5a-local-x86-64.d: Likewise.
*: ld-ifunc/ifunc-5b-local-i386.d: Likewise.
*: ld-ifunc/ifunc-5b-local-x86-64.d: Likewise.
2009-06-03 H.J. Lu <hongjiu.lu@intel.com> 2009-06-03 H.J. Lu <hongjiu.lu@intel.com>
* ld-ifunc/ifunc-2-x86-64.d: Pass --64 to as and -melf_x86_64 to * ld-ifunc/ifunc-2-x86-64.d: Pass --64 to as and -melf_x86_64 to

View File

@ -0,0 +1,7 @@
#ld: -shared
#objdump: -dw
#target: x86_64-*-* i?86-*-*
#...
[ \t0-9a-f]+:[ \t0-9a-f]+call[ \t0-9a-fq]+<\*ABS\*@plt>
#pass

View File

@ -0,0 +1,13 @@
.type foo, %gnu_indirect_function
.set __GI_foo, foo
.text
.type foo, @function
foo:
ret
.size foo, .-foo
.globl bar
.type bar, @function
bar:
call __GI_foo@PLT
ret
.size bar, .-bar

View File

@ -0,0 +1,8 @@
#ld: -m elf_i386 -shared
#as: --32
#objdump: -dw
#target: x86_64-*-* i?86-*-*
#...
[ \t0-9a-f]+:[ \t0-9a-f]+call[ \t0-9a-f]+<\*ABS\*@plt>
#pass

View File

@ -0,0 +1,18 @@
.type foo, %gnu_indirect_function
.set __GI_foo, foo
.text
.type foo, @function
foo:
ret
.size foo, .-foo
.globl bar
.type bar, @function
bar:
call .L6
.L6:
popl %ebx
addl $_GLOBAL_OFFSET_TABLE_+[.-.L6], %ebx
call __GI_foo
leal __GI_foo@GOTOFF(%ebx), %eax
ret
.size bar, .-bar

View File

@ -0,0 +1,9 @@
#as: --64
#ld: -shared -melf_x86_64
#objdump: -dw
#target: x86_64-*-*
#...
[ \t0-9a-f]+:[ \t0-9a-f]+call[ \t0-9a-fq]+<\*ABS\*@plt>
[ \t0-9a-f]+:[ \t0-9a-f]+lea[ \t]+.*\(%rip\),%rax.*[ \t0-9a-fq]+<\*ABS\*@plt>
#pass

View File

@ -0,0 +1,17 @@
.type foo, %gnu_indirect_function
.global __GI_foo
.hidden __GI_foo
.set __GI_foo, foo
.text
.globl foo
.type foo, @function
foo:
ret
.size foo, .-foo
.globl bar
.type bar, @function
bar:
call __GI_foo
leaq __GI_foo(%rip), %rax
ret
.size bar, .-bar

View File

@ -0,0 +1,7 @@
#ld:
#readelf: -r --wide
#target: x86_64-*-* i?86-*-*
#...
[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_[_0-9A-Z]+_IRELATIVE[ ]*[0-9a-f]*
#pass

View File

@ -0,0 +1,18 @@
.text
.type foo, %gnu_indirect_function
.type foo, @function
foo:
ret
.size foo, .-foo
.type start,"function"
.global start
start:
.type _start,"function"
.global _start
_start:
.type __start,"function"
.global __start
__start:
.type __start,"function"
call foo
movl $foo,%eax

View File

@ -0,0 +1,22 @@
.text
.type foo, %gnu_indirect_function
.type foo, @function
foo:
ret
.size foo, .-foo
.type start,"function"
.global start
start:
.type _start,"function"
.global _start
_start:
.type __start,"function"
.global __start
__start:
.type __start,"function"
call .L6
.L6:
popl %ebx
addl $_GLOBAL_OFFSET_TABLE_+[.-.L6], %ebx
call foo@PLT
leal foo@GOT(%ebx), %eax

View File

@ -0,0 +1,18 @@
.text
.type foo, %gnu_indirect_function
.type foo, @function
foo:
ret
.size foo, .-foo
.type start,"function"
.global start
start:
.type _start,"function"
.global _start
_start:
.type __start,"function"
.global __start
__start:
.type __start,"function"
call foo@PLT
movq foo@GOTPCREL(%rip), %rax

View File

@ -0,0 +1,9 @@
#source: ifunc-5-local-i386.s
#ld: -m elf_i386
#as: --32
#readelf: -r --wide
#target: x86_64-*-* i?86-*-*
Relocation section '.rel.plt' at .*
[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_386_IRELATIVE[ ]*

View File

@ -0,0 +1,9 @@
#source: ifunc-5-local-x86-64.s
#as: --64
#ld: -melf_x86_64
#readelf: -r --wide
#target: x86_64-*-*
Relocation section '.rela.plt' at .*
[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_X86_64_IRELATIVE[ ]+[0-9a-f]*

View File

@ -0,0 +1,9 @@
#source: ifunc-5-local-i386.s
#ld: -shared -m elf_i386 -z nocombreloc
#as: --32
#readelf: -r --wide
#target: x86_64-*-* i?86-*-*
Relocation section '.rel.plt' at .*
[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_386_IRELATIVE[ ]*

View File

@ -0,0 +1,9 @@
#source: ifunc-5-local-x86-64.s
#as: --64
#ld: -melf_x86_64 -shared -z nocombreloc
#readelf: -r --wide
#target: x86_64-*-*
Relocation section '.rela.plt' at .*
[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_X86_64_IRELATIVE[ ]+[0-9a-f]*