1,6 → 1,5 |
/* ELF STT_GNU_IFUNC support. |
Copyright 2009-2013 |
Free Software Foundation, Inc. |
Copyright (C) 2009-2015 Free Software Foundation, Inc. |
|
This file is part of BFD, the Binary File Descriptor library. |
|
54,7 → 53,7 |
if (bed->plt_readonly) |
pltflags |= SEC_READONLY; |
|
if (info->shared) |
if (bfd_link_pic (info)) |
{ |
/* We need to create .rel[a].ifunc for shared objects. */ |
const char *rel_sec = (bed->rela_plts_and_copies_p |
126,7 → 125,7 |
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 |
if (!bfd_link_pic (info) |
&& (h->dynindx != -1 |
|| info->export_dynamic) |
&& h->pointer_equality_needed) |
146,7 → 145,7 |
/* When building shared library, we need to handle the case where it is |
marked with regular reference, but not non-GOT reference since the |
non-GOT reference bit may not be set here. */ |
if (info->shared && !h->non_got_ref && h->ref_regular) |
if (bfd_link_pic (info) && !h->non_got_ref && h->ref_regular) |
for (p = *head; p != NULL; p = p->next) |
if (p->count) |
{ |
221,7 → 220,7 |
|
/* We need dynamic relocation for STT_GNU_IFUNC symbol only when |
there is a non-GOT reference in a shared object. */ |
if (!info->shared |
if (!bfd_link_pic (info) |
|| !h->non_got_ref) |
*head = NULL; |
|
253,12 → 252,12 |
objects at run-time. |
We only need to relocate .got entry in shared object. */ |
if (h->got.refcount <= 0 |
|| (info->shared |
|| (bfd_link_pic (info) |
&& (h->dynindx == -1 |
|| h->forced_local)) |
|| (!info->shared |
|| (!bfd_link_pic (info) |
&& !h->pointer_equality_needed) |
|| (info->executable && info->shared) |
|| bfd_link_pie (info) |
|| htab->sgot == NULL) |
{ |
/* Use .got.plt. */ |
268,9 → 267,134 |
{ |
h->got.offset = htab->sgot->size; |
htab->sgot->size += got_entry_size; |
if (info->shared) |
if (bfd_link_pic (info)) |
htab->srelgot->size += sizeof_reloc; |
} |
|
return TRUE; |
} |
|
/* Similar to _bfd_elf_get_synthetic_symtab, optimized for unsorted PLT |
entries. PLT is the PLT section. PLT_SYM_VAL is a function pointer |
which returns an array of PLT entry symbol values. */ |
|
long |
_bfd_elf_ifunc_get_synthetic_symtab |
(bfd *abfd, long symcount ATTRIBUTE_UNUSED, |
asymbol **syms ATTRIBUTE_UNUSED, long dynsymcount, asymbol **dynsyms, |
asymbol **ret, asection *plt, |
bfd_vma *(*get_plt_sym_val) (bfd *, asymbol **, asection *, asection *)) |
{ |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
asection *relplt; |
asymbol *s; |
const char *relplt_name; |
bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); |
arelent *p; |
long count, i, n; |
size_t size; |
Elf_Internal_Shdr *hdr; |
char *names; |
bfd_vma *plt_sym_val; |
|
*ret = NULL; |
|
if (plt == NULL) |
return 0; |
|
if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0) |
return 0; |
|
if (dynsymcount <= 0) |
return 0; |
|
relplt_name = bed->relplt_name; |
if (relplt_name == NULL) |
relplt_name = bed->rela_plts_and_copies_p ? ".rela.plt" : ".rel.plt"; |
relplt = bfd_get_section_by_name (abfd, relplt_name); |
if (relplt == NULL) |
return 0; |
|
hdr = &elf_section_data (relplt)->this_hdr; |
if (hdr->sh_link != elf_dynsymtab (abfd) |
|| (hdr->sh_type != SHT_REL && hdr->sh_type != SHT_RELA)) |
return 0; |
|
slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; |
if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE)) |
return -1; |
|
count = relplt->size / hdr->sh_entsize; |
size = count * sizeof (asymbol); |
p = relplt->relocation; |
for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel) |
{ |
size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt"); |
if (p->addend != 0) |
{ |
#ifdef BFD64 |
size += sizeof ("+0x") - 1 + 8 + 8 * (bed->s->elfclass == ELFCLASS64); |
#else |
size += sizeof ("+0x") - 1 + 8; |
#endif |
} |
} |
|
plt_sym_val = get_plt_sym_val (abfd, dynsyms, plt, relplt); |
if (plt_sym_val == NULL) |
return -1; |
|
s = *ret = (asymbol *) bfd_malloc (size); |
if (s == NULL) |
{ |
free (plt_sym_val); |
return -1; |
} |
|
names = (char *) (s + count); |
p = relplt->relocation; |
n = 0; |
for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel) |
{ |
size_t len; |
bfd_vma addr; |
|
addr = plt_sym_val[i]; |
if (addr == (bfd_vma) -1) |
continue; |
|
*s = **p->sym_ptr_ptr; |
/* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set. Since |
we are defining a symbol, ensure one of them is set. */ |
if ((s->flags & BSF_LOCAL) == 0) |
s->flags |= BSF_GLOBAL; |
s->flags |= BSF_SYNTHETIC; |
s->section = plt; |
s->value = addr - plt->vma; |
s->name = names; |
s->udata.p = NULL; |
len = strlen ((*p->sym_ptr_ptr)->name); |
memcpy (names, (*p->sym_ptr_ptr)->name, len); |
names += len; |
if (p->addend != 0) |
{ |
char buf[30], *a; |
|
memcpy (names, "+0x", sizeof ("+0x") - 1); |
names += sizeof ("+0x") - 1; |
bfd_sprintf_vma (abfd, buf, p->addend); |
for (a = buf; *a == '0'; ++a) |
; |
len = strlen (a); |
memcpy (names, a, len); |
names += len; |
} |
memcpy (names, "@plt", sizeof ("@plt")); |
names += sizeof ("@plt"); |
++s, ++n; |
} |
|
free (plt_sym_val); |
|
return n; |
} |