mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2025-03-02 22:36:27 +00:00
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>
|
||||
|
||||
* 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_DESC_CALL,
|
||||
BFD_RELOC_386_TLS_DESC,
|
||||
BFD_RELOC_386_IRELATIVE,
|
||||
|
||||
/* x86-64/elf relocations */
|
||||
BFD_RELOC_X86_64_GOT32,
|
||||
@ -2868,6 +2869,7 @@ relaxation. */
|
||||
BFD_RELOC_X86_64_GOTPC32_TLSDESC,
|
||||
BFD_RELOC_X86_64_TLSDESC_CALL,
|
||||
BFD_RELOC_X86_64_TLSDESC,
|
||||
BFD_RELOC_X86_64_IRELATIVE,
|
||||
|
||||
/* ns32k relocations */
|
||||
BFD_RELOC_NS32K_IMM_8,
|
||||
|
442
bfd/elf32-i386.c
442
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,
|
||||
bfd_elf_generic_reloc, "R_386_TLS_DESC",
|
||||
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. */
|
||||
#define R_386_tls (R_386_TLS_DESC + 1 - R_386_tls_offset)
|
||||
#define R_386_vt_offset (R_386_GNU_VTINHERIT - R_386_tls)
|
||||
#define R_386_irelative (R_386_IRELATIVE + 1 - R_386_tls_offset)
|
||||
#define R_386_vt_offset (R_386_GNU_VTINHERIT - R_386_irelative)
|
||||
|
||||
/* GNU extension to record C++ vtable hierarchy. */
|
||||
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");
|
||||
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:
|
||||
TRACE ("BFD_RELOC_VTABLE_INHERIT");
|
||||
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
|
||||
>= R_386_ext - R_386_standard)
|
||||
&& ((indx = r_type - R_386_tls_offset) - R_386_ext
|
||||
>= R_386_tls - R_386_ext)
|
||||
&& ((indx = r_type - R_386_vt_offset) - R_386_tls
|
||||
>= R_386_vt - R_386_tls))
|
||||
>= R_386_irelative - R_386_ext)
|
||||
&& ((indx = r_type - R_386_vt_offset) - R_386_irelative
|
||||
>= R_386_vt - R_386_irelative))
|
||||
{
|
||||
(*_bfd_error_handler) (_("%B: invalid relocation type %d"),
|
||||
abfd, (int) r_type);
|
||||
@ -668,6 +675,9 @@ struct elf_i386_link_hash_table
|
||||
asection *srelplt;
|
||||
asection *sdynbss;
|
||||
asection *srelbss;
|
||||
asection *igotplt;
|
||||
asection *iplt;
|
||||
asection *irelplt;
|
||||
|
||||
/* The (unloaded but important) .rel.plt.unloaded section on VxWorks. */
|
||||
asection *srelplt2;
|
||||
@ -764,6 +774,9 @@ elf_i386_link_hash_table_create (bfd *abfd)
|
||||
ret->srelplt = NULL;
|
||||
ret->sdynbss = NULL;
|
||||
ret->srelbss = NULL;
|
||||
ret->igotplt= NULL;
|
||||
ret->iplt = NULL;
|
||||
ret->irelplt= NULL;
|
||||
ret->tls_ldm_got.refcount = 0;
|
||||
ret->next_tls_desc_index = 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
|
||||
|| h->root.type == bfd_link_hash_warning)
|
||||
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,
|
||||
@ -1474,12 +1568,6 @@ elf_i386_check_relocs (bfd *abfd,
|
||||
|
||||
if (sreloc == NULL)
|
||||
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
|
||||
@ -1689,6 +1777,17 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info,
|
||||
struct elf_i386_link_hash_table *htab;
|
||||
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
|
||||
will fill in the contents of the procedure linkage table later,
|
||||
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_entry *eh;
|
||||
struct elf_i386_dyn_relocs *p;
|
||||
bfd_boolean use_indirect_section = FALSE;
|
||||
|
||||
if (h->root.type == bfd_link_hash_indirect)
|
||||
return TRUE;
|
||||
@ -1832,12 +1930,80 @@ 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
|
||||
symbol in a hash traversal. So look at it now. */
|
||||
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;
|
||||
htab = elf_i386_hash_table (info);
|
||||
|
||||
if (htab->elf.dynamic_sections_created
|
||||
&& h->plt.refcount > 0)
|
||||
/* 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)
|
||||
{
|
||||
/* Make sure this symbol is output as a dynamic symbol.
|
||||
Undefined weak syms won't yet be marked as dynamic. */
|
||||
@ -1915,7 +2081,6 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||
h->needs_plt = 0;
|
||||
}
|
||||
|
||||
eh = (struct elf_i386_link_hash_entry *) h;
|
||||
eh->tlsdesc_got = (bfd_vma) -1;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
/* For the non-shared case, discard space for relocs against
|
||||
@ -2092,10 +2247,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||
{
|
||||
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);
|
||||
sreloc->size += p->count * sizeof (Elf32_External_Rel);
|
||||
@ -2299,6 +2451,8 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
|
||||
if (s == htab->splt
|
||||
|| s == htab->sgot
|
||||
|| s == htab->sgotplt
|
||||
|| s == htab->iplt
|
||||
|| s == htab->igotplt
|
||||
|| s == htab->sdynbss)
|
||||
{
|
||||
/* 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
|
||||
>= R_386_ext - R_386_standard)
|
||||
&& ((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)
|
||||
(_("%B: unrecognized relocation (0x%x) in section `%A'"),
|
||||
@ -2706,6 +2860,113 @@ elf_i386_relocate_section (bfd *output_bfd,
|
||||
if (info->relocatable)
|
||||
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)
|
||||
{
|
||||
case R_386_GOT32:
|
||||
@ -2899,12 +3160,6 @@ elf_i386_relocate_section (bfd *output_bfd,
|
||||
|| h->root.type != bfd_link_hash_undefweak)
|
||||
&& (r_type != R_386_PC32
|
||||
|| !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
|
||||
&& !info->shared
|
||||
&& h != NULL
|
||||
@ -2953,16 +3208,7 @@ elf_i386_relocate_section (bfd *output_bfd,
|
||||
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);
|
||||
|
||||
@ -3605,6 +3851,7 @@ elf_i386_relocate_section (bfd *output_bfd,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
do_relocation:
|
||||
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
|
||||
contents, rel->r_offset,
|
||||
relocation, 0);
|
||||
@ -3667,37 +3914,67 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
|
||||
bfd_vma got_offset;
|
||||
Elf_Internal_Rela rel;
|
||||
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
|
||||
it up. */
|
||||
|
||||
if (h->dynindx == -1
|
||||
|| htab->splt == NULL
|
||||
|| htab->sgotplt == NULL
|
||||
|| htab->srelplt == NULL)
|
||||
if ((h->dynindx == -1
|
||||
&& !((h->forced_local || info->executable)
|
||||
&& h->def_regular
|
||||
&& h->type == STT_GNU_IFUNC))
|
||||
|| plt == NULL
|
||||
|| gotplt == NULL
|
||||
|| relplt == NULL)
|
||||
abort ();
|
||||
|
||||
/* Get the index in the procedure linkage table which
|
||||
corresponds to this symbol. This is the index of this symbol
|
||||
in all the symbols for which we are making plt entries. The
|
||||
first entry in the procedure linkage table is reserved. */
|
||||
plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
|
||||
first entry in the procedure linkage table is reserved.
|
||||
|
||||
/* 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.
|
||||
The first three are reserved. */
|
||||
got_offset = (plt_index + 3) * 4;
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
plt_index = h->plt.offset / PLT_ENTRY_SIZE;
|
||||
got_offset = plt_index * 4;
|
||||
}
|
||||
|
||||
/* Fill in the entry in the procedure linkage table. */
|
||||
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);
|
||||
bfd_put_32 (output_bfd,
|
||||
(htab->sgotplt->output_section->vma
|
||||
+ htab->sgotplt->output_offset
|
||||
(gotplt->output_section->vma
|
||||
+ gotplt->output_offset
|
||||
+ got_offset),
|
||||
htab->splt->contents + h->plt.offset + 2);
|
||||
plt->contents + h->plt.offset + 2);
|
||||
|
||||
if (htab->is_vxworks)
|
||||
{
|
||||
@ -3737,31 +4014,52 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
|
||||
}
|
||||
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);
|
||||
bfd_put_32 (output_bfd, got_offset,
|
||||
htab->splt->contents + h->plt.offset + 2);
|
||||
plt->contents + h->plt.offset + 2);
|
||||
}
|
||||
|
||||
bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rel),
|
||||
htab->splt->contents + h->plt.offset + 7);
|
||||
bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
|
||||
htab->splt->contents + h->plt.offset + 12);
|
||||
/* Don't fill PLT entry for static executables. */
|
||||
if (plt == htab->splt)
|
||||
{
|
||||
bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rel),
|
||||
plt->contents + h->plt.offset + 7);
|
||||
bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
|
||||
plt->contents + h->plt.offset + 12);
|
||||
}
|
||||
|
||||
/* Fill in the entry in the global offset table. */
|
||||
bfd_put_32 (output_bfd,
|
||||
(htab->splt->output_section->vma
|
||||
+ htab->splt->output_offset
|
||||
(plt->output_section->vma
|
||||
+ plt->output_offset
|
||||
+ h->plt.offset
|
||||
+ 6),
|
||||
htab->sgotplt->contents + got_offset);
|
||||
gotplt->contents + got_offset);
|
||||
|
||||
/* Fill in the entry in the .rel.plt section. */
|
||||
rel.r_offset = (htab->sgotplt->output_section->vma
|
||||
+ htab->sgotplt->output_offset
|
||||
rel.r_offset = (gotplt->output_section->vma
|
||||
+ gotplt->output_offset
|
||||
+ got_offset);
|
||||
rel.r_info = ELF32_R_INFO (h->dynindx, R_386_JUMP_SLOT);
|
||||
loc = htab->srelplt->contents + plt_index * sizeof (Elf32_External_Rel);
|
||||
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);
|
||||
loc = relplt->contents + plt_index * sizeof (Elf32_External_Rel);
|
||||
bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
|
||||
|
||||
if (!h->def_regular)
|
||||
|
@ -143,12 +143,15 @@ static reloc_howto_type x86_64_elf_howto_table[] =
|
||||
complain_overflow_bitfield, bfd_elf_generic_reloc,
|
||||
"R_X86_64_TLSDESC",
|
||||
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.
|
||||
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_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)
|
||||
|
||||
/* 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_TLSDESC_CALL, R_X86_64_TLSDESC_CALL, },
|
||||
{ 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_ENTRY, R_X86_64_GNU_VTENTRY, },
|
||||
};
|
||||
@ -489,6 +493,9 @@ struct elf64_x86_64_link_hash_table
|
||||
asection *srelplt;
|
||||
asection *sdynbss;
|
||||
asection *srelbss;
|
||||
asection *igotplt;
|
||||
asection *iplt;
|
||||
asection *irelplt;
|
||||
|
||||
/* The offset into splt of the PLT entry for the TLS descriptor
|
||||
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->sdynbss = NULL;
|
||||
ret->srelbss = NULL;
|
||||
ret->igotplt= NULL;
|
||||
ret->iplt = NULL;
|
||||
ret->irelplt= NULL;
|
||||
ret->sym_sec.abfd = NULL;
|
||||
ret->tlsdesc_plt = 0;
|
||||
ret->tlsdesc_got = 0;
|
||||
@ -1011,7 +1021,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
||||
sym_hashes = elf_sym_hashes (abfd);
|
||||
|
||||
sreloc = NULL;
|
||||
|
||||
|
||||
rel_end = relocs + sec->reloc_count;
|
||||
for (rel = relocs; rel < rel_end; rel++)
|
||||
{
|
||||
@ -1037,6 +1047,94 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *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;
|
||||
|
||||
/* 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,
|
||||
@ -1298,12 +1396,6 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
||||
|
||||
if (sreloc == NULL)
|
||||
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
|
||||
@ -1528,6 +1620,17 @@ elf64_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
|
||||
struct elf64_x86_64_link_hash_table *htab;
|
||||
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
|
||||
will fill in the contents of the procedure linkage table later,
|
||||
when we know the address of the .got section. */
|
||||
@ -1659,19 +1762,86 @@ 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_entry *eh;
|
||||
struct elf64_x86_64_dyn_relocs *p;
|
||||
bfd_boolean use_indirect_section = FALSE;
|
||||
|
||||
if (h->root.type == bfd_link_hash_indirect)
|
||||
return TRUE;
|
||||
|
||||
if (h->root.type == bfd_link_hash_warning)
|
||||
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;
|
||||
htab = elf64_x86_64_hash_table (info);
|
||||
|
||||
if (htab->elf.dynamic_sections_created
|
||||
&& h->plt.refcount > 0)
|
||||
/* 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)
|
||||
{
|
||||
/* Make sure this symbol is output as a dynamic symbol.
|
||||
Undefined weak syms won't yet be marked as dynamic. */
|
||||
@ -1729,7 +1899,6 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
|
||||
h->needs_plt = 0;
|
||||
}
|
||||
|
||||
eh = (struct elf64_x86_64_link_hash_entry *) h;
|
||||
eh->tlsdesc_got = (bfd_vma) -1;
|
||||
|
||||
/* 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))
|
||||
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)
|
||||
{
|
||||
@ -1890,10 +2050,7 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
|
||||
{
|
||||
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);
|
||||
|
||||
@ -2110,6 +2267,8 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
|
||||
if (s == htab->splt
|
||||
|| s == htab->sgot
|
||||
|| s == htab->sgotplt
|
||||
|| s == htab->iplt
|
||||
|| s == htab->igotplt
|
||||
|| s == htab->sdynbss)
|
||||
{
|
||||
/* 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_reloc_status_type r;
|
||||
int tls_type;
|
||||
asection *base_got;
|
||||
|
||||
r_type = ELF64_R_TYPE (rel->r_info);
|
||||
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)
|
||||
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
|
||||
copied into the output file to be resolved at run time. */
|
||||
switch (r_type)
|
||||
{
|
||||
asection *base_got;
|
||||
case R_X86_64_GOT32:
|
||||
case R_X86_64_GOT64:
|
||||
/* 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)
|
||||
&& (! IS_X86_64_PCREL_TYPE (r_type)
|
||||
|| ! 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
|
||||
&& !info->shared
|
||||
&& h != NULL
|
||||
@ -2797,16 +3060,7 @@ 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);
|
||||
|
||||
@ -3253,6 +3507,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
||||
howto->name,
|
||||
h->root.root.string);
|
||||
|
||||
do_relocation:
|
||||
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
|
||||
contents, rel->r_offset,
|
||||
relocation, rel->r_addend);
|
||||
@ -3315,28 +3570,58 @@ elf64_x86_64_finish_dynamic_symbol (bfd *output_bfd,
|
||||
bfd_vma got_offset;
|
||||
Elf_Internal_Rela rela;
|
||||
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
|
||||
it up. */
|
||||
if (h->dynindx == -1
|
||||
|| htab->splt == NULL
|
||||
|| htab->sgotplt == NULL
|
||||
|| htab->srelplt == NULL)
|
||||
if ((h->dynindx == -1
|
||||
&& !((h->forced_local || info->executable)
|
||||
&& h->def_regular
|
||||
&& h->type == STT_GNU_IFUNC))
|
||||
|| plt == NULL
|
||||
|| gotplt == NULL
|
||||
|| relplt == NULL)
|
||||
abort ();
|
||||
|
||||
/* Get the index in the procedure linkage table which
|
||||
corresponds to this symbol. This is the index of this symbol
|
||||
in all the symbols for which we are making plt entries. The
|
||||
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
|
||||
first entry in the procedure linkage table is reserved.
|
||||
|
||||
Get the offset into the .got table of the entry that
|
||||
corresponds to this function. Each .got entry is GOT_ENTRY_SIZE
|
||||
bytes. The first three are reserved for the dynamic linker. */
|
||||
got_offset = (plt_index + 3) * GOT_ENTRY_SIZE;
|
||||
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;
|
||||
}
|
||||
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. */
|
||||
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);
|
||||
|
||||
/* 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
|
||||
instruction uses 6 bytes, subtract this value. */
|
||||
bfd_put_32 (output_bfd,
|
||||
(htab->sgotplt->output_section->vma
|
||||
+ htab->sgotplt->output_offset
|
||||
(gotplt->output_section->vma
|
||||
+ gotplt->output_offset
|
||||
+ got_offset
|
||||
- htab->splt->output_section->vma
|
||||
- htab->splt->output_offset
|
||||
- plt->output_section->vma
|
||||
- plt->output_offset
|
||||
- h->plt.offset
|
||||
- 6),
|
||||
htab->splt->contents + h->plt.offset + 2);
|
||||
/* Put relocation index. */
|
||||
bfd_put_32 (output_bfd, plt_index,
|
||||
htab->splt->contents + h->plt.offset + 7);
|
||||
/* Put offset for jmp .PLT0. */
|
||||
bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
|
||||
htab->splt->contents + h->plt.offset + 12);
|
||||
plt->contents + h->plt.offset + 2);
|
||||
|
||||
/* Don't fill PLT entry for static executables. */
|
||||
if (plt == htab->splt)
|
||||
{
|
||||
/* Put relocation index. */
|
||||
bfd_put_32 (output_bfd, plt_index,
|
||||
plt->contents + h->plt.offset + 7);
|
||||
/* Put offset for jmp .PLT0. */
|
||||
bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
|
||||
plt->contents + h->plt.offset + 12);
|
||||
}
|
||||
|
||||
/* Fill in the entry in the global offset table, initially this
|
||||
points to the pushq instruction in the PLT which is at offset 6. */
|
||||
bfd_put_64 (output_bfd, (htab->splt->output_section->vma
|
||||
+ htab->splt->output_offset
|
||||
bfd_put_64 (output_bfd, (plt->output_section->vma
|
||||
+ plt->output_offset
|
||||
+ h->plt.offset + 6),
|
||||
htab->sgotplt->contents + got_offset);
|
||||
gotplt->contents + got_offset);
|
||||
|
||||
/* Fill in the entry in the .rela.plt section. */
|
||||
rela.r_offset = (htab->sgotplt->output_section->vma
|
||||
+ htab->sgotplt->output_offset
|
||||
rela.r_offset = (gotplt->output_section->vma
|
||||
+ gotplt->output_offset
|
||||
+ got_offset);
|
||||
rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_JUMP_SLOT);
|
||||
rela.r_addend = 0;
|
||||
loc = htab->srelplt->contents + plt_index * sizeof (Elf64_External_Rela);
|
||||
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_addend = 0;
|
||||
}
|
||||
loc = relplt->contents + plt_index * sizeof (Elf64_External_Rela);
|
||||
bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
|
||||
|
||||
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_DESC_CALL",
|
||||
"BFD_RELOC_386_TLS_DESC",
|
||||
"BFD_RELOC_386_IRELATIVE",
|
||||
"BFD_RELOC_X86_64_GOT32",
|
||||
"BFD_RELOC_X86_64_PLT32",
|
||||
"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_TLSDESC_CALL",
|
||||
"BFD_RELOC_X86_64_TLSDESC",
|
||||
"BFD_RELOC_X86_64_IRELATIVE",
|
||||
"BFD_RELOC_NS32K_IMM_8",
|
||||
"BFD_RELOC_NS32K_IMM_16",
|
||||
"BFD_RELOC_NS32K_IMM_32",
|
||||
|
@ -2492,6 +2492,8 @@ ENUMX
|
||||
BFD_RELOC_386_TLS_DESC_CALL
|
||||
ENUMX
|
||||
BFD_RELOC_386_TLS_DESC
|
||||
ENUMX
|
||||
BFD_RELOC_386_IRELATIVE
|
||||
ENUMDOC
|
||||
i386/elf relocations
|
||||
|
||||
@ -2547,6 +2549,8 @@ ENUMX
|
||||
BFD_RELOC_X86_64_TLSDESC_CALL
|
||||
ENUMX
|
||||
BFD_RELOC_X86_64_TLSDESC
|
||||
ENUMX
|
||||
BFD_RELOC_X86_64_IRELATIVE
|
||||
ENUMDOC
|
||||
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>
|
||||
|
||||
* 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_DESC_CALL,40)
|
||||
RELOC_NUMBER (R_386_TLS_DESC, 41)
|
||||
RELOC_NUMBER (R_386_IRELATIVE, 42) /* Adjust indirectly by program base */
|
||||
|
||||
/* Used by Intel. */
|
||||
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
|
||||
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_VTENTRY, 251) /* GNU C++ hack */
|
||||
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>
|
||||
|
||||
* ld-pe/non-c-lang-syms.c: New dump test source file.
|
||||
|
7
ld/testsuite/ld-ifunc/ifunc-1-x86.d
Normal file
7
ld/testsuite/ld-ifunc/ifunc-1-x86.d
Normal 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
|
16
ld/testsuite/ld-ifunc/ifunc-1-x86.s
Normal file
16
ld/testsuite/ld-ifunc/ifunc-1-x86.s
Normal file
@ -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
|
8
ld/testsuite/ld-ifunc/ifunc-2-i386.d
Normal file
8
ld/testsuite/ld-ifunc/ifunc-2-i386.d
Normal file
@ -0,0 +1,8 @@
|
||||
#ld: -m elf_i386 -shared
|
||||
#as: --32
|
||||
#objdump: -dw
|
||||
#target: x86_64-*-* i?86-*-*
|
||||
|
||||
#...
|
||||
[ \t0-9a-f]+:[ \t0-9a-f]+call[ \t0-9a-f]+<\*ABS\*@plt>
|
||||
#pass
|
21
ld/testsuite/ld-ifunc/ifunc-2-i386.s
Normal file
21
ld/testsuite/ld-ifunc/ifunc-2-i386.s
Normal file
@ -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
|
8
ld/testsuite/ld-ifunc/ifunc-2-x86-64.d
Normal file
8
ld/testsuite/ld-ifunc/ifunc-2-x86-64.d
Normal file
@ -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
|
17
ld/testsuite/ld-ifunc/ifunc-2-x86-64.s
Normal file
17
ld/testsuite/ld-ifunc/ifunc-2-x86-64.s
Normal file
@ -0,0 +1,17 @@
|
||||
.type foo, %gnu_indirect_function
|
||||
.global __GI_foo
|
||||
.hidden __GI_foo
|
||||
.set __GI_foo, foo
|
||||
.text
|
||||
.globl foo
|
||||
.type foo, @function
|
||||
foo:
|
||||
ret
|
||||
.size foo, .-foo
|
||||
.globl bar
|
||||
.type bar, @function
|
||||
bar:
|
||||
call __GI_foo
|
||||
leaq __GI_foo(%rip), %rax
|
||||
ret
|
||||
.size bar, .-bar
|
16
ld/testsuite/ld-ifunc/ifunc-3-x86.s
Normal file
16
ld/testsuite/ld-ifunc/ifunc-3-x86.s
Normal file
@ -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
|
8
ld/testsuite/ld-ifunc/ifunc-3a-x86.d
Normal file
8
ld/testsuite/ld-ifunc/ifunc-3a-x86.d
Normal file
@ -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
|
8
ld/testsuite/ld-ifunc/ifunc-3b-x86.d
Normal file
8
ld/testsuite/ld-ifunc/ifunc-3b-x86.d
Normal file
@ -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
|
7
ld/testsuite/ld-ifunc/ifunc-4-x86.d
Normal file
7
ld/testsuite/ld-ifunc/ifunc-4-x86.d
Normal file
@ -0,0 +1,7 @@
|
||||
#ld:
|
||||
#readelf: -r --wide
|
||||
#target: x86_64-*-* i?86-*-*
|
||||
|
||||
#...
|
||||
[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_[_0-9A-Z]+_IRELATIVE[ ]*[0-9a-f]*
|
||||
#pass
|
19
ld/testsuite/ld-ifunc/ifunc-4-x86.s
Normal file
19
ld/testsuite/ld-ifunc/ifunc-4-x86.s
Normal file
@ -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
|
8
ld/testsuite/ld-ifunc/ifunc-5-i386.d
Normal file
8
ld/testsuite/ld-ifunc/ifunc-5-i386.d
Normal file
@ -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
|
23
ld/testsuite/ld-ifunc/ifunc-5-i386.s
Normal file
23
ld/testsuite/ld-ifunc/ifunc-5-i386.s
Normal file
@ -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
|
7
ld/testsuite/ld-ifunc/ifunc-5-x86-64.d
Normal file
7
ld/testsuite/ld-ifunc/ifunc-5-x86-64.d
Normal file
@ -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
|
19
ld/testsuite/ld-ifunc/ifunc-5-x86-64.s
Normal file
19
ld/testsuite/ld-ifunc/ifunc-5-x86-64.s
Normal file
@ -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
|
||||
}
|
||||
|
||||
# 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.
|
||||
# Returns -1 upon error, 0 if the reloc was not found and 1 if it was found.
|
||||
proc contains_ifunc_reloc { binary_file } {
|
||||
@ -184,11 +211,16 @@ if { $fails == 0 } {
|
||||
return
|
||||
}
|
||||
|
||||
# Check the executables.
|
||||
# Check the executables and shared libraries
|
||||
#
|
||||
# The linked ifunc using executables should have an OSABI field of LINUX
|
||||
# The linked non-ifunc using executable should have an OSABI field of NONE (aka System V).
|
||||
# The linked ifunc using executables and the shared library containing
|
||||
# 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}]} {
|
||||
fail "Static ifunc-using executable does not have an OS/ABI field of LINUX"
|
||||
set fails [expr $fails + 1]
|
||||
@ -202,9 +234,14 @@ if {! [check_osabi tmpdir/static_nonifunc_prog {UNIX - System V}]} {
|
||||
set fails [expr $fails + 1]
|
||||
}
|
||||
|
||||
# The linked ifunc using executables should contain an IFUNC symbol,
|
||||
# The non-ifunc using executable should not.
|
||||
# The linked ifunc using executables and the shared library containing
|
||||
# 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} {
|
||||
fail "Static ifunc-using executable does not contain an IFUNC symbol"
|
||||
set fails [expr $fails + 1]
|
||||
@ -218,12 +255,17 @@ if {[contains_ifunc_symbol tmpdir/static_nonifunc_prog] != 0} {
|
||||
set fails [expr $fails + 1]
|
||||
}
|
||||
|
||||
# The linked ifunc using executablea should contain a dynamic reloc referencing the IFUNC symbol.
|
||||
# (Even the static executable which should have a dynamic section created for it).
|
||||
# The non-ifunc using executable should not.
|
||||
# The linked ifunc using executables and shared libraries should contain
|
||||
# a dynamic reloc referencing the IFUNC symbol. (Even the static
|
||||
# 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} {
|
||||
fail "Static ifunc-using executable does not contain a reloc against an IFUNC symbol"
|
||||
if {[contains_irelative_reloc tmpdir/libshared_ifunc.so] != 1} {
|
||||
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]
|
||||
}
|
||||
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_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 ; }
|
||||
__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 */
|
||||
|
||||
int
|
||||
|
Loading…
x
Reference in New Issue
Block a user