forked from Imagelibrary/binutils-gdb
2009-06-17 H.J. Lu <hongjiu.lu@intel.com>
* elf-bfd.h (_bfd_elf_allocate_ifunc_dyn_relocs): New. * elf-ifunc.c (_bfd_elf_allocate_ifunc_dyn_relocs): Likewise. * elf32-i386.c (elf_i386_allocate_dynrelocs): Use it. * elf64-x86-64.c (elf64_x86_64_allocate_dynrelocs): Likewise. 2009-06-17 H.J. Lu <hongjiu.lu@intel.com> * elf-bfd.h (_bfd_elf_create_ifunc_dyn_reloc): New. * elf-ifunc.c (_bfd_elf_create_ifunc_dyn_reloc): Likewise. * elf32-i386.c (elf_i386_check_relocs): Use it. * elf64-x86-64.c (elf64_x86_64_check_relocs): Likewise. 2009-06-17 H.J. Lu <hongjiu.lu@intel.com> * elf-bfd.h (elf_dyn_relocs): New. * elf32-i386.c (elf_i386_dyn_relocs): Removed. (elf_i386_link_hash_entry): Replace elf_i386_dyn_relocs with elf_dyn_relocs. (elf_i386_copy_indirect_symbol): Likewise. (elf_i386_check_relocs): Likewise. (elf_i386_gc_sweep_hook): Likewise. (elf_i386_allocate_dynrelocs): Likewise. (elf_i386_readonly_dynrelocs): Likewise. (elf_i386_size_dynamic_sections): Likewise. * elf64-x86-64.c (elf64_x86_64_dyn_relocs): Removed. (elf64_x86_64_link_hash_entry): Replace elf64_x86_64_dyn_relocs with elf_dyn_relocs. (elf64_x86_64_copy_indirect_symbol): Updated. (elf64_x86_64_check_relocs): Likewise. (elf64_x86_64_gc_sweep_hook): Likewise. (elf64_x86_64_adjust_dynamic_symbol): Likewise. (elf64_x86_64_allocate_dynrelocs): Likewise. (elf64_x86_64_readonly_dynrelocs): Likewise. (elf64_x86_64_size_dynamic_sections): Likewise.
This commit is contained in:
182
bfd/elf-ifunc.c
182
bfd/elf-ifunc.c
@@ -103,3 +103,185 @@ _bfd_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info)
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* For a STT_GNU_IFUNC symbol, create a dynamic reloc section, SRELOC,
|
||||
for the input section, SEC, and append this reloc to HEAD. */
|
||||
|
||||
asection *
|
||||
_bfd_elf_create_ifunc_dyn_reloc (bfd *abfd, struct bfd_link_info *info,
|
||||
asection *sec, asection *sreloc,
|
||||
struct elf_dyn_relocs **head)
|
||||
{
|
||||
struct elf_dyn_relocs *p;
|
||||
struct elf_link_hash_table *htab = elf_hash_table (info);
|
||||
|
||||
if (sreloc == NULL)
|
||||
{
|
||||
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
|
||||
|
||||
if (htab->dynobj == NULL)
|
||||
htab->dynobj = abfd;
|
||||
|
||||
sreloc = _bfd_elf_make_dynamic_reloc_section (sec, htab->dynobj,
|
||||
bed->s->log_file_align,
|
||||
abfd,
|
||||
bed->rela_plts_and_copies_p);
|
||||
if (sreloc == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = *head;
|
||||
if (p == NULL || p->sec != sec)
|
||||
{
|
||||
bfd_size_type amt = sizeof *p;
|
||||
|
||||
p = ((struct elf_dyn_relocs *) bfd_alloc (htab->dynobj, amt));
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
p->next = *head;
|
||||
*head = p;
|
||||
p->sec = sec;
|
||||
p->count = 0;
|
||||
p->pc_count = 0;
|
||||
}
|
||||
p->count += 1;
|
||||
|
||||
return sreloc;
|
||||
}
|
||||
|
||||
/* Allocate space in .plt, .got and associated reloc sections for
|
||||
dynamic relocs against a STT_GNU_IFUNC symbol definition. */
|
||||
|
||||
bfd_boolean
|
||||
_bfd_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info,
|
||||
struct elf_link_hash_entry *h,
|
||||
struct elf_dyn_relocs **head,
|
||||
unsigned int plt_entry_size,
|
||||
unsigned int got_entry_size)
|
||||
{
|
||||
asection *plt, *gotplt, *relplt;
|
||||
struct elf_dyn_relocs *p;
|
||||
unsigned int sizeof_reloc;
|
||||
const struct elf_backend_data *bed;
|
||||
struct elf_link_hash_table *htab;
|
||||
|
||||
/* When a shared library references a STT_GNU_IFUNC symbol defined
|
||||
in executable, the address of the resolved function may be used.
|
||||
But in non-shared executable, the address of its .plt slot may
|
||||
be used. Pointer equality may not work correctly. PIE should
|
||||
be used if pointer equality is required here. */
|
||||
if (!info->shared
|
||||
&& (h->dynindx != -1
|
||||
|| info->export_dynamic)
|
||||
&& h->pointer_equality_needed)
|
||||
{
|
||||
info->callbacks->einfo
|
||||
(_("%F%P: dynamic STT_GNU_IFUNC symbol `%s' with pointer "
|
||||
"equality in `%B' can not be used when making an "
|
||||
"executable; recompile with -fPIE and relink with -pie\n"),
|
||||
h->root.root.string,
|
||||
h->root.u.def.section->owner);
|
||||
bfd_set_error (bfd_error_bad_value);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
*head = NULL;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bed = get_elf_backend_data (info->output_bfd);
|
||||
if (bed->rela_plts_and_copies_p)
|
||||
sizeof_reloc = bed->s->sizeof_rela;
|
||||
else
|
||||
sizeof_reloc = bed->s->sizeof_rel;
|
||||
|
||||
htab = elf_hash_table (info);
|
||||
|
||||
/* When building a static executable, use .iplt, .igot.plt and
|
||||
.rel[a].iplt sections for STT_GNU_IFUNC symbols. */
|
||||
if (htab->splt != NULL)
|
||||
{
|
||||
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_*_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 .rel[a].plt/.rel[a].iplt
|
||||
section. */
|
||||
relplt->size += sizeof_reloc;
|
||||
relplt->reloc_count++;
|
||||
|
||||
/* We need dynamic relocation for STT_GNU_IFUNC symbol only when
|
||||
there is a non-GOT reference in a shared object. */
|
||||
if (!info->shared
|
||||
|| !h->non_got_ref)
|
||||
*head = NULL;
|
||||
|
||||
/* Finally, allocate space. */
|
||||
for (p = *head; p != NULL; p = p->next)
|
||||
htab->irelifunc->size += p->count * sizeof_reloc;
|
||||
|
||||
/* For STT_GNU_IFUNC symbol, .got.plt has the real function addres
|
||||
and .got has the PLT entry adddress. We will load the GOT entry
|
||||
with the PLT entry in finish_dynamic_symbol if it is used. For
|
||||
branch, it uses .got.plt. For symbol value,
|
||||
1. Use .got.plt in a shared object if it is forced local or not
|
||||
dynamic.
|
||||
2. Use .got.plt in a non-shared object if pointer equality isn't
|
||||
needed.
|
||||
3. Use .got.plt in PIE.
|
||||
4. Use .got.plt if .got isn't used.
|
||||
5. Otherwise use .got so that it can be shared among different
|
||||
objects at run-time.
|
||||
We only need to relocate .got entry in shared object. */
|
||||
if ((info->shared
|
||||
&& (h->dynindx == -1
|
||||
|| h->forced_local))
|
||||
|| (!info->shared
|
||||
&& !h->pointer_equality_needed)
|
||||
|| (info->executable && info->shared)
|
||||
|| htab->sgot == NULL)
|
||||
{
|
||||
/* Use .got.plt. */
|
||||
h->got.offset = (bfd_vma) -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
h->got.offset = htab->sgot->size;
|
||||
htab->sgot->size += got_entry_size;
|
||||
if (info->shared)
|
||||
htab->srelgot->size += sizeof_reloc;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user