bfd/
2009-06-01 H.J. Lu <hongjiu.lu@intel.com> PR ld/10205 * elf32-i386.c (elf_howto_table): Add R_386_IRELATIVE. (elf_i386_reloc_type_lookup): Likewise. (R_386_tls): Removed. (R_386_irelative): New. (R_386_vt_offset): Updated. (elf_i386_rtype_to_howto): Likewise. (elf_i386_link_hash_table): Add igotplt, iplt and irelplt. (elf_i386_link_hash_table_create): Initialize igotplt, iplt and irelplt. (elf_i386_check_relocs): Handle STT_GNU_IFUNC symbol first. (elf_i386_adjust_dynamic_symbol): Likewise. (elf_i386_allocate_dynrelocs): Likewise. (elf_i386_relocate_section): Likewise. (elf_i386_size_dynamic_sections): Set up .iplt and .igot.plt sections. (elf_i386_finish_dynamic_symbol): When building a static executable, use .iplt, .igot.plt and .rel.iplt sections for STT_GNU_IFUNC symbols. Generate R_386_IRELATIVE relocation for locally defined STT_GNU_IFUNC symbol. * elf64-x86-64.c (x86_64_elf_howto): Add R_X86_64_IRELATIVE. (x86_64_reloc_map): Likewise. (R_X86_64_standard): Updated. (elf64_x86_64_link_hash_table): Add igotplt, iplt and irelplt. (elf64_x86_64_link_hash_table_create): Initialize igotplt, iplt and irelplt. (elf64_x86_64_check_relocs): Handle STT_GNU_IFUNC symbol first. (elf64_x86_64_adjust_dynamic_symbol): Likewise. (elf64_x86_64_allocate_dynrelocs): Likewise. (elf64_x86_64_relocate_section): Likewise. (elf64_x86_64_size_dynamic_sections): Set up .iplt and .igot.plt sections. (elf64_x86_64_finish_dynamic_symbol): When building a static executable, use .iplt, .igot.plt and .rela.iplt sections for STT_GNU_IFUNC symbols. Generate R_X86_64_IRELATIVE relocation for locally defined STT_GNU_IFUNC symbol. * reloc.c (BFD_RELOC_386_IRELATIVE): New. (BFD_RELOC_X86_64_IRELATIVE): Likewise. * bfd-in2.h: Regenerated. * libbfd.h: Likewise. include/elf/ 2009-06-01 H.J. Lu <hongjiu.lu@intel.com> PR ld/10205 * i386.h (R_386_IRELATIVE): New. * x86-64.h (R_X86_64_IRELATIVE): Likewise. ld/testsuite/ 2009-06-01 H.J. Lu <hongjiu.lu@intel.com> PR ld/10205 * ld-ifunc/ifunc.exp (contains_irelative_reloc): New. Use it on executable and shared library. Run *.d. * ld-ifunc/lib.c: Add a hidden alias, __GI_library_func2, for library_func2. (library_func): New. * ld-ifunc/ifunc-1-x86.d: New. * ld-ifunc/ifunc-1-x86.s: Likewise. * ld-ifunc/ifunc-2-i386.d: Likewise. * ld-ifunc/ifunc-2-i386.s: Likewise. * ld-ifunc/ifunc-2-x86-64.d: Likewise. * ld-ifunc/ifunc-2-x86-64.s: Likewise. * ld-ifunc/ifunc-3a-x86.d: Likewise. * ld-ifunc/ifunc-3b-x86.d: Likewise. * ld-ifunc/ifunc-3-x86.s: Likewise. * ld-ifunc/ifunc-4-x86.d: Likewise. * ld-ifunc/ifunc-4-x86.s: Likewise. * ld-ifunc/ifunc-5-i386.d: Likewise. * ld-ifunc/ifunc-5-i386.s: Likewise. * ld-ifunc/ifunc-5-x86-64.d: Likewise. * ld-ifunc/ifunc-5-x86-64.s: Likewise.
This commit is contained in:
parent
3aa14d16c6
commit
cbe950e9fe
|
@ -1,3 +1,49 @@
|
||||||
|
2009-06-01 H.J. Lu <hongjiu.lu@intel.com>
|
||||||
|
|
||||||
|
PR ld/10205
|
||||||
|
* elf32-i386.c (elf_howto_table): Add R_386_IRELATIVE.
|
||||||
|
(elf_i386_reloc_type_lookup): Likewise.
|
||||||
|
(R_386_tls): Removed.
|
||||||
|
(R_386_irelative): New.
|
||||||
|
(R_386_vt_offset): Updated.
|
||||||
|
(elf_i386_rtype_to_howto): Likewise.
|
||||||
|
(elf_i386_link_hash_table): Add igotplt, iplt and irelplt.
|
||||||
|
(elf_i386_link_hash_table_create): Initialize igotplt,
|
||||||
|
iplt and irelplt.
|
||||||
|
(elf_i386_check_relocs): Handle STT_GNU_IFUNC symbol first.
|
||||||
|
(elf_i386_adjust_dynamic_symbol): Likewise.
|
||||||
|
(elf_i386_allocate_dynrelocs): Likewise.
|
||||||
|
(elf_i386_relocate_section): Likewise.
|
||||||
|
(elf_i386_size_dynamic_sections): Set up .iplt and .igot.plt
|
||||||
|
sections.
|
||||||
|
(elf_i386_finish_dynamic_symbol): When building a static
|
||||||
|
executable, use .iplt, .igot.plt and .rel.iplt sections for
|
||||||
|
STT_GNU_IFUNC symbols. Generate R_386_IRELATIVE relocation for
|
||||||
|
locally defined STT_GNU_IFUNC symbol.
|
||||||
|
|
||||||
|
* elf64-x86-64.c (x86_64_elf_howto): Add R_X86_64_IRELATIVE.
|
||||||
|
(x86_64_reloc_map): Likewise.
|
||||||
|
(R_X86_64_standard): Updated.
|
||||||
|
(elf64_x86_64_link_hash_table): Add igotplt, iplt and irelplt.
|
||||||
|
(elf64_x86_64_link_hash_table_create): Initialize igotplt,
|
||||||
|
iplt and irelplt.
|
||||||
|
(elf64_x86_64_check_relocs): Handle STT_GNU_IFUNC symbol first.
|
||||||
|
(elf64_x86_64_adjust_dynamic_symbol): Likewise.
|
||||||
|
(elf64_x86_64_allocate_dynrelocs): Likewise.
|
||||||
|
(elf64_x86_64_relocate_section): Likewise.
|
||||||
|
(elf64_x86_64_size_dynamic_sections): Set up .iplt and .igot.plt
|
||||||
|
sections.
|
||||||
|
(elf64_x86_64_finish_dynamic_symbol): When building a static
|
||||||
|
executable, use .iplt, .igot.plt and .rela.iplt sections for
|
||||||
|
STT_GNU_IFUNC symbols. Generate R_X86_64_IRELATIVE relocation
|
||||||
|
for locally defined STT_GNU_IFUNC symbol.
|
||||||
|
|
||||||
|
* reloc.c (BFD_RELOC_386_IRELATIVE): New.
|
||||||
|
(BFD_RELOC_X86_64_IRELATIVE): Likewise.
|
||||||
|
|
||||||
|
* bfd-in2.h: Regenerated.
|
||||||
|
* libbfd.h: Likewise.
|
||||||
|
|
||||||
2009-06-01 H.J. Lu <hongjiu.lu@intel.com>
|
2009-06-01 H.J. Lu <hongjiu.lu@intel.com>
|
||||||
|
|
||||||
* elf-bfd.h (struct bfd_elf_section_data): Remove indirect_relocs.
|
* elf-bfd.h (struct bfd_elf_section_data): Remove indirect_relocs.
|
||||||
|
|
|
@ -2840,6 +2840,7 @@ relaxation. */
|
||||||
BFD_RELOC_386_TLS_GOTDESC,
|
BFD_RELOC_386_TLS_GOTDESC,
|
||||||
BFD_RELOC_386_TLS_DESC_CALL,
|
BFD_RELOC_386_TLS_DESC_CALL,
|
||||||
BFD_RELOC_386_TLS_DESC,
|
BFD_RELOC_386_TLS_DESC,
|
||||||
|
BFD_RELOC_386_IRELATIVE,
|
||||||
|
|
||||||
/* x86-64/elf relocations */
|
/* x86-64/elf relocations */
|
||||||
BFD_RELOC_X86_64_GOT32,
|
BFD_RELOC_X86_64_GOT32,
|
||||||
|
@ -2868,6 +2869,7 @@ relaxation. */
|
||||||
BFD_RELOC_X86_64_GOTPC32_TLSDESC,
|
BFD_RELOC_X86_64_GOTPC32_TLSDESC,
|
||||||
BFD_RELOC_X86_64_TLSDESC_CALL,
|
BFD_RELOC_X86_64_TLSDESC_CALL,
|
||||||
BFD_RELOC_X86_64_TLSDESC,
|
BFD_RELOC_X86_64_TLSDESC,
|
||||||
|
BFD_RELOC_X86_64_IRELATIVE,
|
||||||
|
|
||||||
/* ns32k relocations */
|
/* ns32k relocations */
|
||||||
BFD_RELOC_NS32K_IMM_8,
|
BFD_RELOC_NS32K_IMM_8,
|
||||||
|
|
428
bfd/elf32-i386.c
428
bfd/elf32-i386.c
|
@ -138,10 +138,13 @@ static reloc_howto_type elf_howto_table[]=
|
||||||
HOWTO(R_386_TLS_DESC, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
|
HOWTO(R_386_TLS_DESC, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
|
||||||
bfd_elf_generic_reloc, "R_386_TLS_DESC",
|
bfd_elf_generic_reloc, "R_386_TLS_DESC",
|
||||||
TRUE, 0xffffffff, 0xffffffff, FALSE),
|
TRUE, 0xffffffff, 0xffffffff, FALSE),
|
||||||
|
HOWTO(R_386_IRELATIVE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
|
||||||
|
bfd_elf_generic_reloc, "R_386_IRELATIVE",
|
||||||
|
TRUE, 0xffffffff, 0xffffffff, FALSE),
|
||||||
|
|
||||||
/* Another gap. */
|
/* Another gap. */
|
||||||
#define R_386_tls (R_386_TLS_DESC + 1 - R_386_tls_offset)
|
#define R_386_irelative (R_386_IRELATIVE + 1 - R_386_tls_offset)
|
||||||
#define R_386_vt_offset (R_386_GNU_VTINHERIT - R_386_tls)
|
#define R_386_vt_offset (R_386_GNU_VTINHERIT - R_386_irelative)
|
||||||
|
|
||||||
/* GNU extension to record C++ vtable hierarchy. */
|
/* GNU extension to record C++ vtable hierarchy. */
|
||||||
HOWTO (R_386_GNU_VTINHERIT, /* type */
|
HOWTO (R_386_GNU_VTINHERIT, /* type */
|
||||||
|
@ -316,6 +319,10 @@ elf_i386_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
|
||||||
TRACE ("BFD_RELOC_386_TLS_DESC");
|
TRACE ("BFD_RELOC_386_TLS_DESC");
|
||||||
return &elf_howto_table[R_386_TLS_DESC - R_386_tls_offset];
|
return &elf_howto_table[R_386_TLS_DESC - R_386_tls_offset];
|
||||||
|
|
||||||
|
case BFD_RELOC_386_IRELATIVE:
|
||||||
|
TRACE ("BFD_RELOC_386_IRELATIVE");
|
||||||
|
return &elf_howto_table[R_386_IRELATIVE];
|
||||||
|
|
||||||
case BFD_RELOC_VTABLE_INHERIT:
|
case BFD_RELOC_VTABLE_INHERIT:
|
||||||
TRACE ("BFD_RELOC_VTABLE_INHERIT");
|
TRACE ("BFD_RELOC_VTABLE_INHERIT");
|
||||||
return &elf_howto_table[R_386_GNU_VTINHERIT - R_386_vt_offset];
|
return &elf_howto_table[R_386_GNU_VTINHERIT - R_386_vt_offset];
|
||||||
|
@ -355,9 +362,9 @@ elf_i386_rtype_to_howto (bfd *abfd, unsigned r_type)
|
||||||
&& ((indx = r_type - R_386_ext_offset) - R_386_standard
|
&& ((indx = r_type - R_386_ext_offset) - R_386_standard
|
||||||
>= R_386_ext - R_386_standard)
|
>= R_386_ext - R_386_standard)
|
||||||
&& ((indx = r_type - R_386_tls_offset) - R_386_ext
|
&& ((indx = r_type - R_386_tls_offset) - R_386_ext
|
||||||
>= R_386_tls - R_386_ext)
|
>= R_386_irelative - R_386_ext)
|
||||||
&& ((indx = r_type - R_386_vt_offset) - R_386_tls
|
&& ((indx = r_type - R_386_vt_offset) - R_386_irelative
|
||||||
>= R_386_vt - R_386_tls))
|
>= R_386_vt - R_386_irelative))
|
||||||
{
|
{
|
||||||
(*_bfd_error_handler) (_("%B: invalid relocation type %d"),
|
(*_bfd_error_handler) (_("%B: invalid relocation type %d"),
|
||||||
abfd, (int) r_type);
|
abfd, (int) r_type);
|
||||||
|
@ -668,6 +675,9 @@ struct elf_i386_link_hash_table
|
||||||
asection *srelplt;
|
asection *srelplt;
|
||||||
asection *sdynbss;
|
asection *sdynbss;
|
||||||
asection *srelbss;
|
asection *srelbss;
|
||||||
|
asection *igotplt;
|
||||||
|
asection *iplt;
|
||||||
|
asection *irelplt;
|
||||||
|
|
||||||
/* The (unloaded but important) .rel.plt.unloaded section on VxWorks. */
|
/* The (unloaded but important) .rel.plt.unloaded section on VxWorks. */
|
||||||
asection *srelplt2;
|
asection *srelplt2;
|
||||||
|
@ -764,6 +774,9 @@ elf_i386_link_hash_table_create (bfd *abfd)
|
||||||
ret->srelplt = NULL;
|
ret->srelplt = NULL;
|
||||||
ret->sdynbss = NULL;
|
ret->sdynbss = NULL;
|
||||||
ret->srelbss = NULL;
|
ret->srelbss = NULL;
|
||||||
|
ret->igotplt= NULL;
|
||||||
|
ret->iplt = NULL;
|
||||||
|
ret->irelplt= NULL;
|
||||||
ret->tls_ldm_got.refcount = 0;
|
ret->tls_ldm_got.refcount = 0;
|
||||||
ret->next_tls_desc_index = 0;
|
ret->next_tls_desc_index = 0;
|
||||||
ret->sgotplt_jump_table_size = 0;
|
ret->sgotplt_jump_table_size = 0;
|
||||||
|
@ -1251,6 +1264,87 @@ elf_i386_check_relocs (bfd *abfd,
|
||||||
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;
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
won't appear in output. */
|
||||||
|
switch (r_type)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R_386_32:
|
||||||
|
case R_386_PC32:
|
||||||
|
case R_386_PLT32:
|
||||||
|
case R_386_GOT32:
|
||||||
|
case R_386_GOTOFF:
|
||||||
|
if (!info->shared && htab->iplt == NULL)
|
||||||
|
{
|
||||||
|
if (!_bfd_elf_create_static_ifunc_sections (abfd,
|
||||||
|
info))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
htab->iplt = bfd_get_section_by_name (abfd, ".iplt");
|
||||||
|
htab->irelplt = bfd_get_section_by_name (abfd,
|
||||||
|
".rel.iplt");
|
||||||
|
htab->igotplt = bfd_get_section_by_name (abfd,
|
||||||
|
".igot.plt");
|
||||||
|
if (!htab->iplt
|
||||||
|
|| !htab->irelplt
|
||||||
|
|| !htab->igotplt)
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Since STT_GNU_IFUNC symbol must go through PLT, we handle
|
||||||
|
it here if it is defined in a non-shared object. */
|
||||||
|
if (h->type == STT_GNU_IFUNC
|
||||||
|
&& h->def_regular)
|
||||||
|
{
|
||||||
|
/* It is referenced by a non-shared object. */
|
||||||
|
h->ref_regular = 1;
|
||||||
|
|
||||||
|
/* STT_GNU_IFUNC symbol must go through PLT. */
|
||||||
|
h->plt.refcount += 1;
|
||||||
|
|
||||||
|
/* STT_GNU_IFUNC needs dynamic sections. */
|
||||||
|
if (htab->elf.dynobj == NULL)
|
||||||
|
htab->elf.dynobj = abfd;
|
||||||
|
|
||||||
|
switch (r_type)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
(*_bfd_error_handler)
|
||||||
|
(_("%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__);
|
||||||
|
bfd_set_error (bfd_error_bad_value);
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
case R_386_32:
|
||||||
|
case R_386_PC32:
|
||||||
|
h->non_got_ref = 1;
|
||||||
|
if (r_type != R_386_PC32)
|
||||||
|
h->pointer_equality_needed = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R_386_PLT32:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R_386_GOT32:
|
||||||
|
case R_386_GOTOFF:
|
||||||
|
if (htab->sgot == NULL
|
||||||
|
&& !elf_i386_create_got_section (htab->elf.dynobj,
|
||||||
|
info))
|
||||||
|
return FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! elf_i386_tls_transition (info, abfd, sec, NULL,
|
if (! elf_i386_tls_transition (info, abfd, sec, NULL,
|
||||||
|
@ -1474,12 +1568,6 @@ elf_i386_check_relocs (bfd *abfd,
|
||||||
|
|
||||||
if (sreloc == NULL)
|
if (sreloc == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* Create the ifunc section as well, even if we have not encountered a
|
|
||||||
indirect function symbol yet. We may not even see one in the input
|
|
||||||
object file, but we can still encounter them in libraries. */
|
|
||||||
(void) _bfd_elf_make_ifunc_reloc_section
|
|
||||||
(abfd, sec, htab->elf.dynobj, 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If this is a global symbol, we count the number of
|
/* If this is a global symbol, we count the number of
|
||||||
|
@ -1689,6 +1777,17 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info,
|
||||||
struct elf_i386_link_hash_table *htab;
|
struct elf_i386_link_hash_table *htab;
|
||||||
asection *s;
|
asection *s;
|
||||||
|
|
||||||
|
/* STT_GNU_IFUNC symbol must go through PLT. */
|
||||||
|
if (h->type == STT_GNU_IFUNC)
|
||||||
|
{
|
||||||
|
if (h->plt.refcount <= 0)
|
||||||
|
{
|
||||||
|
h->plt.offset = (bfd_vma) -1;
|
||||||
|
h->needs_plt = 0;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* If this is a function, put it in the procedure linkage table. We
|
/* If this is a function, put it in the procedure linkage table. We
|
||||||
will fill in the contents of the procedure linkage table later,
|
will fill in the contents of the procedure linkage table later,
|
||||||
when we know the address of the .got section. */
|
when we know the address of the .got section. */
|
||||||
|
@ -1822,7 +1921,6 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||||
struct elf_i386_link_hash_table *htab;
|
struct elf_i386_link_hash_table *htab;
|
||||||
struct elf_i386_link_hash_entry *eh;
|
struct elf_i386_link_hash_entry *eh;
|
||||||
struct elf_i386_dyn_relocs *p;
|
struct elf_i386_dyn_relocs *p;
|
||||||
bfd_boolean use_indirect_section = FALSE;
|
|
||||||
|
|
||||||
if (h->root.type == bfd_link_hash_indirect)
|
if (h->root.type == bfd_link_hash_indirect)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -1832,11 +1930,79 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||||
entry in the hash table, thus we never get to see the real
|
entry in the hash table, thus we never get to see the real
|
||||||
symbol in a hash traversal. So look at it now. */
|
symbol in a hash traversal. So look at it now. */
|
||||||
h = (struct elf_link_hash_entry *) h->root.u.i.link;
|
h = (struct elf_link_hash_entry *) h->root.u.i.link;
|
||||||
|
eh = (struct elf_i386_link_hash_entry *) h;
|
||||||
|
|
||||||
info = (struct bfd_link_info *) inf;
|
info = (struct bfd_link_info *) inf;
|
||||||
htab = elf_i386_hash_table (info);
|
htab = elf_i386_hash_table (info);
|
||||||
|
|
||||||
if (htab->elf.dynamic_sections_created
|
/* Since STT_GNU_IFUNC symbol must go through PLT, we handle it
|
||||||
|
here if it is defined and referenced in a non-shared object. */
|
||||||
|
if (h->type == STT_GNU_IFUNC
|
||||||
|
&& h->def_regular)
|
||||||
|
{
|
||||||
|
asection *plt, *gotplt, *relplt;
|
||||||
|
|
||||||
|
/* Return and discard space for dynamic relocations against it if
|
||||||
|
it is never referenced in a non-shared object. */
|
||||||
|
if (!h->ref_regular)
|
||||||
|
{
|
||||||
|
if (h->plt.refcount > 0
|
||||||
|
|| h->got.refcount > 0)
|
||||||
|
abort ();
|
||||||
|
h->got.offset = (bfd_vma) -1;
|
||||||
|
eh->dyn_relocs = NULL;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h->plt.refcount <= 0)
|
||||||
|
abort ();
|
||||||
|
|
||||||
|
/* When building a static executable, use .iplt, .igot.plt and
|
||||||
|
.rel.iplt sections for STT_GNU_IFUNC symbols. */
|
||||||
|
if (htab->splt != 0)
|
||||||
|
{
|
||||||
|
plt = htab->splt;
|
||||||
|
gotplt = htab->sgotplt;
|
||||||
|
relplt = htab->srelplt;
|
||||||
|
|
||||||
|
/* If this is the first .plt entry, make room for the special
|
||||||
|
first entry. */
|
||||||
|
if (plt->size == 0)
|
||||||
|
plt->size += PLT_ENTRY_SIZE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
plt = htab->iplt;
|
||||||
|
gotplt = htab->igotplt;
|
||||||
|
relplt = htab->irelplt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't update value of STT_GNU_IFUNC symbol to PLT. We need
|
||||||
|
the original value for R_386_IRELATIVE. */
|
||||||
|
h->plt.offset = plt->size;
|
||||||
|
|
||||||
|
/* Make room for this entry in the .plt/.iplt section. */
|
||||||
|
plt->size += PLT_ENTRY_SIZE;
|
||||||
|
|
||||||
|
/* We also need to make an entry in the .got.plt/.got.iplt
|
||||||
|
section, which will be placed in the .got section by the
|
||||||
|
linker script. */
|
||||||
|
gotplt->size += 4;
|
||||||
|
|
||||||
|
/* We also need to make an entry in the .rela.plt/.rela.iplt
|
||||||
|
section. */
|
||||||
|
relplt->size += sizeof (Elf32_External_Rel);
|
||||||
|
relplt->reloc_count++;
|
||||||
|
|
||||||
|
/* No need for dynamic relocation for local STT_GNU_IFUNC symbol.
|
||||||
|
Discard space for relocations against it. */
|
||||||
|
if (h->dynindx == -1 || h->forced_local)
|
||||||
|
eh->dyn_relocs = NULL;
|
||||||
|
|
||||||
|
/* STT_GNU_IFUNC symbol uses .got.plt, not .got. */
|
||||||
|
h->got.refcount = 0;
|
||||||
|
}
|
||||||
|
else if (htab->elf.dynamic_sections_created
|
||||||
&& h->plt.refcount > 0)
|
&& h->plt.refcount > 0)
|
||||||
{
|
{
|
||||||
/* Make sure this symbol is output as a dynamic symbol.
|
/* Make sure this symbol is output as a dynamic symbol.
|
||||||
|
@ -1915,7 +2081,6 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||||
h->needs_plt = 0;
|
h->needs_plt = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
eh = (struct elf_i386_link_hash_entry *) h;
|
|
||||||
eh->tlsdesc_got = (bfd_vma) -1;
|
eh->tlsdesc_got = (bfd_vma) -1;
|
||||||
|
|
||||||
/* If R_386_TLS_{IE_32,IE,GOTIE} symbol is now local to the binary,
|
/* If R_386_TLS_{IE_32,IE,GOTIE} symbol is now local to the binary,
|
||||||
|
@ -2044,16 +2209,6 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (_bfd_elf_is_ifunc_symbol (info->output_bfd, h)
|
|
||||||
&& h->dynindx == -1
|
|
||||||
&& ! h->forced_local)
|
|
||||||
{
|
|
||||||
if (bfd_elf_link_record_dynamic_symbol (info, h)
|
|
||||||
&& h->dynindx != -1)
|
|
||||||
use_indirect_section = TRUE;
|
|
||||||
else
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
else if (ELIMINATE_COPY_RELOCS)
|
else if (ELIMINATE_COPY_RELOCS)
|
||||||
{
|
{
|
||||||
/* For the non-shared case, discard space for relocs against
|
/* For the non-shared case, discard space for relocs against
|
||||||
|
@ -2092,9 +2247,6 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||||
{
|
{
|
||||||
asection *sreloc;
|
asection *sreloc;
|
||||||
|
|
||||||
if (use_indirect_section)
|
|
||||||
sreloc = elf_section_data (p->sec)->indirect_relocs;
|
|
||||||
else
|
|
||||||
sreloc = elf_section_data (p->sec)->sreloc;
|
sreloc = elf_section_data (p->sec)->sreloc;
|
||||||
|
|
||||||
BFD_ASSERT (sreloc != NULL);
|
BFD_ASSERT (sreloc != NULL);
|
||||||
|
@ -2299,6 +2451,8 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
|
||||||
if (s == htab->splt
|
if (s == htab->splt
|
||||||
|| s == htab->sgot
|
|| s == htab->sgot
|
||||||
|| s == htab->sgotplt
|
|| s == htab->sgotplt
|
||||||
|
|| s == htab->iplt
|
||||||
|
|| s == htab->igotplt
|
||||||
|| s == htab->sdynbss)
|
|| s == htab->sdynbss)
|
||||||
{
|
{
|
||||||
/* Strip this section if we don't need it; see the
|
/* Strip this section if we don't need it; see the
|
||||||
|
@ -2589,7 +2743,7 @@ elf_i386_relocate_section (bfd *output_bfd,
|
||||||
&& ((indx = r_type - R_386_ext_offset) - R_386_standard
|
&& ((indx = r_type - R_386_ext_offset) - R_386_standard
|
||||||
>= R_386_ext - R_386_standard)
|
>= R_386_ext - R_386_standard)
|
||||||
&& ((indx = r_type - R_386_tls_offset) - R_386_ext
|
&& ((indx = r_type - R_386_tls_offset) - R_386_ext
|
||||||
>= R_386_tls - R_386_ext))
|
>= R_386_irelative - R_386_ext))
|
||||||
{
|
{
|
||||||
(*_bfd_error_handler)
|
(*_bfd_error_handler)
|
||||||
(_("%B: unrecognized relocation (0x%x) in section `%A'"),
|
(_("%B: unrecognized relocation (0x%x) in section `%A'"),
|
||||||
|
@ -2706,6 +2860,113 @@ elf_i386_relocate_section (bfd *output_bfd,
|
||||||
if (info->relocatable)
|
if (info->relocatable)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Since STT_GNU_IFUNC symbol must go through PLT, we handle
|
||||||
|
it here if it is defined in a non-shared object. */
|
||||||
|
if (h != NULL
|
||||||
|
&& h->type == STT_GNU_IFUNC
|
||||||
|
&& h->def_regular)
|
||||||
|
{
|
||||||
|
asection *plt, *gotplt, *base_got;
|
||||||
|
bfd_vma plt_index;
|
||||||
|
|
||||||
|
if ((input_section->flags & SEC_ALLOC) == 0
|
||||||
|
|| h->plt.offset == (bfd_vma) -1)
|
||||||
|
abort ();
|
||||||
|
|
||||||
|
/* STT_GNU_IFUNC symbol must go through PLT. */
|
||||||
|
if (htab->splt != NULL)
|
||||||
|
{
|
||||||
|
plt = htab->splt;
|
||||||
|
gotplt = htab->sgotplt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
plt = htab->iplt;
|
||||||
|
gotplt = htab->igotplt;
|
||||||
|
}
|
||||||
|
|
||||||
|
relocation = (plt->output_section->vma
|
||||||
|
+ plt->output_offset + h->plt.offset);
|
||||||
|
|
||||||
|
switch (r_type)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
(*_bfd_error_handler)
|
||||||
|
(_("%B: relocation %s against STT_GNU_IFUNC "
|
||||||
|
"symbol `%s' isn't handled by %s"), input_bfd,
|
||||||
|
elf_howto_table[r_type].name,
|
||||||
|
h->root.root.string, __FUNCTION__);
|
||||||
|
bfd_set_error (bfd_error_bad_value);
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
case R_386_32:
|
||||||
|
case R_386_PC32:
|
||||||
|
case R_386_PLT32:
|
||||||
|
goto do_relocation;
|
||||||
|
|
||||||
|
case R_386_GOT32:
|
||||||
|
base_got = htab->sgot;
|
||||||
|
off = h->got.offset;
|
||||||
|
|
||||||
|
if (base_got == NULL
|
||||||
|
|| off != (bfd_vma) -1)
|
||||||
|
abort ();
|
||||||
|
|
||||||
|
/* We can't use h->got.offset here to save state, or
|
||||||
|
even just remember the offset, as finish_dynamic_symbol
|
||||||
|
would use that as offset into .got. */
|
||||||
|
|
||||||
|
if (htab->splt != NULL)
|
||||||
|
{
|
||||||
|
plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
|
||||||
|
off = (plt_index + 3) * 4;
|
||||||
|
base_got = htab->sgotplt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
plt_index = h->plt.offset / PLT_ENTRY_SIZE;
|
||||||
|
off = plt_index * 4;
|
||||||
|
base_got = htab->igotplt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h->dynindx == -1
|
||||||
|
|| h->forced_local
|
||||||
|
|| info->symbolic)
|
||||||
|
{
|
||||||
|
/* This references the local defitionion. We must
|
||||||
|
initialize this entry in the global offset table.
|
||||||
|
Since the offset must always be a multiple of 8, we
|
||||||
|
use the least significant bit to record whether we
|
||||||
|
have initialized it already.
|
||||||
|
|
||||||
|
When doing a dynamic link, we create a .rela.got
|
||||||
|
relocation entry to initialize the value. This is
|
||||||
|
done in the finish_dynamic_symbol routine. */
|
||||||
|
if ((off & 1) != 0)
|
||||||
|
off &= ~1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bfd_put_32 (output_bfd, relocation,
|
||||||
|
base_got->contents + off);
|
||||||
|
h->got.offset |= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
relocation = off;
|
||||||
|
|
||||||
|
/* Adjust for static executables. */
|
||||||
|
if (htab->splt == NULL)
|
||||||
|
relocation += gotplt->output_offset;
|
||||||
|
|
||||||
|
goto do_relocation;
|
||||||
|
|
||||||
|
case R_386_GOTOFF:
|
||||||
|
relocation -= (gotplt->output_section->vma
|
||||||
|
+ gotplt->output_offset);
|
||||||
|
goto do_relocation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (r_type)
|
switch (r_type)
|
||||||
{
|
{
|
||||||
case R_386_GOT32:
|
case R_386_GOT32:
|
||||||
|
@ -2899,12 +3160,6 @@ elf_i386_relocate_section (bfd *output_bfd,
|
||||||
|| h->root.type != bfd_link_hash_undefweak)
|
|| h->root.type != bfd_link_hash_undefweak)
|
||||||
&& (r_type != R_386_PC32
|
&& (r_type != R_386_PC32
|
||||||
|| !SYMBOL_CALLS_LOCAL (info, h)))
|
|| !SYMBOL_CALLS_LOCAL (info, h)))
|
||||||
|| (! info->shared
|
|
||||||
&& h != NULL
|
|
||||||
&& h->dynindx != -1
|
|
||||||
&& ! h->forced_local
|
|
||||||
&& ((struct elf_i386_link_hash_entry *) h)->dyn_relocs != NULL
|
|
||||||
&& _bfd_elf_is_ifunc_symbol (output_bfd, h))
|
|
||||||
|| (ELIMINATE_COPY_RELOCS
|
|| (ELIMINATE_COPY_RELOCS
|
||||||
&& !info->shared
|
&& !info->shared
|
||||||
&& h != NULL
|
&& h != NULL
|
||||||
|
@ -2953,15 +3208,6 @@ elf_i386_relocate_section (bfd *output_bfd,
|
||||||
outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
|
outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! info->shared
|
|
||||||
&& h != NULL
|
|
||||||
&& h->dynindx != -1
|
|
||||||
&& ! h->forced_local
|
|
||||||
&& _bfd_elf_is_ifunc_symbol (output_bfd, h)
|
|
||||||
&& elf_section_data (input_section)->indirect_relocs != NULL
|
|
||||||
&& elf_section_data (input_section)->indirect_relocs->contents != NULL)
|
|
||||||
sreloc = elf_section_data (input_section)->indirect_relocs;
|
|
||||||
else
|
|
||||||
sreloc = elf_section_data (input_section)->sreloc;
|
sreloc = elf_section_data (input_section)->sreloc;
|
||||||
|
|
||||||
BFD_ASSERT (sreloc != NULL && sreloc->contents != NULL);
|
BFD_ASSERT (sreloc != NULL && sreloc->contents != NULL);
|
||||||
|
@ -3605,6 +3851,7 @@ elf_i386_relocate_section (bfd *output_bfd,
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do_relocation:
|
||||||
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
|
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
|
||||||
contents, rel->r_offset,
|
contents, rel->r_offset,
|
||||||
relocation, 0);
|
relocation, 0);
|
||||||
|
@ -3667,37 +3914,67 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
|
||||||
bfd_vma got_offset;
|
bfd_vma got_offset;
|
||||||
Elf_Internal_Rela rel;
|
Elf_Internal_Rela rel;
|
||||||
bfd_byte *loc;
|
bfd_byte *loc;
|
||||||
|
asection *plt, *gotplt, *relplt;
|
||||||
|
|
||||||
|
/* When building a static executable, use .iplt, .igot.plt and
|
||||||
|
.rel.iplt sections for STT_GNU_IFUNC symbols. */
|
||||||
|
if (htab->splt != 0)
|
||||||
|
{
|
||||||
|
plt = htab->splt;
|
||||||
|
gotplt = htab->sgotplt;
|
||||||
|
relplt = htab->srelplt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
plt = htab->iplt;
|
||||||
|
gotplt = htab->igotplt;
|
||||||
|
relplt = htab->irelplt;
|
||||||
|
}
|
||||||
|
|
||||||
/* This symbol has an entry in the procedure linkage table. Set
|
/* This symbol has an entry in the procedure linkage table. Set
|
||||||
it up. */
|
it up. */
|
||||||
|
|
||||||
if (h->dynindx == -1
|
if ((h->dynindx == -1
|
||||||
|| htab->splt == NULL
|
&& !((h->forced_local || info->executable)
|
||||||
|| htab->sgotplt == NULL
|
&& h->def_regular
|
||||||
|| htab->srelplt == NULL)
|
&& h->type == STT_GNU_IFUNC))
|
||||||
|
|| plt == NULL
|
||||||
|
|| gotplt == NULL
|
||||||
|
|| relplt == NULL)
|
||||||
abort ();
|
abort ();
|
||||||
|
|
||||||
/* Get the index in the procedure linkage table which
|
/* Get the index in the procedure linkage table which
|
||||||
corresponds to this symbol. This is the index of this symbol
|
corresponds to this symbol. This is the index of this symbol
|
||||||
in all the symbols for which we are making plt entries. The
|
in all the symbols for which we are making plt entries. The
|
||||||
first entry in the procedure linkage table is reserved. */
|
first entry in the procedure linkage table is reserved.
|
||||||
plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
|
|
||||||
|
|
||||||
/* Get the offset into the .got table of the entry that
|
Get the offset into the .got table of the entry that
|
||||||
corresponds to this function. Each .got entry is 4 bytes.
|
corresponds to this function. Each .got entry is 4 bytes.
|
||||||
The first three are reserved. */
|
The first three are reserved.
|
||||||
|
|
||||||
|
For static executables, we don't reserve anything. */
|
||||||
|
|
||||||
|
if (plt == htab->splt)
|
||||||
|
{
|
||||||
|
plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
|
||||||
got_offset = (plt_index + 3) * 4;
|
got_offset = (plt_index + 3) * 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
plt_index = h->plt.offset / PLT_ENTRY_SIZE;
|
||||||
|
got_offset = plt_index * 4;
|
||||||
|
}
|
||||||
|
|
||||||
/* Fill in the entry in the procedure linkage table. */
|
/* Fill in the entry in the procedure linkage table. */
|
||||||
if (! info->shared)
|
if (! info->shared)
|
||||||
{
|
{
|
||||||
memcpy (htab->splt->contents + h->plt.offset, elf_i386_plt_entry,
|
memcpy (plt->contents + h->plt.offset, elf_i386_plt_entry,
|
||||||
PLT_ENTRY_SIZE);
|
PLT_ENTRY_SIZE);
|
||||||
bfd_put_32 (output_bfd,
|
bfd_put_32 (output_bfd,
|
||||||
(htab->sgotplt->output_section->vma
|
(gotplt->output_section->vma
|
||||||
+ htab->sgotplt->output_offset
|
+ gotplt->output_offset
|
||||||
+ got_offset),
|
+ got_offset),
|
||||||
htab->splt->contents + h->plt.offset + 2);
|
plt->contents + h->plt.offset + 2);
|
||||||
|
|
||||||
if (htab->is_vxworks)
|
if (htab->is_vxworks)
|
||||||
{
|
{
|
||||||
|
@ -3737,31 +4014,52 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memcpy (htab->splt->contents + h->plt.offset, elf_i386_pic_plt_entry,
|
memcpy (plt->contents + h->plt.offset, elf_i386_pic_plt_entry,
|
||||||
PLT_ENTRY_SIZE);
|
PLT_ENTRY_SIZE);
|
||||||
bfd_put_32 (output_bfd, got_offset,
|
bfd_put_32 (output_bfd, got_offset,
|
||||||
htab->splt->contents + h->plt.offset + 2);
|
plt->contents + h->plt.offset + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Don't fill PLT entry for static executables. */
|
||||||
|
if (plt == htab->splt)
|
||||||
|
{
|
||||||
bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rel),
|
bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rel),
|
||||||
htab->splt->contents + h->plt.offset + 7);
|
plt->contents + h->plt.offset + 7);
|
||||||
bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
|
bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
|
||||||
htab->splt->contents + h->plt.offset + 12);
|
plt->contents + h->plt.offset + 12);
|
||||||
|
}
|
||||||
|
|
||||||
/* Fill in the entry in the global offset table. */
|
/* Fill in the entry in the global offset table. */
|
||||||
bfd_put_32 (output_bfd,
|
bfd_put_32 (output_bfd,
|
||||||
(htab->splt->output_section->vma
|
(plt->output_section->vma
|
||||||
+ htab->splt->output_offset
|
+ plt->output_offset
|
||||||
+ h->plt.offset
|
+ h->plt.offset
|
||||||
+ 6),
|
+ 6),
|
||||||
htab->sgotplt->contents + got_offset);
|
gotplt->contents + got_offset);
|
||||||
|
|
||||||
/* Fill in the entry in the .rel.plt section. */
|
/* Fill in the entry in the .rel.plt section. */
|
||||||
rel.r_offset = (htab->sgotplt->output_section->vma
|
rel.r_offset = (gotplt->output_section->vma
|
||||||
+ htab->sgotplt->output_offset
|
+ gotplt->output_offset
|
||||||
+ got_offset);
|
+ got_offset);
|
||||||
|
if (h->dynindx == -1
|
||||||
|
|| ((info->executable
|
||||||
|
|| ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
|
||||||
|
&& h->def_regular
|
||||||
|
&& h->type == STT_GNU_IFUNC))
|
||||||
|
{
|
||||||
|
/* If an STT_GNU_IFUNC symbol is locally defined, generate
|
||||||
|
R_386_IRELATIVE instead of R_386_JUMP_SLOT. Store addend
|
||||||
|
in the .got.plt section. */
|
||||||
|
bfd_put_32 (output_bfd,
|
||||||
|
(h->root.u.def.value
|
||||||
|
+ h->root.u.def.section->output_section->vma
|
||||||
|
+ h->root.u.def.section->output_offset),
|
||||||
|
gotplt->contents + got_offset);
|
||||||
|
rel.r_info = ELF32_R_INFO (0, R_386_IRELATIVE);
|
||||||
|
}
|
||||||
|
else
|
||||||
rel.r_info = ELF32_R_INFO (h->dynindx, R_386_JUMP_SLOT);
|
rel.r_info = ELF32_R_INFO (h->dynindx, R_386_JUMP_SLOT);
|
||||||
loc = htab->srelplt->contents + plt_index * sizeof (Elf32_External_Rel);
|
loc = relplt->contents + plt_index * sizeof (Elf32_External_Rel);
|
||||||
bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
|
bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
|
||||||
|
|
||||||
if (!h->def_regular)
|
if (!h->def_regular)
|
||||||
|
|
|
@ -143,12 +143,15 @@ static reloc_howto_type x86_64_elf_howto_table[] =
|
||||||
complain_overflow_bitfield, bfd_elf_generic_reloc,
|
complain_overflow_bitfield, bfd_elf_generic_reloc,
|
||||||
"R_X86_64_TLSDESC",
|
"R_X86_64_TLSDESC",
|
||||||
FALSE, MINUS_ONE, MINUS_ONE, FALSE),
|
FALSE, MINUS_ONE, MINUS_ONE, FALSE),
|
||||||
|
HOWTO(R_X86_64_IRELATIVE, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
|
||||||
|
bfd_elf_generic_reloc, "R_X86_64_IRELATIVE", FALSE, MINUS_ONE,
|
||||||
|
MINUS_ONE, FALSE),
|
||||||
|
|
||||||
/* We have a gap in the reloc numbers here.
|
/* We have a gap in the reloc numbers here.
|
||||||
R_X86_64_standard counts the number up to this point, and
|
R_X86_64_standard counts the number up to this point, and
|
||||||
R_X86_64_vt_offset is the value to subtract from a reloc type of
|
R_X86_64_vt_offset is the value to subtract from a reloc type of
|
||||||
R_X86_64_GNU_VT* to form an index into this table. */
|
R_X86_64_GNU_VT* to form an index into this table. */
|
||||||
#define R_X86_64_standard (R_X86_64_TLSDESC + 1)
|
#define R_X86_64_standard (R_X86_64_IRELATIVE + 1)
|
||||||
#define R_X86_64_vt_offset (R_X86_64_GNU_VTINHERIT - R_X86_64_standard)
|
#define R_X86_64_vt_offset (R_X86_64_GNU_VTINHERIT - R_X86_64_standard)
|
||||||
|
|
||||||
/* GNU extension to record C++ vtable hierarchy. */
|
/* GNU extension to record C++ vtable hierarchy. */
|
||||||
|
@ -211,6 +214,7 @@ static const struct elf_reloc_map x86_64_reloc_map[] =
|
||||||
{ BFD_RELOC_X86_64_GOTPC32_TLSDESC, R_X86_64_GOTPC32_TLSDESC, },
|
{ BFD_RELOC_X86_64_GOTPC32_TLSDESC, R_X86_64_GOTPC32_TLSDESC, },
|
||||||
{ BFD_RELOC_X86_64_TLSDESC_CALL, R_X86_64_TLSDESC_CALL, },
|
{ BFD_RELOC_X86_64_TLSDESC_CALL, R_X86_64_TLSDESC_CALL, },
|
||||||
{ BFD_RELOC_X86_64_TLSDESC, R_X86_64_TLSDESC, },
|
{ BFD_RELOC_X86_64_TLSDESC, R_X86_64_TLSDESC, },
|
||||||
|
{ BFD_RELOC_X86_64_IRELATIVE, R_X86_64_IRELATIVE, },
|
||||||
{ BFD_RELOC_VTABLE_INHERIT, R_X86_64_GNU_VTINHERIT, },
|
{ BFD_RELOC_VTABLE_INHERIT, R_X86_64_GNU_VTINHERIT, },
|
||||||
{ BFD_RELOC_VTABLE_ENTRY, R_X86_64_GNU_VTENTRY, },
|
{ BFD_RELOC_VTABLE_ENTRY, R_X86_64_GNU_VTENTRY, },
|
||||||
};
|
};
|
||||||
|
@ -489,6 +493,9 @@ struct elf64_x86_64_link_hash_table
|
||||||
asection *srelplt;
|
asection *srelplt;
|
||||||
asection *sdynbss;
|
asection *sdynbss;
|
||||||
asection *srelbss;
|
asection *srelbss;
|
||||||
|
asection *igotplt;
|
||||||
|
asection *iplt;
|
||||||
|
asection *irelplt;
|
||||||
|
|
||||||
/* The offset into splt of the PLT entry for the TLS descriptor
|
/* The offset into splt of the PLT entry for the TLS descriptor
|
||||||
resolver. Special values are 0, if not necessary (or not found
|
resolver. Special values are 0, if not necessary (or not found
|
||||||
|
@ -581,6 +588,9 @@ elf64_x86_64_link_hash_table_create (bfd *abfd)
|
||||||
ret->srelplt = NULL;
|
ret->srelplt = NULL;
|
||||||
ret->sdynbss = NULL;
|
ret->sdynbss = NULL;
|
||||||
ret->srelbss = NULL;
|
ret->srelbss = NULL;
|
||||||
|
ret->igotplt= NULL;
|
||||||
|
ret->iplt = NULL;
|
||||||
|
ret->irelplt= NULL;
|
||||||
ret->sym_sec.abfd = NULL;
|
ret->sym_sec.abfd = NULL;
|
||||||
ret->tlsdesc_plt = 0;
|
ret->tlsdesc_plt = 0;
|
||||||
ret->tlsdesc_got = 0;
|
ret->tlsdesc_got = 0;
|
||||||
|
@ -1037,6 +1047,94 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *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;
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
won't appear in output. */
|
||||||
|
switch (r_type)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R_X86_64_32S:
|
||||||
|
case R_X86_64_32:
|
||||||
|
case R_X86_64_64:
|
||||||
|
case R_X86_64_PC32:
|
||||||
|
case R_X86_64_PC64:
|
||||||
|
case R_X86_64_PLT32:
|
||||||
|
case R_X86_64_GOTPCREL:
|
||||||
|
case R_X86_64_GOTPCREL64:
|
||||||
|
if (!info->shared && htab->iplt == NULL)
|
||||||
|
{
|
||||||
|
if (!_bfd_elf_create_static_ifunc_sections (abfd,
|
||||||
|
info))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
htab->iplt = bfd_get_section_by_name (abfd, ".iplt");
|
||||||
|
htab->irelplt = bfd_get_section_by_name (abfd,
|
||||||
|
".rela.iplt");
|
||||||
|
htab->igotplt = bfd_get_section_by_name (abfd,
|
||||||
|
".igot.plt");
|
||||||
|
if (!htab->iplt
|
||||||
|
|| !htab->irelplt
|
||||||
|
|| !htab->igotplt)
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Since STT_GNU_IFUNC symbol must go through PLT, we handle
|
||||||
|
it here if it is defined in a non-shared object. */
|
||||||
|
if (h->type == STT_GNU_IFUNC
|
||||||
|
&& h->def_regular)
|
||||||
|
{
|
||||||
|
/* It is referenced by a non-shared object. */
|
||||||
|
h->ref_regular = 1;
|
||||||
|
|
||||||
|
/* STT_GNU_IFUNC symbol must go through PLT. */
|
||||||
|
h->plt.refcount += 1;
|
||||||
|
|
||||||
|
/* STT_GNU_IFUNC needs dynamic sections. */
|
||||||
|
if (htab->elf.dynobj == NULL)
|
||||||
|
htab->elf.dynobj = abfd;
|
||||||
|
|
||||||
|
switch (r_type)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
(*_bfd_error_handler)
|
||||||
|
(_("%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__);
|
||||||
|
bfd_set_error (bfd_error_bad_value);
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
case R_X86_64_32S:
|
||||||
|
case R_X86_64_32:
|
||||||
|
case R_X86_64_64:
|
||||||
|
case R_X86_64_PC32:
|
||||||
|
case R_X86_64_PC64:
|
||||||
|
h->non_got_ref = 1;
|
||||||
|
if (r_type != R_X86_64_PC32
|
||||||
|
&& r_type != R_X86_64_PC64)
|
||||||
|
h->pointer_equality_needed = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R_X86_64_PLT32:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R_X86_64_GOTPCREL:
|
||||||
|
case R_X86_64_GOTPCREL64:
|
||||||
|
if (htab->sgot == NULL
|
||||||
|
&& !elf64_x86_64_create_got_section (htab->elf.dynobj,
|
||||||
|
info))
|
||||||
|
return FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! elf64_x86_64_tls_transition (info, abfd, sec, NULL,
|
if (! elf64_x86_64_tls_transition (info, abfd, sec, NULL,
|
||||||
|
@ -1298,12 +1396,6 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
||||||
|
|
||||||
if (sreloc == NULL)
|
if (sreloc == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* Create the ifunc section, even if we will not encounter an
|
|
||||||
indirect function symbol. We may not even see one in the input
|
|
||||||
object file, but we can still encounter them in libraries. */
|
|
||||||
(void) _bfd_elf_make_ifunc_reloc_section
|
|
||||||
(abfd, sec, htab->elf.dynobj, 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If this is a global symbol, we count the number of
|
/* If this is a global symbol, we count the number of
|
||||||
|
@ -1528,6 +1620,17 @@ elf64_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
|
||||||
struct elf64_x86_64_link_hash_table *htab;
|
struct elf64_x86_64_link_hash_table *htab;
|
||||||
asection *s;
|
asection *s;
|
||||||
|
|
||||||
|
/* STT_GNU_IFUNC symbol must go through PLT. */
|
||||||
|
if (h->type == STT_GNU_IFUNC)
|
||||||
|
{
|
||||||
|
if (h->plt.refcount <= 0)
|
||||||
|
{
|
||||||
|
h->plt.offset = (bfd_vma) -1;
|
||||||
|
h->needs_plt = 0;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* If this is a function, put it in the procedure linkage table. We
|
/* If this is a function, put it in the procedure linkage table. We
|
||||||
will fill in the contents of the procedure linkage table later,
|
will fill in the contents of the procedure linkage table later,
|
||||||
when we know the address of the .got section. */
|
when we know the address of the .got section. */
|
||||||
|
@ -1659,18 +1762,85 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
|
||||||
struct elf64_x86_64_link_hash_table *htab;
|
struct elf64_x86_64_link_hash_table *htab;
|
||||||
struct elf64_x86_64_link_hash_entry *eh;
|
struct elf64_x86_64_link_hash_entry *eh;
|
||||||
struct elf64_x86_64_dyn_relocs *p;
|
struct elf64_x86_64_dyn_relocs *p;
|
||||||
bfd_boolean use_indirect_section = FALSE;
|
|
||||||
|
|
||||||
if (h->root.type == bfd_link_hash_indirect)
|
if (h->root.type == bfd_link_hash_indirect)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
if (h->root.type == bfd_link_hash_warning)
|
if (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;
|
||||||
|
eh = (struct elf64_x86_64_link_hash_entry *) h;
|
||||||
|
|
||||||
info = (struct bfd_link_info *) inf;
|
info = (struct bfd_link_info *) inf;
|
||||||
htab = elf64_x86_64_hash_table (info);
|
htab = elf64_x86_64_hash_table (info);
|
||||||
|
|
||||||
if (htab->elf.dynamic_sections_created
|
/* Since STT_GNU_IFUNC symbol must go through PLT, we handle it
|
||||||
|
here if it is defined and referenced in a non-shared object. */
|
||||||
|
if (h->type == STT_GNU_IFUNC
|
||||||
|
&& h->def_regular)
|
||||||
|
{
|
||||||
|
asection *plt, *gotplt, *relplt;
|
||||||
|
|
||||||
|
/* Return and discard space for dynamic relocations against it if
|
||||||
|
it is never referenced in a non-shared object. */
|
||||||
|
if (!h->ref_regular)
|
||||||
|
{
|
||||||
|
if (h->plt.refcount > 0
|
||||||
|
|| h->got.refcount > 0)
|
||||||
|
abort ();
|
||||||
|
h->got.offset = (bfd_vma) -1;
|
||||||
|
eh->dyn_relocs = NULL;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h->plt.refcount <= 0)
|
||||||
|
abort ();
|
||||||
|
|
||||||
|
/* When building a static executable, use .iplt, .igot.plt and
|
||||||
|
.rela.iplt sections for STT_GNU_IFUNC symbols. */
|
||||||
|
if (htab->splt != 0)
|
||||||
|
{
|
||||||
|
plt = htab->splt;
|
||||||
|
gotplt = htab->sgotplt;
|
||||||
|
relplt = htab->srelplt;
|
||||||
|
|
||||||
|
/* If this is the first .plt entry, make room for the special
|
||||||
|
first entry. */
|
||||||
|
if (plt->size == 0)
|
||||||
|
plt->size += PLT_ENTRY_SIZE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
plt = htab->iplt;
|
||||||
|
gotplt = htab->igotplt;
|
||||||
|
relplt = htab->irelplt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't update value of STT_GNU_IFUNC symbol to PLT. We need
|
||||||
|
the original value for R_X86_64_IRELATIVE. */
|
||||||
|
h->plt.offset = plt->size;
|
||||||
|
|
||||||
|
/* Make room for this entry in the .plt/.iplt section. */
|
||||||
|
plt->size += PLT_ENTRY_SIZE;
|
||||||
|
|
||||||
|
/* We also need to make an entry in the .got.plt/.got.iplt
|
||||||
|
section, which will be placed in the .got section by the
|
||||||
|
linker script. */
|
||||||
|
gotplt->size += GOT_ENTRY_SIZE;
|
||||||
|
|
||||||
|
/* We also need to make an entry in the .rela.plt/.rela.iplt
|
||||||
|
section. */
|
||||||
|
relplt->size += sizeof (Elf64_External_Rela);
|
||||||
|
relplt->reloc_count++;
|
||||||
|
|
||||||
|
/* No need for dynamic relocation for local STT_GNU_IFUNC symbol.
|
||||||
|
Discard space for relocations against it. */
|
||||||
|
if (h->dynindx == -1 || h->forced_local)
|
||||||
|
eh->dyn_relocs = NULL;
|
||||||
|
|
||||||
|
/* STT_GNU_IFUNC symbol uses .got.plt, not .got. */
|
||||||
|
h->got.refcount = 0;
|
||||||
|
}
|
||||||
|
else if (htab->elf.dynamic_sections_created
|
||||||
&& h->plt.refcount > 0)
|
&& h->plt.refcount > 0)
|
||||||
{
|
{
|
||||||
/* Make sure this symbol is output as a dynamic symbol.
|
/* Make sure this symbol is output as a dynamic symbol.
|
||||||
|
@ -1729,7 +1899,6 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
|
||||||
h->needs_plt = 0;
|
h->needs_plt = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
eh = (struct elf64_x86_64_link_hash_entry *) h;
|
|
||||||
eh->tlsdesc_got = (bfd_vma) -1;
|
eh->tlsdesc_got = (bfd_vma) -1;
|
||||||
|
|
||||||
/* If R_X86_64_GOTTPOFF symbol is now local to the binary,
|
/* If R_X86_64_GOTTPOFF symbol is now local to the binary,
|
||||||
|
@ -1843,16 +2012,7 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
|
||||||
&& ! bfd_elf_link_record_dynamic_symbol (info, h))
|
&& ! bfd_elf_link_record_dynamic_symbol (info, h))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (_bfd_elf_is_ifunc_symbol (info->output_bfd, h)
|
|
||||||
&& h->dynindx == -1
|
|
||||||
&& ! h->forced_local)
|
|
||||||
{
|
|
||||||
if (bfd_elf_link_record_dynamic_symbol (info, h)
|
|
||||||
&& h->dynindx != -1)
|
|
||||||
use_indirect_section = TRUE;
|
|
||||||
else
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
else if (ELIMINATE_COPY_RELOCS)
|
else if (ELIMINATE_COPY_RELOCS)
|
||||||
{
|
{
|
||||||
|
@ -1890,9 +2050,6 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
|
||||||
{
|
{
|
||||||
asection * sreloc;
|
asection * sreloc;
|
||||||
|
|
||||||
if (use_indirect_section)
|
|
||||||
sreloc = elf_section_data (p->sec)->indirect_relocs;
|
|
||||||
else
|
|
||||||
sreloc = elf_section_data (p->sec)->sreloc;
|
sreloc = elf_section_data (p->sec)->sreloc;
|
||||||
|
|
||||||
BFD_ASSERT (sreloc != NULL);
|
BFD_ASSERT (sreloc != NULL);
|
||||||
|
@ -2110,6 +2267,8 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
|
||||||
if (s == htab->splt
|
if (s == htab->splt
|
||||||
|| s == htab->sgot
|
|| s == htab->sgot
|
||||||
|| s == htab->sgotplt
|
|| s == htab->sgotplt
|
||||||
|
|| s == htab->iplt
|
||||||
|
|| s == htab->igotplt
|
||||||
|| s == htab->sdynbss)
|
|| s == htab->sdynbss)
|
||||||
{
|
{
|
||||||
/* Strip this section if we don't need it; see the
|
/* Strip this section if we don't need it; see the
|
||||||
|
@ -2362,6 +2521,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
||||||
bfd_boolean unresolved_reloc;
|
bfd_boolean unresolved_reloc;
|
||||||
bfd_reloc_status_type r;
|
bfd_reloc_status_type r;
|
||||||
int tls_type;
|
int tls_type;
|
||||||
|
asection *base_got;
|
||||||
|
|
||||||
r_type = ELF64_R_TYPE (rel->r_info);
|
r_type = ELF64_R_TYPE (rel->r_info);
|
||||||
if (r_type == (int) R_X86_64_GNU_VTINHERIT
|
if (r_type == (int) R_X86_64_GNU_VTINHERIT
|
||||||
|
@ -2411,11 +2571,120 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
||||||
if (info->relocatable)
|
if (info->relocatable)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Since STT_GNU_IFUNC symbol must go through PLT, we handle
|
||||||
|
it here if it is defined in a non-shared object. */
|
||||||
|
if (h != NULL
|
||||||
|
&& h->type == STT_GNU_IFUNC
|
||||||
|
&& h->def_regular)
|
||||||
|
{
|
||||||
|
asection *plt;
|
||||||
|
bfd_vma plt_index;
|
||||||
|
|
||||||
|
if ((input_section->flags & SEC_ALLOC) == 0
|
||||||
|
|| h->plt.offset == (bfd_vma) -1)
|
||||||
|
abort ();
|
||||||
|
|
||||||
|
/* STT_GNU_IFUNC symbol must go through PLT. */
|
||||||
|
plt = htab->splt ? htab->splt : htab->iplt;
|
||||||
|
relocation = (plt->output_section->vma
|
||||||
|
+ plt->output_offset + h->plt.offset);
|
||||||
|
|
||||||
|
switch (r_type)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
(*_bfd_error_handler)
|
||||||
|
(_("%B: relocation %s against STT_GNU_IFUNC "
|
||||||
|
"symbol `%s' isn't handled by %s"), input_bfd,
|
||||||
|
x86_64_elf_howto_table[r_type].name,
|
||||||
|
h->root.root.string, __FUNCTION__);
|
||||||
|
bfd_set_error (bfd_error_bad_value);
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
case R_X86_64_32S:
|
||||||
|
if (!info->executable)
|
||||||
|
abort ();
|
||||||
|
|
||||||
|
case R_X86_64_32:
|
||||||
|
case R_X86_64_64:
|
||||||
|
case R_X86_64_PC32:
|
||||||
|
case R_X86_64_PC64:
|
||||||
|
case R_X86_64_PLT32:
|
||||||
|
goto do_relocation;
|
||||||
|
|
||||||
|
case R_X86_64_GOTPCREL:
|
||||||
|
case R_X86_64_GOTPCREL64:
|
||||||
|
base_got = htab->sgot;
|
||||||
|
off = h->got.offset;
|
||||||
|
|
||||||
|
if (base_got == NULL
|
||||||
|
|| off != (bfd_vma) -1)
|
||||||
|
abort ();
|
||||||
|
|
||||||
|
/* We can't use h->got.offset here to save state, or
|
||||||
|
even just remember the offset, as finish_dynamic_symbol
|
||||||
|
would use that as offset into .got. */
|
||||||
|
|
||||||
|
if (htab->splt != NULL)
|
||||||
|
{
|
||||||
|
plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
|
||||||
|
off = (plt_index + 3) * GOT_ENTRY_SIZE;
|
||||||
|
base_got = htab->sgotplt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
plt_index = h->plt.offset / PLT_ENTRY_SIZE;
|
||||||
|
off = plt_index * GOT_ENTRY_SIZE;
|
||||||
|
base_got = htab->igotplt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h->dynindx == -1
|
||||||
|
|| h->forced_local
|
||||||
|
|| info->symbolic)
|
||||||
|
{
|
||||||
|
/* This references the local defitionion. We must
|
||||||
|
initialize this entry in the global offset table.
|
||||||
|
Since the offset must always be a multiple of 8, we
|
||||||
|
use the least significant bit to record whether we
|
||||||
|
have initialized it already.
|
||||||
|
|
||||||
|
When doing a dynamic link, we create a .rela.got
|
||||||
|
relocation entry to initialize the value. This is
|
||||||
|
done in the finish_dynamic_symbol routine. */
|
||||||
|
if ((off & 1) != 0)
|
||||||
|
off &= ~1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bfd_put_64 (output_bfd, relocation,
|
||||||
|
base_got->contents + off);
|
||||||
|
/* Note that this is harmless for the GOTPLT64 case,
|
||||||
|
as -1 | 1 still is -1. */
|
||||||
|
h->got.offset |= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
relocation = (base_got->output_section->vma
|
||||||
|
+ base_got->output_offset + off);
|
||||||
|
|
||||||
|
if (r_type != R_X86_64_GOTPCREL
|
||||||
|
&& r_type != R_X86_64_GOTPCREL64)
|
||||||
|
{
|
||||||
|
asection *gotplt;
|
||||||
|
if (htab->splt != NULL)
|
||||||
|
gotplt = htab->sgotplt;
|
||||||
|
else
|
||||||
|
gotplt = htab->igotplt;
|
||||||
|
relocation -= (gotplt->output_section->vma
|
||||||
|
- gotplt->output_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
goto do_relocation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* When generating a shared object, the relocations handled here are
|
/* When generating a shared object, the relocations handled here are
|
||||||
copied into the output file to be resolved at run time. */
|
copied into the output file to be resolved at run time. */
|
||||||
switch (r_type)
|
switch (r_type)
|
||||||
{
|
{
|
||||||
asection *base_got;
|
|
||||||
case R_X86_64_GOT32:
|
case R_X86_64_GOT32:
|
||||||
case R_X86_64_GOT64:
|
case R_X86_64_GOT64:
|
||||||
/* Relocation is to the entry for this symbol in the global
|
/* Relocation is to the entry for this symbol in the global
|
||||||
|
@ -2700,12 +2969,6 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
||||||
|| h->root.type != bfd_link_hash_undefweak)
|
|| h->root.type != bfd_link_hash_undefweak)
|
||||||
&& (! IS_X86_64_PCREL_TYPE (r_type)
|
&& (! IS_X86_64_PCREL_TYPE (r_type)
|
||||||
|| ! SYMBOL_CALLS_LOCAL (info, h)))
|
|| ! SYMBOL_CALLS_LOCAL (info, h)))
|
||||||
|| (! info->shared
|
|
||||||
&& h != NULL
|
|
||||||
&& h->dynindx != -1
|
|
||||||
&& ! h->forced_local
|
|
||||||
&& ((struct elf64_x86_64_link_hash_entry *) h)->dyn_relocs != NULL
|
|
||||||
&& _bfd_elf_is_ifunc_symbol (output_bfd, h))
|
|
||||||
|| (ELIMINATE_COPY_RELOCS
|
|| (ELIMINATE_COPY_RELOCS
|
||||||
&& !info->shared
|
&& !info->shared
|
||||||
&& h != NULL
|
&& h != NULL
|
||||||
|
@ -2797,15 +3060,6 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! info->shared
|
|
||||||
&& h != NULL
|
|
||||||
&& h->dynindx != -1
|
|
||||||
&& ! h->forced_local
|
|
||||||
&& _bfd_elf_is_ifunc_symbol (output_bfd, h)
|
|
||||||
&& elf_section_data (input_section)->indirect_relocs != NULL
|
|
||||||
&& elf_section_data (input_section)->indirect_relocs->contents != NULL)
|
|
||||||
sreloc = elf_section_data (input_section)->indirect_relocs;
|
|
||||||
else
|
|
||||||
sreloc = elf_section_data (input_section)->sreloc;
|
sreloc = elf_section_data (input_section)->sreloc;
|
||||||
|
|
||||||
BFD_ASSERT (sreloc != NULL && sreloc->contents != NULL);
|
BFD_ASSERT (sreloc != NULL && sreloc->contents != NULL);
|
||||||
|
@ -3253,6 +3507,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
||||||
howto->name,
|
howto->name,
|
||||||
h->root.root.string);
|
h->root.root.string);
|
||||||
|
|
||||||
|
do_relocation:
|
||||||
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
|
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
|
||||||
contents, rel->r_offset,
|
contents, rel->r_offset,
|
||||||
relocation, rel->r_addend);
|
relocation, rel->r_addend);
|
||||||
|
@ -3315,28 +3570,58 @@ elf64_x86_64_finish_dynamic_symbol (bfd *output_bfd,
|
||||||
bfd_vma got_offset;
|
bfd_vma got_offset;
|
||||||
Elf_Internal_Rela rela;
|
Elf_Internal_Rela rela;
|
||||||
bfd_byte *loc;
|
bfd_byte *loc;
|
||||||
|
asection *plt, *gotplt, *relplt;
|
||||||
|
|
||||||
|
/* When building a static executable, use .iplt, .igot.plt and
|
||||||
|
.rela.iplt sections for STT_GNU_IFUNC symbols. */
|
||||||
|
if (htab->splt != 0)
|
||||||
|
{
|
||||||
|
plt = htab->splt;
|
||||||
|
gotplt = htab->sgotplt;
|
||||||
|
relplt = htab->srelplt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
plt = htab->iplt;
|
||||||
|
gotplt = htab->igotplt;
|
||||||
|
relplt = htab->irelplt;
|
||||||
|
}
|
||||||
|
|
||||||
/* This symbol has an entry in the procedure linkage table. Set
|
/* This symbol has an entry in the procedure linkage table. Set
|
||||||
it up. */
|
it up. */
|
||||||
if (h->dynindx == -1
|
if ((h->dynindx == -1
|
||||||
|| htab->splt == NULL
|
&& !((h->forced_local || info->executable)
|
||||||
|| htab->sgotplt == NULL
|
&& h->def_regular
|
||||||
|| htab->srelplt == NULL)
|
&& h->type == STT_GNU_IFUNC))
|
||||||
|
|| plt == NULL
|
||||||
|
|| gotplt == NULL
|
||||||
|
|| relplt == NULL)
|
||||||
abort ();
|
abort ();
|
||||||
|
|
||||||
/* Get the index in the procedure linkage table which
|
/* Get the index in the procedure linkage table which
|
||||||
corresponds to this symbol. This is the index of this symbol
|
corresponds to this symbol. This is the index of this symbol
|
||||||
in all the symbols for which we are making plt entries. The
|
in all the symbols for which we are making plt entries. The
|
||||||
first entry in the procedure linkage table is reserved. */
|
first entry in the procedure linkage table is reserved.
|
||||||
plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
|
|
||||||
|
|
||||||
/* Get the offset into the .got table of the entry that
|
Get the offset into the .got table of the entry that
|
||||||
corresponds to this function. Each .got entry is GOT_ENTRY_SIZE
|
corresponds to this function. Each .got entry is GOT_ENTRY_SIZE
|
||||||
bytes. The first three are reserved for the dynamic linker. */
|
bytes. The first three are reserved for the dynamic linker.
|
||||||
|
|
||||||
|
For static executables, we don't reserve anything. */
|
||||||
|
|
||||||
|
if (plt == htab->splt)
|
||||||
|
{
|
||||||
|
plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
|
||||||
got_offset = (plt_index + 3) * GOT_ENTRY_SIZE;
|
got_offset = (plt_index + 3) * GOT_ENTRY_SIZE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
plt_index = h->plt.offset / PLT_ENTRY_SIZE;
|
||||||
|
got_offset = plt_index * GOT_ENTRY_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Fill in the entry in the procedure linkage table. */
|
/* Fill in the entry in the procedure linkage table. */
|
||||||
memcpy (htab->splt->contents + h->plt.offset, elf64_x86_64_plt_entry,
|
memcpy (plt->contents + h->plt.offset, elf64_x86_64_plt_entry,
|
||||||
PLT_ENTRY_SIZE);
|
PLT_ENTRY_SIZE);
|
||||||
|
|
||||||
/* Insert the relocation positions of the plt section. The magic
|
/* Insert the relocation positions of the plt section. The magic
|
||||||
|
@ -3345,35 +3630,56 @@ elf64_x86_64_finish_dynamic_symbol (bfd *output_bfd,
|
||||||
/* Put offset for jmp *name@GOTPCREL(%rip), since the
|
/* Put offset for jmp *name@GOTPCREL(%rip), since the
|
||||||
instruction uses 6 bytes, subtract this value. */
|
instruction uses 6 bytes, subtract this value. */
|
||||||
bfd_put_32 (output_bfd,
|
bfd_put_32 (output_bfd,
|
||||||
(htab->sgotplt->output_section->vma
|
(gotplt->output_section->vma
|
||||||
+ htab->sgotplt->output_offset
|
+ gotplt->output_offset
|
||||||
+ got_offset
|
+ got_offset
|
||||||
- htab->splt->output_section->vma
|
- plt->output_section->vma
|
||||||
- htab->splt->output_offset
|
- plt->output_offset
|
||||||
- h->plt.offset
|
- h->plt.offset
|
||||||
- 6),
|
- 6),
|
||||||
htab->splt->contents + h->plt.offset + 2);
|
plt->contents + h->plt.offset + 2);
|
||||||
|
|
||||||
|
/* Don't fill PLT entry for static executables. */
|
||||||
|
if (plt == htab->splt)
|
||||||
|
{
|
||||||
/* Put relocation index. */
|
/* Put relocation index. */
|
||||||
bfd_put_32 (output_bfd, plt_index,
|
bfd_put_32 (output_bfd, plt_index,
|
||||||
htab->splt->contents + h->plt.offset + 7);
|
plt->contents + h->plt.offset + 7);
|
||||||
/* Put offset for jmp .PLT0. */
|
/* Put offset for jmp .PLT0. */
|
||||||
bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
|
bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
|
||||||
htab->splt->contents + h->plt.offset + 12);
|
plt->contents + h->plt.offset + 12);
|
||||||
|
}
|
||||||
|
|
||||||
/* Fill in the entry in the global offset table, initially this
|
/* Fill in the entry in the global offset table, initially this
|
||||||
points to the pushq instruction in the PLT which is at offset 6. */
|
points to the pushq instruction in the PLT which is at offset 6. */
|
||||||
bfd_put_64 (output_bfd, (htab->splt->output_section->vma
|
bfd_put_64 (output_bfd, (plt->output_section->vma
|
||||||
+ htab->splt->output_offset
|
+ plt->output_offset
|
||||||
+ h->plt.offset + 6),
|
+ h->plt.offset + 6),
|
||||||
htab->sgotplt->contents + got_offset);
|
gotplt->contents + got_offset);
|
||||||
|
|
||||||
/* Fill in the entry in the .rela.plt section. */
|
/* Fill in the entry in the .rela.plt section. */
|
||||||
rela.r_offset = (htab->sgotplt->output_section->vma
|
rela.r_offset = (gotplt->output_section->vma
|
||||||
+ htab->sgotplt->output_offset
|
+ gotplt->output_offset
|
||||||
+ got_offset);
|
+ got_offset);
|
||||||
|
if (h->dynindx == -1
|
||||||
|
|| ((info->executable
|
||||||
|
|| ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
|
||||||
|
&& h->def_regular
|
||||||
|
&& h->type == STT_GNU_IFUNC))
|
||||||
|
{
|
||||||
|
/* If an STT_GNU_IFUNC symbol is locally defined, generate
|
||||||
|
R_X86_64_IRELATIVE instead of R_X86_64_JUMP_SLOT. */
|
||||||
|
rela.r_info = ELF64_R_INFO (0, R_X86_64_IRELATIVE);
|
||||||
|
rela.r_addend = (h->root.u.def.value
|
||||||
|
+ h->root.u.def.section->output_section->vma
|
||||||
|
+ h->root.u.def.section->output_offset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_JUMP_SLOT);
|
rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_JUMP_SLOT);
|
||||||
rela.r_addend = 0;
|
rela.r_addend = 0;
|
||||||
loc = htab->srelplt->contents + plt_index * sizeof (Elf64_External_Rela);
|
}
|
||||||
|
loc = relplt->contents + plt_index * sizeof (Elf64_External_Rela);
|
||||||
bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
|
bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
|
||||||
|
|
||||||
if (!h->def_regular)
|
if (!h->def_regular)
|
||||||
|
|
|
@ -1104,6 +1104,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
|
||||||
"BFD_RELOC_386_TLS_GOTDESC",
|
"BFD_RELOC_386_TLS_GOTDESC",
|
||||||
"BFD_RELOC_386_TLS_DESC_CALL",
|
"BFD_RELOC_386_TLS_DESC_CALL",
|
||||||
"BFD_RELOC_386_TLS_DESC",
|
"BFD_RELOC_386_TLS_DESC",
|
||||||
|
"BFD_RELOC_386_IRELATIVE",
|
||||||
"BFD_RELOC_X86_64_GOT32",
|
"BFD_RELOC_X86_64_GOT32",
|
||||||
"BFD_RELOC_X86_64_PLT32",
|
"BFD_RELOC_X86_64_PLT32",
|
||||||
"BFD_RELOC_X86_64_COPY",
|
"BFD_RELOC_X86_64_COPY",
|
||||||
|
@ -1130,6 +1131,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
|
||||||
"BFD_RELOC_X86_64_GOTPC32_TLSDESC",
|
"BFD_RELOC_X86_64_GOTPC32_TLSDESC",
|
||||||
"BFD_RELOC_X86_64_TLSDESC_CALL",
|
"BFD_RELOC_X86_64_TLSDESC_CALL",
|
||||||
"BFD_RELOC_X86_64_TLSDESC",
|
"BFD_RELOC_X86_64_TLSDESC",
|
||||||
|
"BFD_RELOC_X86_64_IRELATIVE",
|
||||||
"BFD_RELOC_NS32K_IMM_8",
|
"BFD_RELOC_NS32K_IMM_8",
|
||||||
"BFD_RELOC_NS32K_IMM_16",
|
"BFD_RELOC_NS32K_IMM_16",
|
||||||
"BFD_RELOC_NS32K_IMM_32",
|
"BFD_RELOC_NS32K_IMM_32",
|
||||||
|
|
|
@ -2492,6 +2492,8 @@ ENUMX
|
||||||
BFD_RELOC_386_TLS_DESC_CALL
|
BFD_RELOC_386_TLS_DESC_CALL
|
||||||
ENUMX
|
ENUMX
|
||||||
BFD_RELOC_386_TLS_DESC
|
BFD_RELOC_386_TLS_DESC
|
||||||
|
ENUMX
|
||||||
|
BFD_RELOC_386_IRELATIVE
|
||||||
ENUMDOC
|
ENUMDOC
|
||||||
i386/elf relocations
|
i386/elf relocations
|
||||||
|
|
||||||
|
@ -2547,6 +2549,8 @@ ENUMX
|
||||||
BFD_RELOC_X86_64_TLSDESC_CALL
|
BFD_RELOC_X86_64_TLSDESC_CALL
|
||||||
ENUMX
|
ENUMX
|
||||||
BFD_RELOC_X86_64_TLSDESC
|
BFD_RELOC_X86_64_TLSDESC
|
||||||
|
ENUMX
|
||||||
|
BFD_RELOC_X86_64_IRELATIVE
|
||||||
ENUMDOC
|
ENUMDOC
|
||||||
x86-64/elf relocations
|
x86-64/elf relocations
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
2009-06-01 H.J. Lu <hongjiu.lu@intel.com>
|
||||||
|
|
||||||
|
PR ld/10205
|
||||||
|
* i386.h (R_386_IRELATIVE): New.
|
||||||
|
* x86-64.h (R_X86_64_IRELATIVE): Likewise.
|
||||||
|
|
||||||
2009-05-27 H.J. Lu <hongjiu.lu@intel.com>
|
2009-05-27 H.J. Lu <hongjiu.lu@intel.com>
|
||||||
|
|
||||||
* common.h: Update comments for dynamic tag ranges.
|
* common.h: Update comments for dynamic tag ranges.
|
||||||
|
|
|
@ -66,6 +66,7 @@ START_RELOC_NUMBERS (elf_i386_reloc_type)
|
||||||
RELOC_NUMBER (R_386_TLS_GOTDESC, 39)
|
RELOC_NUMBER (R_386_TLS_GOTDESC, 39)
|
||||||
RELOC_NUMBER (R_386_TLS_DESC_CALL,40)
|
RELOC_NUMBER (R_386_TLS_DESC_CALL,40)
|
||||||
RELOC_NUMBER (R_386_TLS_DESC, 41)
|
RELOC_NUMBER (R_386_TLS_DESC, 41)
|
||||||
|
RELOC_NUMBER (R_386_IRELATIVE, 42) /* Adjust indirectly by program base */
|
||||||
|
|
||||||
/* Used by Intel. */
|
/* Used by Intel. */
|
||||||
RELOC_NUMBER (R_386_USED_BY_INTEL_200, 200)
|
RELOC_NUMBER (R_386_USED_BY_INTEL_200, 200)
|
||||||
|
|
|
@ -71,6 +71,7 @@ START_RELOC_NUMBERS (elf_x86_64_reloc_type)
|
||||||
RELOC_NUMBER (R_X86_64_TLSDESC_CALL, 35) /* Relaxable call through TLS
|
RELOC_NUMBER (R_X86_64_TLSDESC_CALL, 35) /* Relaxable call through TLS
|
||||||
descriptor. */
|
descriptor. */
|
||||||
RELOC_NUMBER (R_X86_64_TLSDESC, 36) /* 2x64-bit TLS descriptor. */
|
RELOC_NUMBER (R_X86_64_TLSDESC, 36) /* 2x64-bit TLS descriptor. */
|
||||||
|
RELOC_NUMBER (R_X86_64_IRELATIVE, 37) /* Adjust indirectly by program base */
|
||||||
RELOC_NUMBER (R_X86_64_GNU_VTINHERIT, 250) /* GNU C++ hack */
|
RELOC_NUMBER (R_X86_64_GNU_VTINHERIT, 250) /* GNU C++ hack */
|
||||||
RELOC_NUMBER (R_X86_64_GNU_VTENTRY, 251) /* GNU C++ hack */
|
RELOC_NUMBER (R_X86_64_GNU_VTENTRY, 251) /* GNU C++ hack */
|
||||||
END_RELOC_NUMBERS (R_X86_64_max)
|
END_RELOC_NUMBERS (R_X86_64_max)
|
||||||
|
|
|
@ -1,3 +1,30 @@
|
||||||
|
2009-06-01 H.J. Lu <hongjiu.lu@intel.com>
|
||||||
|
|
||||||
|
PR ld/10205
|
||||||
|
* ld-ifunc/ifunc.exp (contains_irelative_reloc): New.
|
||||||
|
Use it on executable and shared library.
|
||||||
|
Run *.d.
|
||||||
|
|
||||||
|
* ld-ifunc/lib.c: Add a hidden alias, __GI_library_func2, for
|
||||||
|
library_func2.
|
||||||
|
(library_func): New.
|
||||||
|
|
||||||
|
* ld-ifunc/ifunc-1-x86.d: New.
|
||||||
|
* ld-ifunc/ifunc-1-x86.s: Likewise.
|
||||||
|
* ld-ifunc/ifunc-2-i386.d: Likewise.
|
||||||
|
* ld-ifunc/ifunc-2-i386.s: Likewise.
|
||||||
|
* ld-ifunc/ifunc-2-x86-64.d: Likewise.
|
||||||
|
* ld-ifunc/ifunc-2-x86-64.s: Likewise.
|
||||||
|
* ld-ifunc/ifunc-3a-x86.d: Likewise.
|
||||||
|
* ld-ifunc/ifunc-3b-x86.d: Likewise.
|
||||||
|
* ld-ifunc/ifunc-3-x86.s: Likewise.
|
||||||
|
* ld-ifunc/ifunc-4-x86.d: Likewise.
|
||||||
|
* ld-ifunc/ifunc-4-x86.s: Likewise.
|
||||||
|
* ld-ifunc/ifunc-5-i386.d: Likewise.
|
||||||
|
* ld-ifunc/ifunc-5-i386.s: Likewise.
|
||||||
|
* ld-ifunc/ifunc-5-x86-64.d: Likewise.
|
||||||
|
* ld-ifunc/ifunc-5-x86-64.s: Likewise.
|
||||||
|
|
||||||
2009-05-27 Dave Korn <dave.korn.cygwin@gmail.com>
|
2009-05-27 Dave Korn <dave.korn.cygwin@gmail.com>
|
||||||
|
|
||||||
* ld-pe/non-c-lang-syms.c: New dump test source file.
|
* ld-pe/non-c-lang-syms.c: New dump test source 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
|
|
@ -0,0 +1,16 @@
|
||||||
|
.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@PLT
|
||||||
|
ret
|
||||||
|
.size bar, .-bar
|
|
@ -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
|
|
@ -0,0 +1,21 @@
|
||||||
|
.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 .L6
|
||||||
|
.L6:
|
||||||
|
popl %ebx
|
||||||
|
addl $_GLOBAL_OFFSET_TABLE_+[.-.L6], %ebx
|
||||||
|
call __GI_foo
|
||||||
|
leal __GI_foo@GOTOFF(%ebx), %eax
|
||||||
|
ret
|
||||||
|
.size bar, .-bar
|
|
@ -0,0 +1,8 @@
|
||||||
|
#ld: -shared
|
||||||
|
#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
|
|
@ -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
|
|
@ -0,0 +1,16 @@
|
||||||
|
.type foo, %gnu_indirect_function
|
||||||
|
.global __GI_foo
|
||||||
|
.protected __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@PLT
|
||||||
|
ret
|
||||||
|
.size bar, .-bar
|
|
@ -0,0 +1,8 @@
|
||||||
|
#source: ifunc-3-x86.s
|
||||||
|
#ld: -shared
|
||||||
|
#objdump: -dw
|
||||||
|
#target: x86_64-*-* i?86-*-*
|
||||||
|
|
||||||
|
#...
|
||||||
|
[ \t0-9a-f]+:[ \t0-9a-f]+call[ \t0-9a-fq]+<\*ABS\*@plt>
|
||||||
|
#pass
|
|
@ -0,0 +1,8 @@
|
||||||
|
#source: ifunc-3-x86.s
|
||||||
|
#ld: -shared
|
||||||
|
#readelf: -r --wide
|
||||||
|
#target: x86_64-*-* i?86-*-*
|
||||||
|
|
||||||
|
#...
|
||||||
|
[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_[_0-9A-Z]+_IRELATIVE[ ]*[0-9a-f]*
|
||||||
|
#pass
|
|
@ -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
|
|
@ -0,0 +1,19 @@
|
||||||
|
.text
|
||||||
|
.type foo, %gnu_indirect_function
|
||||||
|
.globl foo
|
||||||
|
.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
|
|
@ -0,0 +1,8 @@
|
||||||
|
#ld: -m elf_i386
|
||||||
|
#as: --32
|
||||||
|
#readelf: -r --wide
|
||||||
|
#target: x86_64-*-* i?86-*-*
|
||||||
|
|
||||||
|
#...
|
||||||
|
[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_386_IRELATIVE[ ]*
|
||||||
|
#pass
|
|
@ -0,0 +1,23 @@
|
||||||
|
.text
|
||||||
|
.type foo, %gnu_indirect_function
|
||||||
|
.globl foo
|
||||||
|
.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
|
|
@ -0,0 +1,7 @@
|
||||||
|
#ld:
|
||||||
|
#readelf: -r --wide
|
||||||
|
#target: x86_64-*-*
|
||||||
|
|
||||||
|
#...
|
||||||
|
[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_X86_64_IRELATIVE[ ]+[0-9a-f]*
|
||||||
|
#pass
|
|
@ -0,0 +1,19 @@
|
||||||
|
.text
|
||||||
|
.type foo, %gnu_indirect_function
|
||||||
|
.globl foo
|
||||||
|
.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
|
|
@ -98,6 +98,33 @@ proc contains_ifunc_symbol { binary_file } {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# A procedure to confirm that a file contains the R_*_IRELATIVE
|
||||||
|
# relocation.
|
||||||
|
# Returns -1 upon error, 0 if the relocation was not found and 1 if
|
||||||
|
# it was found.
|
||||||
|
proc contains_irelative_reloc { binary_file } {
|
||||||
|
global READELF
|
||||||
|
global READELFFLAGS
|
||||||
|
|
||||||
|
catch "exec $READELF $READELFFLAGS --relocs --wide $binary_file > readelf.out" got
|
||||||
|
|
||||||
|
if ![string match "" $got] then {
|
||||||
|
verbose "proc contains_irelative_reloc: Readelf produced unexpected out processing $binary_file: $got"
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Look for a line like this:
|
||||||
|
# 0000000000600ab0 0000000000000025 R_X86_64_IRELATIVE 000000000040061c
|
||||||
|
# 080496f4 0000002a R_386_IRELATIVE
|
||||||
|
|
||||||
|
|
||||||
|
if { ![regexp "\[0-9a-f\]+\[ \]+\[0-9a-f\]+\[ \]+R_\[_0-9A-Z\]+_IRELATIVE\[ \]*\[0-9a-f\]*\n" [file_contents readelf.out]] } {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
# A procedure to confirm that a file contains a relocation that references an IFUNC symbol.
|
# A procedure to confirm that a file contains a relocation that references an IFUNC symbol.
|
||||||
# Returns -1 upon error, 0 if the reloc was not found and 1 if it was found.
|
# Returns -1 upon error, 0 if the reloc was not found and 1 if it was found.
|
||||||
proc contains_ifunc_reloc { binary_file } {
|
proc contains_ifunc_reloc { binary_file } {
|
||||||
|
@ -184,11 +211,16 @@ if { $fails == 0 } {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check the executables.
|
# Check the executables and shared libraries
|
||||||
#
|
#
|
||||||
# The linked ifunc using executables should have an OSABI field of LINUX
|
# The linked ifunc using executables and the shared library containing
|
||||||
# The linked non-ifunc using executable should have an OSABI field of NONE (aka System V).
|
# ifunc should have an OSABI field of LINUX. The linked non-ifunc using
|
||||||
|
# executable should have an OSABI field of NONE (aka System V).
|
||||||
|
|
||||||
|
if {! [check_osabi tmpdir/libshared_ifunc.so {UNIX - Linux}]} {
|
||||||
|
fail "Shared libraries containing ifunc does not have an OS/ABI field of LINUX"
|
||||||
|
set fails [expr $fails + 1]
|
||||||
|
}
|
||||||
if {! [check_osabi tmpdir/static_prog {UNIX - Linux}]} {
|
if {! [check_osabi tmpdir/static_prog {UNIX - Linux}]} {
|
||||||
fail "Static ifunc-using executable does not have an OS/ABI field of LINUX"
|
fail "Static ifunc-using executable does not have an OS/ABI field of LINUX"
|
||||||
set fails [expr $fails + 1]
|
set fails [expr $fails + 1]
|
||||||
|
@ -202,9 +234,14 @@ if {! [check_osabi tmpdir/static_nonifunc_prog {UNIX - System V}]} {
|
||||||
set fails [expr $fails + 1]
|
set fails [expr $fails + 1]
|
||||||
}
|
}
|
||||||
|
|
||||||
# The linked ifunc using executables should contain an IFUNC symbol,
|
# The linked ifunc using executables and the shared library containing
|
||||||
# The non-ifunc using executable should not.
|
# ifunc should contain an IFUNC symbol. The non-ifunc using executable
|
||||||
|
# should not.
|
||||||
|
|
||||||
|
if {[contains_ifunc_symbol tmpdir/libshared_ifunc.so] != 1} {
|
||||||
|
fail "Shared libraries containing ifunc does not contain an IFUNC symbol"
|
||||||
|
set fails [expr $fails + 1]
|
||||||
|
}
|
||||||
if {[contains_ifunc_symbol tmpdir/static_prog] != 1} {
|
if {[contains_ifunc_symbol tmpdir/static_prog] != 1} {
|
||||||
fail "Static ifunc-using executable does not contain an IFUNC symbol"
|
fail "Static ifunc-using executable does not contain an IFUNC symbol"
|
||||||
set fails [expr $fails + 1]
|
set fails [expr $fails + 1]
|
||||||
|
@ -218,12 +255,17 @@ if {[contains_ifunc_symbol tmpdir/static_nonifunc_prog] != 0} {
|
||||||
set fails [expr $fails + 1]
|
set fails [expr $fails + 1]
|
||||||
}
|
}
|
||||||
|
|
||||||
# The linked ifunc using executablea should contain a dynamic reloc referencing the IFUNC symbol.
|
# The linked ifunc using executables and shared libraries should contain
|
||||||
# (Even the static executable which should have a dynamic section created for it).
|
# a dynamic reloc referencing the IFUNC symbol. (Even the static
|
||||||
# The non-ifunc using executable should not.
|
# executable which should have a dynamic section created for it). The
|
||||||
|
# non-ifunc using executable should not.
|
||||||
|
|
||||||
if {[contains_ifunc_reloc tmpdir/static_prog] != 1} {
|
if {[contains_irelative_reloc tmpdir/libshared_ifunc.so] != 1} {
|
||||||
fail "Static ifunc-using executable does not contain a reloc against an IFUNC symbol"
|
fail "ifunc-using shared library does not contain R_*_IRELATIVE relocation"
|
||||||
|
set fails [expr $fails + 1]
|
||||||
|
}
|
||||||
|
if {[contains_irelative_reloc tmpdir/static_prog] != 1} {
|
||||||
|
fail "Static ifunc-using executable does not contain R_*_IRELATIVE relocation"
|
||||||
set fails [expr $fails + 1]
|
set fails [expr $fails + 1]
|
||||||
}
|
}
|
||||||
if {[contains_ifunc_reloc tmpdir/dynamic_prog] != 1} {
|
if {[contains_ifunc_reloc tmpdir/dynamic_prog] != 1} {
|
||||||
|
@ -252,3 +294,10 @@ if { $verbose < 1 } {
|
||||||
remote_file host delete "tmpdir/static_prog"
|
remote_file host delete "tmpdir/static_prog"
|
||||||
remote_file host delete "tmpdir/static_nonifunc_prog"
|
remote_file host delete "tmpdir/static_nonifunc_prog"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set test_list [lsort [glob -nocomplain $srcdir/$subdir/*.d]]
|
||||||
|
foreach t $test_list {
|
||||||
|
# We need to strip the ".d", but can leave the dirname.
|
||||||
|
verbose [file rootname $t]
|
||||||
|
run_dump_test [file rootname $t]
|
||||||
|
}
|
||||||
|
|
|
@ -15,6 +15,19 @@ void * library_func2_ifunc (void) __asm__ ("library_func2");
|
||||||
void * library_func2_ifunc (void) { return global ? minus_one : zero ; }
|
void * library_func2_ifunc (void) { return global ? minus_one : zero ; }
|
||||||
__asm__(".type library_func2, %gnu_indirect_function");
|
__asm__(".type library_func2, %gnu_indirect_function");
|
||||||
|
|
||||||
|
extern int library_func2 (int);
|
||||||
|
extern __typeof (library_func2) library_func2 __asm__ ("__GI_library_func2");
|
||||||
|
|
||||||
|
__asm__(".global __GI_library_func2");
|
||||||
|
__asm__(".hidden __GI_library_func2");
|
||||||
|
__asm__(".set __GI_library_func2, library_func2");
|
||||||
|
|
||||||
|
int
|
||||||
|
library_func (int x)
|
||||||
|
{
|
||||||
|
return library_func2 (x);
|
||||||
|
}
|
||||||
|
|
||||||
#else /* WITHOUT_IFUNC */
|
#else /* WITHOUT_IFUNC */
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
Loading…
Reference in New Issue