+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>
* elf32-arm.c (elf32_arm_fix_exidx_coverage): Avoid crash if
#include "elf-bfd.h"
#include "elf-vxworks.h"
#include "bfd_stdint.h"
+#include "objalloc.h"
+#include "hashtab.h"
/* 386 uses REL relocations instead of RELA. */
#define USE_REL 1
/* _TLS_MODULE_BASE_ symbol. */
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. */
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. */
static struct bfd_link_hash_table *
ret->plt0_pad_byte = 0;
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;
}
+/* 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
shortcuts to them in our hash table. */
const Elf_Internal_Rela *rel;
const Elf_Internal_Rela *rel_end;
asection *sreloc;
+ Elf_Internal_Sym *isymbuf;
if (info->relocatable)
return TRUE;
htab = elf_i386_hash_table (info);
symtab_hdr = &elf_symtab_hdr (abfd);
+ isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
sym_hashes = elf_sym_hashes (abfd);
sreloc = NULL;
}
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
{
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ }
+ if (h != NULL)
+ {
/* Create the ifunc sections for static executables. If we
never see an indirect function symbol nor we are building
a static executable, those sections will be empty and
(_("%B: relocation %s against STT_GNU_IFUNC "
"symbol `%s' isn't handled by %s"), abfd,
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);
return FALSE;
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. */
static bfd_boolean
sym dynamic relocs. */
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
incremented. However, when we reserve space for TLS descriptors,
it's not incremented, so in order to compute the space reserved
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
{
asection *sreloc;
bfd_vma offset;
- /* Need a dynamic relocation get the the real
- function adddress. */
+ /* Need a dynamic relocation to get the real function
+ adddress. */
offset = _bfd_elf_section_offset (output_bfd,
info,
input_section,
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
is relative to the ".got" section. */
- if (strcmp (h->root.root.string, "_DYNAMIC") == 0
- || (!htab->is_vxworks && h == htab->elf.hgot))
+ if (sym != NULL
+ && (strcmp (h->root.root.string, "_DYNAMIC") == 0
+ || (!htab->is_vxworks && h == htab->elf.hgot)))
sym->st_shndx = SHN_ABS;
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
dynamic linker, before writing them out. */
if (htab->sgot && htab->sgot->size > 0)
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;
}
#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_free elf_i386_link_hash_table_free
#define bfd_elf32_bfd_reloc_type_lookup elf_i386_reloc_type_lookup
#define bfd_elf32_bfd_reloc_name_lookup elf_i386_reloc_name_lookup
#include "libbfd.h"
#include "elf-bfd.h"
#include "bfd_stdint.h"
+#include "objalloc.h"
+#include "hashtab.h"
#include "elf/x86-64.h"
/* _TLS_MODULE_BASE_ symbol. */
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. */
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. */
static struct bfd_link_hash_table *
ret->sgotplt_jump_table_size = 0;
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;
}
+/* 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
shortcuts to them in our hash table. */
const Elf_Internal_Rela *rel;
const Elf_Internal_Rela *rel_end;
asection *sreloc;
+ Elf_Internal_Sym *isymbuf;
if (info->relocatable)
return TRUE;
htab = elf64_x86_64_hash_table (info);
symtab_hdr = &elf_symtab_hdr (abfd);
+ isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
sym_hashes = elf_sym_hashes (abfd);
sreloc = NULL;
}
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
{
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ }
+ if (h != NULL)
+ {
/* Create the ifunc sections for static executables. If we
never see an indirect function symbol nor we are building
a static executable, those sections will be empty and
(_("%B: relocation %s against STT_GNU_IFUNC "
"symbol `%s' isn't handled by %s"), abfd,
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);
return FALSE;
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. */
static bfd_boolean
elf_link_hash_traverse (&htab->elf, elf64_x86_64_allocate_dynrelocs,
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
incremented. However, when we reserve space for TLS descriptors,
it's not incremented, so in order to compute the space reserved
sym = local_syms + 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
{
bfd_byte *loc;
asection *sreloc;
- /* Need a dynamic relocation get the the real
- function address. */
+ /* Need a dynamic relocation to get the real function
+ address. */
outrel.r_offset = _bfd_elf_section_offset (output_bfd,
info,
input_section,
bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
}
- /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */
- if (strcmp (h->root.root.string, "_DYNAMIC") == 0
- || h == htab->elf.hgot)
+ /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. SYM may
+ be NULL for local symbols. */
+ if (sym != NULL
+ && (strcmp (h->root.root.string, "_DYNAMIC") == 0
+ || h == htab->elf.hgot))
sym->st_shndx = SHN_ABS;
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
dynamic linker, before writing them out. */
elf_section_data (htab->sgot->output_section)->this_hdr.sh_entsize
= 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;
}
#define bfd_elf64_bfd_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_name_lookup \
elf64_x86_64_reloc_name_lookup
+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>
* config/tc-moxie.c (md_chars_to_number): Define.
if ((sym_seg == seg
|| (symbol_section_p (fixP->fx_addsy)
&& sym_seg != absolute_section))
- && !generic_force_reloc (fixP))
+ && !TC_FORCE_RELOCATION (fixP))
{
/* Yes, we add the values in twice. This is because
bfd_install_relocation subtracts them out again. I think
(OUTPUT_FLAVOR == bfd_target_elf_flavour)
#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
object for which we still want to do the relocation at runtime.
False if we are willing to perform this relocation while building
+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>
* ld-ifunc/ifunc-2-x86-64.d: Pass --64 to as and -melf_x86_64 to
--- /dev/null
+#ld: -shared
+#objdump: -dw
+#target: x86_64-*-* i?86-*-*
+
+#...
+[ \t0-9a-f]+:[ \t0-9a-f]+call[ \t0-9a-fq]+<\*ABS\*@plt>
+#pass
--- /dev/null
+ .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
--- /dev/null
+#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
--- /dev/null
+ .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
--- /dev/null
+#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
--- /dev/null
+ .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
--- /dev/null
+#ld:
+#readelf: -r --wide
+#target: x86_64-*-* i?86-*-*
+
+#...
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_[_0-9A-Z]+_IRELATIVE[ ]*[0-9a-f]*
+#pass
--- /dev/null
+ .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
--- /dev/null
+ .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
--- /dev/null
+ .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
--- /dev/null
+#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[ ]*
--- /dev/null
+#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]*
--- /dev/null
+#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[ ]*
--- /dev/null
+#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]*