mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-09-13 10:29:26 +08:00
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:
@ -1,3 +1,42 @@
|
|||||||
|
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.
|
||||||
|
|
||||||
2009-06-17 H.J. Lu <hongjiu.lu@intel.com>
|
2009-06-17 H.J. Lu <hongjiu.lu@intel.com>
|
||||||
|
|
||||||
* elf32-arm.c (create_got_section): Get existing .rela.got
|
* elf32-arm.c (create_got_section): Get existing .rela.got
|
||||||
|
@ -2157,8 +2157,34 @@ extern int _bfd_elf_obj_attrs_arg_type (bfd *, int, int);
|
|||||||
extern void _bfd_elf_parse_attributes (bfd *, Elf_Internal_Shdr *);
|
extern void _bfd_elf_parse_attributes (bfd *, Elf_Internal_Shdr *);
|
||||||
extern bfd_boolean _bfd_elf_merge_object_attributes (bfd *, bfd *);
|
extern bfd_boolean _bfd_elf_merge_object_attributes (bfd *, bfd *);
|
||||||
|
|
||||||
|
/* The linker may needs to keep track of the number of relocs that it
|
||||||
|
decides to copy as dynamic relocs in check_relocs for each symbol.
|
||||||
|
This is so that it can later discard them if they are found to be
|
||||||
|
unnecessary. We can store the information in a field extending the
|
||||||
|
regular ELF linker hash table. */
|
||||||
|
|
||||||
|
struct elf_dyn_relocs
|
||||||
|
{
|
||||||
|
struct elf_dyn_relocs *next;
|
||||||
|
|
||||||
|
/* The input section of the reloc. */
|
||||||
|
asection *sec;
|
||||||
|
|
||||||
|
/* Total number of relocs copied for the input section. */
|
||||||
|
bfd_size_type count;
|
||||||
|
|
||||||
|
/* Number of pc-relative relocs copied for the input section. */
|
||||||
|
bfd_size_type pc_count;
|
||||||
|
};
|
||||||
|
|
||||||
extern bfd_boolean _bfd_elf_create_ifunc_sections
|
extern bfd_boolean _bfd_elf_create_ifunc_sections
|
||||||
(bfd *, struct bfd_link_info *);
|
(bfd *, struct bfd_link_info *);
|
||||||
|
extern asection * _bfd_elf_create_ifunc_dyn_reloc
|
||||||
|
(bfd *, struct bfd_link_info *, asection *sec, asection *sreloc,
|
||||||
|
struct elf_dyn_relocs **);
|
||||||
|
extern bfd_boolean _bfd_elf_allocate_ifunc_dyn_relocs
|
||||||
|
(struct bfd_link_info *, struct elf_link_hash_entry *,
|
||||||
|
struct elf_dyn_relocs **, unsigned int, unsigned int);
|
||||||
|
|
||||||
/* Large common section. */
|
/* Large common section. */
|
||||||
extern asection _bfd_elf_large_com_section;
|
extern asection _bfd_elf_large_com_section;
|
||||||
|
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;
|
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;
|
||||||
|
}
|
||||||
|
203
bfd/elf32-i386.c
203
bfd/elf32-i386.c
@ -577,26 +577,6 @@ static const bfd_byte elf_i386_pic_plt_entry[PLT_ENTRY_SIZE] =
|
|||||||
#define PLTRESOLVE_RELOCS 2
|
#define PLTRESOLVE_RELOCS 2
|
||||||
#define PLT_NON_JUMP_SLOT_RELOCS 2
|
#define PLT_NON_JUMP_SLOT_RELOCS 2
|
||||||
|
|
||||||
/* The i386 linker needs to keep track of the number of relocs that it
|
|
||||||
decides to copy as dynamic relocs in check_relocs for each symbol.
|
|
||||||
This is so that it can later discard them if they are found to be
|
|
||||||
unnecessary. We store the information in a field extending the
|
|
||||||
regular ELF linker hash table. */
|
|
||||||
|
|
||||||
struct elf_i386_dyn_relocs
|
|
||||||
{
|
|
||||||
struct elf_i386_dyn_relocs *next;
|
|
||||||
|
|
||||||
/* The input section of the reloc. */
|
|
||||||
asection *sec;
|
|
||||||
|
|
||||||
/* Total number of relocs copied for the input section. */
|
|
||||||
bfd_size_type count;
|
|
||||||
|
|
||||||
/* Number of pc-relative relocs copied for the input section. */
|
|
||||||
bfd_size_type pc_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* i386 ELF linker hash entry. */
|
/* i386 ELF linker hash entry. */
|
||||||
|
|
||||||
struct elf_i386_link_hash_entry
|
struct elf_i386_link_hash_entry
|
||||||
@ -604,7 +584,7 @@ struct elf_i386_link_hash_entry
|
|||||||
struct elf_link_hash_entry elf;
|
struct elf_link_hash_entry elf;
|
||||||
|
|
||||||
/* Track dynamic relocs copied for this symbol. */
|
/* Track dynamic relocs copied for this symbol. */
|
||||||
struct elf_i386_dyn_relocs *dyn_relocs;
|
struct elf_dyn_relocs *dyn_relocs;
|
||||||
|
|
||||||
#define GOT_UNKNOWN 0
|
#define GOT_UNKNOWN 0
|
||||||
#define GOT_NORMAL 1
|
#define GOT_NORMAL 1
|
||||||
@ -919,14 +899,14 @@ elf_i386_copy_indirect_symbol (struct bfd_link_info *info,
|
|||||||
{
|
{
|
||||||
if (edir->dyn_relocs != NULL)
|
if (edir->dyn_relocs != NULL)
|
||||||
{
|
{
|
||||||
struct elf_i386_dyn_relocs **pp;
|
struct elf_dyn_relocs **pp;
|
||||||
struct elf_i386_dyn_relocs *p;
|
struct elf_dyn_relocs *p;
|
||||||
|
|
||||||
/* Add reloc counts against the indirect sym to the direct sym
|
/* Add reloc counts against the indirect sym to the direct sym
|
||||||
list. Merge any entries against the same section. */
|
list. Merge any entries against the same section. */
|
||||||
for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
|
for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
|
||||||
{
|
{
|
||||||
struct elf_i386_dyn_relocs *q;
|
struct elf_dyn_relocs *q;
|
||||||
|
|
||||||
for (q = edir->dyn_relocs; q != NULL; q = q->next)
|
for (q = edir->dyn_relocs; q != NULL; q = q->next)
|
||||||
if (q->sec == p->sec)
|
if (q->sec == p->sec)
|
||||||
@ -1407,40 +1387,15 @@ elf_i386_check_relocs (bfd *abfd,
|
|||||||
h->pointer_equality_needed = 1;
|
h->pointer_equality_needed = 1;
|
||||||
if (info->shared)
|
if (info->shared)
|
||||||
{
|
{
|
||||||
struct elf_i386_dyn_relocs *p;
|
|
||||||
struct elf_i386_dyn_relocs **head;
|
|
||||||
|
|
||||||
/* We must copy these reloc types into the
|
/* We must copy these reloc types into the
|
||||||
output file. Create a reloc section in
|
output file. Create a reloc section in
|
||||||
dynobj and make room for this reloc. */
|
dynobj and make room for this reloc. */
|
||||||
if (sreloc == NULL)
|
sreloc = _bfd_elf_create_ifunc_dyn_reloc
|
||||||
{
|
(abfd, info, sec, sreloc,
|
||||||
if (htab->elf.dynobj == NULL)
|
&((struct elf_i386_link_hash_entry *) h)->dyn_relocs);
|
||||||
htab->elf.dynobj = abfd;
|
|
||||||
|
|
||||||
sreloc = _bfd_elf_make_dynamic_reloc_section
|
|
||||||
(sec, htab->elf.dynobj, 2, abfd, FALSE);
|
|
||||||
|
|
||||||
if (sreloc == NULL)
|
if (sreloc == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
head = &((struct elf_i386_link_hash_entry *) h)->dyn_relocs;
|
|
||||||
p = *head;
|
|
||||||
if (p == NULL || p->sec != sec)
|
|
||||||
{
|
|
||||||
bfd_size_type amt = sizeof *p;
|
|
||||||
p = bfd_alloc (htab->elf.dynobj, amt);
|
|
||||||
if (p == NULL)
|
|
||||||
return FALSE;
|
|
||||||
p->next = *head;
|
|
||||||
*head = p;
|
|
||||||
p->sec = sec;
|
|
||||||
p->count = 0;
|
|
||||||
p->pc_count = 0;
|
|
||||||
}
|
|
||||||
p->count += 1;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R_386_PC32:
|
case R_386_PC32:
|
||||||
@ -1669,8 +1624,8 @@ elf_i386_check_relocs (bfd *abfd,
|
|||||||
&& (h->root.type == bfd_link_hash_defweak
|
&& (h->root.type == bfd_link_hash_defweak
|
||||||
|| !h->def_regular)))
|
|| !h->def_regular)))
|
||||||
{
|
{
|
||||||
struct elf_i386_dyn_relocs *p;
|
struct elf_dyn_relocs *p;
|
||||||
struct elf_i386_dyn_relocs **head;
|
struct elf_dyn_relocs **head;
|
||||||
|
|
||||||
/* We must copy these reloc types into the output file.
|
/* We must copy these reloc types into the output file.
|
||||||
Create a reloc section in dynobj and make room for
|
Create a reloc section in dynobj and make room for
|
||||||
@ -1707,7 +1662,7 @@ elf_i386_check_relocs (bfd *abfd,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
vpp = &elf_section_data (s)->local_dynrel;
|
vpp = &elf_section_data (s)->local_dynrel;
|
||||||
head = (struct elf_i386_dyn_relocs **)vpp;
|
head = (struct elf_dyn_relocs **)vpp;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = *head;
|
p = *head;
|
||||||
@ -1808,8 +1763,8 @@ elf_i386_gc_sweep_hook (bfd *abfd,
|
|||||||
if (r_symndx >= symtab_hdr->sh_info)
|
if (r_symndx >= symtab_hdr->sh_info)
|
||||||
{
|
{
|
||||||
struct elf_i386_link_hash_entry *eh;
|
struct elf_i386_link_hash_entry *eh;
|
||||||
struct elf_i386_dyn_relocs **pp;
|
struct elf_dyn_relocs **pp;
|
||||||
struct elf_i386_dyn_relocs *p;
|
struct elf_dyn_relocs *p;
|
||||||
|
|
||||||
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
|
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
|
||||||
while (h->root.type == bfd_link_hash_indirect
|
while (h->root.type == bfd_link_hash_indirect
|
||||||
@ -1980,7 +1935,7 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info,
|
|||||||
if (ELIMINATE_COPY_RELOCS && !htab->is_vxworks)
|
if (ELIMINATE_COPY_RELOCS && !htab->is_vxworks)
|
||||||
{
|
{
|
||||||
struct elf_i386_link_hash_entry * eh;
|
struct elf_i386_link_hash_entry * eh;
|
||||||
struct elf_i386_dyn_relocs *p;
|
struct elf_dyn_relocs *p;
|
||||||
|
|
||||||
eh = (struct elf_i386_link_hash_entry *) h;
|
eh = (struct elf_i386_link_hash_entry *) h;
|
||||||
for (p = eh->dyn_relocs; p != NULL; p = p->next)
|
for (p = eh->dyn_relocs; p != NULL; p = p->next)
|
||||||
@ -2037,7 +1992,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
|||||||
struct bfd_link_info *info;
|
struct bfd_link_info *info;
|
||||||
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_dyn_relocs *p;
|
||||||
|
|
||||||
if (h->root.type == bfd_link_hash_indirect)
|
if (h->root.type == bfd_link_hash_indirect)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@ -2056,123 +2011,9 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
|||||||
here if it is defined and referenced in a non-shared object. */
|
here if it is defined and referenced in a non-shared object. */
|
||||||
if (h->type == STT_GNU_IFUNC
|
if (h->type == STT_GNU_IFUNC
|
||||||
&& h->def_regular)
|
&& h->def_regular)
|
||||||
{
|
return _bfd_elf_allocate_ifunc_dyn_relocs (info, h,
|
||||||
asection *plt, *gotplt, *relplt;
|
&eh->dyn_relocs,
|
||||||
|
PLT_ENTRY_SIZE, 4);
|
||||||
/* 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;
|
|
||||||
eh->dyn_relocs = NULL;
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* When building a static executable, use .iplt, .igot.plt and
|
|
||||||
.rel.iplt sections for STT_GNU_IFUNC symbols. */
|
|
||||||
if (htab->elf.splt != NULL)
|
|
||||||
{
|
|
||||||
plt = htab->elf.splt;
|
|
||||||
gotplt = htab->elf.sgotplt;
|
|
||||||
relplt = htab->elf.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->elf.iplt;
|
|
||||||
gotplt = htab->elf.igotplt;
|
|
||||||
relplt = htab->elf.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++;
|
|
||||||
|
|
||||||
/* 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)
|
|
||||||
eh->dyn_relocs = NULL;
|
|
||||||
|
|
||||||
/* Finally, allocate space. */
|
|
||||||
for (p = eh->dyn_relocs; p != NULL; p = p->next)
|
|
||||||
htab->elf.irelifunc->size += p->count * sizeof (Elf32_External_Rel);
|
|
||||||
|
|
||||||
/* 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->elf.sgot == NULL)
|
|
||||||
{
|
|
||||||
/* Use .got.plt. */
|
|
||||||
h->got.offset = (bfd_vma) -1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
h->got.offset = htab->elf.sgot->size;
|
|
||||||
htab->elf.sgot->size += 4;
|
|
||||||
if (info->shared)
|
|
||||||
htab->elf.srelgot->size += sizeof (Elf32_External_Rel);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
else if (htab->elf.dynamic_sections_created
|
else if (htab->elf.dynamic_sections_created
|
||||||
&& h->plt.refcount > 0)
|
&& h->plt.refcount > 0)
|
||||||
{
|
{
|
||||||
@ -2337,7 +2178,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
|||||||
should avoid writing assembly like ".long foo - .". */
|
should avoid writing assembly like ".long foo - .". */
|
||||||
if (SYMBOL_CALLS_LOCAL (info, h))
|
if (SYMBOL_CALLS_LOCAL (info, h))
|
||||||
{
|
{
|
||||||
struct elf_i386_dyn_relocs **pp;
|
struct elf_dyn_relocs **pp;
|
||||||
|
|
||||||
for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
|
for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
|
||||||
{
|
{
|
||||||
@ -2352,7 +2193,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
|||||||
|
|
||||||
if (htab->is_vxworks)
|
if (htab->is_vxworks)
|
||||||
{
|
{
|
||||||
struct elf_i386_dyn_relocs **pp;
|
struct elf_dyn_relocs **pp;
|
||||||
for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
|
for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
|
||||||
{
|
{
|
||||||
if (strcmp (p->sec->output_section->name, ".tls_vars") == 0)
|
if (strcmp (p->sec->output_section->name, ".tls_vars") == 0)
|
||||||
@ -2452,7 +2293,7 @@ static bfd_boolean
|
|||||||
elf_i386_readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
elf_i386_readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||||
{
|
{
|
||||||
struct elf_i386_link_hash_entry *eh;
|
struct elf_i386_link_hash_entry *eh;
|
||||||
struct elf_i386_dyn_relocs *p;
|
struct elf_dyn_relocs *p;
|
||||||
|
|
||||||
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;
|
||||||
@ -2522,9 +2363,9 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
|
|||||||
|
|
||||||
for (s = ibfd->sections; s != NULL; s = s->next)
|
for (s = ibfd->sections; s != NULL; s = s->next)
|
||||||
{
|
{
|
||||||
struct elf_i386_dyn_relocs *p;
|
struct elf_dyn_relocs *p;
|
||||||
|
|
||||||
for (p = ((struct elf_i386_dyn_relocs *)
|
for (p = ((struct elf_dyn_relocs *)
|
||||||
elf_section_data (s)->local_dynrel);
|
elf_section_data (s)->local_dynrel);
|
||||||
p != NULL;
|
p != NULL;
|
||||||
p = p->next)
|
p = p->next)
|
||||||
|
@ -396,27 +396,6 @@ static const bfd_byte elf64_x86_64_plt_entry[PLT_ENTRY_SIZE] =
|
|||||||
0, 0, 0, 0 /* replaced with offset to start of .plt0. */
|
0, 0, 0, 0 /* replaced with offset to start of .plt0. */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The x86-64 linker needs to keep track of the number of relocs that
|
|
||||||
it decides to copy as dynamic relocs in check_relocs for each symbol.
|
|
||||||
This is so that it can later discard them if they are found to be
|
|
||||||
unnecessary. We store the information in a field extending the
|
|
||||||
regular ELF linker hash table. */
|
|
||||||
|
|
||||||
struct elf64_x86_64_dyn_relocs
|
|
||||||
{
|
|
||||||
/* Next section. */
|
|
||||||
struct elf64_x86_64_dyn_relocs *next;
|
|
||||||
|
|
||||||
/* The input section of the reloc. */
|
|
||||||
asection *sec;
|
|
||||||
|
|
||||||
/* Total number of relocs copied for the input section. */
|
|
||||||
bfd_size_type count;
|
|
||||||
|
|
||||||
/* Number of pc-relative relocs copied for the input section. */
|
|
||||||
bfd_size_type pc_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* x86-64 ELF linker hash entry. */
|
/* x86-64 ELF linker hash entry. */
|
||||||
|
|
||||||
struct elf64_x86_64_link_hash_entry
|
struct elf64_x86_64_link_hash_entry
|
||||||
@ -424,7 +403,7 @@ struct elf64_x86_64_link_hash_entry
|
|||||||
struct elf_link_hash_entry elf;
|
struct elf_link_hash_entry elf;
|
||||||
|
|
||||||
/* Track dynamic relocs copied for this symbol. */
|
/* Track dynamic relocs copied for this symbol. */
|
||||||
struct elf64_x86_64_dyn_relocs *dyn_relocs;
|
struct elf_dyn_relocs *dyn_relocs;
|
||||||
|
|
||||||
#define GOT_UNKNOWN 0
|
#define GOT_UNKNOWN 0
|
||||||
#define GOT_NORMAL 1
|
#define GOT_NORMAL 1
|
||||||
@ -726,14 +705,14 @@ elf64_x86_64_copy_indirect_symbol (struct bfd_link_info *info,
|
|||||||
{
|
{
|
||||||
if (edir->dyn_relocs != NULL)
|
if (edir->dyn_relocs != NULL)
|
||||||
{
|
{
|
||||||
struct elf64_x86_64_dyn_relocs **pp;
|
struct elf_dyn_relocs **pp;
|
||||||
struct elf64_x86_64_dyn_relocs *p;
|
struct elf_dyn_relocs *p;
|
||||||
|
|
||||||
/* Add reloc counts against the indirect sym to the direct sym
|
/* Add reloc counts against the indirect sym to the direct sym
|
||||||
list. Merge any entries against the same section. */
|
list. Merge any entries against the same section. */
|
||||||
for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
|
for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
|
||||||
{
|
{
|
||||||
struct elf64_x86_64_dyn_relocs *q;
|
struct elf_dyn_relocs *q;
|
||||||
|
|
||||||
for (q = edir->dyn_relocs; q != NULL; q = q->next)
|
for (q = edir->dyn_relocs; q != NULL; q = q->next)
|
||||||
if (q->sec == p->sec)
|
if (q->sec == p->sec)
|
||||||
@ -1192,42 +1171,15 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||||||
h->pointer_equality_needed = 1;
|
h->pointer_equality_needed = 1;
|
||||||
if (info->shared)
|
if (info->shared)
|
||||||
{
|
{
|
||||||
struct elf64_x86_64_dyn_relocs *p;
|
|
||||||
struct elf64_x86_64_dyn_relocs **head;
|
|
||||||
|
|
||||||
/* We must copy these reloc types into the output
|
/* We must copy these reloc types into the output
|
||||||
file. Create a reloc section in dynobj and
|
file. Create a reloc section in dynobj and
|
||||||
make room for this reloc. */
|
make room for this reloc. */
|
||||||
if (sreloc == NULL)
|
sreloc = _bfd_elf_create_ifunc_dyn_reloc
|
||||||
{
|
(abfd, info, sec, sreloc,
|
||||||
if (htab->elf.dynobj == NULL)
|
&((struct elf64_x86_64_link_hash_entry *) h)->dyn_relocs);
|
||||||
htab->elf.dynobj = abfd;
|
|
||||||
|
|
||||||
sreloc = _bfd_elf_make_dynamic_reloc_section
|
|
||||||
(sec, htab->elf.dynobj, 3, abfd, TRUE);
|
|
||||||
|
|
||||||
if (sreloc == NULL)
|
if (sreloc == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
head = &((struct elf64_x86_64_link_hash_entry *) h)->dyn_relocs;
|
|
||||||
p = *head;
|
|
||||||
if (p == NULL || p->sec != sec)
|
|
||||||
{
|
|
||||||
bfd_size_type amt = sizeof *p;
|
|
||||||
|
|
||||||
p = ((struct elf64_x86_64_dyn_relocs *)
|
|
||||||
bfd_alloc (htab->elf.dynobj, amt));
|
|
||||||
if (p == NULL)
|
|
||||||
return FALSE;
|
|
||||||
p->next = *head;
|
|
||||||
*head = p;
|
|
||||||
p->sec = sec;
|
|
||||||
p->count = 0;
|
|
||||||
p->pc_count = 0;
|
|
||||||
}
|
|
||||||
p->count += 1;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R_X86_64_32S:
|
case R_X86_64_32S:
|
||||||
@ -1500,8 +1452,8 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||||||
&& (h->root.type == bfd_link_hash_defweak
|
&& (h->root.type == bfd_link_hash_defweak
|
||||||
|| !h->def_regular)))
|
|| !h->def_regular)))
|
||||||
{
|
{
|
||||||
struct elf64_x86_64_dyn_relocs *p;
|
struct elf_dyn_relocs *p;
|
||||||
struct elf64_x86_64_dyn_relocs **head;
|
struct elf_dyn_relocs **head;
|
||||||
|
|
||||||
/* We must copy these reloc types into the output file.
|
/* We must copy these reloc types into the output file.
|
||||||
Create a reloc section in dynobj and make room for
|
Create a reloc section in dynobj and make room for
|
||||||
@ -1540,7 +1492,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||||||
/* Beware of type punned pointers vs strict aliasing
|
/* Beware of type punned pointers vs strict aliasing
|
||||||
rules. */
|
rules. */
|
||||||
vpp = &(elf_section_data (s)->local_dynrel);
|
vpp = &(elf_section_data (s)->local_dynrel);
|
||||||
head = (struct elf64_x86_64_dyn_relocs **)vpp;
|
head = (struct elf_dyn_relocs **)vpp;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = *head;
|
p = *head;
|
||||||
@ -1548,7 +1500,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||||||
{
|
{
|
||||||
bfd_size_type amt = sizeof *p;
|
bfd_size_type amt = sizeof *p;
|
||||||
|
|
||||||
p = ((struct elf64_x86_64_dyn_relocs *)
|
p = ((struct elf_dyn_relocs *)
|
||||||
bfd_alloc (htab->elf.dynobj, amt));
|
bfd_alloc (htab->elf.dynobj, amt));
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -1642,8 +1594,8 @@ elf64_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
|
|||||||
if (r_symndx >= symtab_hdr->sh_info)
|
if (r_symndx >= symtab_hdr->sh_info)
|
||||||
{
|
{
|
||||||
struct elf64_x86_64_link_hash_entry *eh;
|
struct elf64_x86_64_link_hash_entry *eh;
|
||||||
struct elf64_x86_64_dyn_relocs **pp;
|
struct elf_dyn_relocs **pp;
|
||||||
struct elf64_x86_64_dyn_relocs *p;
|
struct elf_dyn_relocs *p;
|
||||||
|
|
||||||
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
|
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
|
||||||
while (h->root.type == bfd_link_hash_indirect
|
while (h->root.type == bfd_link_hash_indirect
|
||||||
@ -1820,7 +1772,7 @@ elf64_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
|
|||||||
if (ELIMINATE_COPY_RELOCS)
|
if (ELIMINATE_COPY_RELOCS)
|
||||||
{
|
{
|
||||||
struct elf64_x86_64_link_hash_entry * eh;
|
struct elf64_x86_64_link_hash_entry * eh;
|
||||||
struct elf64_x86_64_dyn_relocs *p;
|
struct elf_dyn_relocs *p;
|
||||||
|
|
||||||
eh = (struct elf64_x86_64_link_hash_entry *) h;
|
eh = (struct elf64_x86_64_link_hash_entry *) h;
|
||||||
for (p = eh->dyn_relocs; p != NULL; p = p->next)
|
for (p = eh->dyn_relocs; p != NULL; p = p->next)
|
||||||
@ -1881,7 +1833,7 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
|
|||||||
struct bfd_link_info *info;
|
struct bfd_link_info *info;
|
||||||
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 elf_dyn_relocs *p;
|
||||||
|
|
||||||
if (h->root.type == bfd_link_hash_indirect)
|
if (h->root.type == bfd_link_hash_indirect)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@ -1897,124 +1849,10 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
|
|||||||
here if it is defined and referenced in a non-shared object. */
|
here if it is defined and referenced in a non-shared object. */
|
||||||
if (h->type == STT_GNU_IFUNC
|
if (h->type == STT_GNU_IFUNC
|
||||||
&& h->def_regular)
|
&& h->def_regular)
|
||||||
{
|
return _bfd_elf_allocate_ifunc_dyn_relocs (info, h,
|
||||||
asection *plt, *gotplt, *relplt;
|
&eh->dyn_relocs,
|
||||||
|
PLT_ENTRY_SIZE,
|
||||||
/* When a shared library references a STT_GNU_IFUNC symbol
|
GOT_ENTRY_SIZE);
|
||||||
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;
|
|
||||||
eh->dyn_relocs = NULL;
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* When building a static executable, use .iplt, .igot.plt and
|
|
||||||
.rela.iplt sections for STT_GNU_IFUNC symbols. */
|
|
||||||
if (htab->elf.splt != NULL)
|
|
||||||
{
|
|
||||||
plt = htab->elf.splt;
|
|
||||||
gotplt = htab->elf.sgotplt;
|
|
||||||
relplt = htab->elf.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->elf.iplt;
|
|
||||||
gotplt = htab->elf.igotplt;
|
|
||||||
relplt = htab->elf.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++;
|
|
||||||
|
|
||||||
/* 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)
|
|
||||||
eh->dyn_relocs = NULL;
|
|
||||||
|
|
||||||
/* Finally, allocate space. */
|
|
||||||
for (p = eh->dyn_relocs; p != NULL; p = p->next)
|
|
||||||
htab->elf.irelifunc->size
|
|
||||||
+= p->count * sizeof (Elf64_External_Rela);
|
|
||||||
|
|
||||||
/* 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->elf.sgot == NULL)
|
|
||||||
{
|
|
||||||
/* Use .got.plt. */
|
|
||||||
h->got.offset = (bfd_vma) -1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
h->got.offset = htab->elf.sgot->size;
|
|
||||||
htab->elf.sgot->size += GOT_ENTRY_SIZE;
|
|
||||||
if (info->shared)
|
|
||||||
htab->elf.srelgot->size += sizeof (Elf64_External_Rela);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
else if (htab->elf.dynamic_sections_created
|
else if (htab->elf.dynamic_sections_created
|
||||||
&& h->plt.refcount > 0)
|
&& h->plt.refcount > 0)
|
||||||
{
|
{
|
||||||
@ -2159,7 +1997,7 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
|
|||||||
should avoid writing weird assembly. */
|
should avoid writing weird assembly. */
|
||||||
if (SYMBOL_CALLS_LOCAL (info, h))
|
if (SYMBOL_CALLS_LOCAL (info, h))
|
||||||
{
|
{
|
||||||
struct elf64_x86_64_dyn_relocs **pp;
|
struct elf_dyn_relocs **pp;
|
||||||
|
|
||||||
for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
|
for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
|
||||||
{
|
{
|
||||||
@ -2260,7 +2098,7 @@ static bfd_boolean
|
|||||||
elf64_x86_64_readonly_dynrelocs (struct elf_link_hash_entry *h, void * inf)
|
elf64_x86_64_readonly_dynrelocs (struct elf_link_hash_entry *h, void * inf)
|
||||||
{
|
{
|
||||||
struct elf64_x86_64_link_hash_entry *eh;
|
struct elf64_x86_64_link_hash_entry *eh;
|
||||||
struct elf64_x86_64_dyn_relocs *p;
|
struct elf_dyn_relocs *p;
|
||||||
|
|
||||||
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;
|
||||||
@ -2330,9 +2168,9 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
|
|||||||
|
|
||||||
for (s = ibfd->sections; s != NULL; s = s->next)
|
for (s = ibfd->sections; s != NULL; s = s->next)
|
||||||
{
|
{
|
||||||
struct elf64_x86_64_dyn_relocs *p;
|
struct elf_dyn_relocs *p;
|
||||||
|
|
||||||
for (p = (struct elf64_x86_64_dyn_relocs *)
|
for (p = (struct elf_dyn_relocs *)
|
||||||
(elf_section_data (s)->local_dynrel);
|
(elf_section_data (s)->local_dynrel);
|
||||||
p != NULL;
|
p != NULL;
|
||||||
p = p->next)
|
p = p->next)
|
||||||
|
Reference in New Issue
Block a user