aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2009-06-18 00:45:14 +0000
committerH.J. Lu <hjl.tools@gmail.com>2009-06-18 00:45:14 +0000
commite03a8ed8034fdfbbf7f73ae2fbf7fe29b60c6c5a (patch)
tree52ecfdadd8cf4b12ebcc096e90c46293da4a6fd1
parentd9942914aa3db149a6c835cdd3e88917ffe47835 (diff)
downloadfsf-binutils-gdb-e03a8ed8034fdfbbf7f73ae2fbf7fe29b60c6c5a.zip
fsf-binutils-gdb-e03a8ed8034fdfbbf7f73ae2fbf7fe29b60c6c5a.tar.gz
fsf-binutils-gdb-e03a8ed8034fdfbbf7f73ae2fbf7fe29b60c6c5a.tar.bz2
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.
-rw-r--r--bfd/ChangeLog39
-rw-r--r--bfd/elf-bfd.h26
-rw-r--r--bfd/elf-ifunc.c182
-rw-r--r--bfd/elf32-i386.c205
-rw-r--r--bfd/elf64-x86-64.c210
5 files changed, 294 insertions, 368 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 15e73e9..6458ccf 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,5 +1,44 @@
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>
+
* elf32-arm.c (create_got_section): Get existing .rela.got
section.
* elf32-hppa.c (elf32_hppa_create_dynamic_sections): Likewise.
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index b81f009..d1a23ad 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -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 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
(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. */
extern asection _bfd_elf_large_com_section;
diff --git a/bfd/elf-ifunc.c b/bfd/elf-ifunc.c
index 4bfc31b..b9b50c3 100644
--- a/bfd/elf-ifunc.c
+++ b/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;
+}
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index 60a4142..32ea287 100644
--- a/bfd/elf32-i386.c
+++ b/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 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. */
struct elf_i386_link_hash_entry
@@ -604,7 +584,7 @@ struct elf_i386_link_hash_entry
struct elf_link_hash_entry elf;
/* 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_NORMAL 1
@@ -919,14 +899,14 @@ elf_i386_copy_indirect_symbol (struct bfd_link_info *info,
{
if (edir->dyn_relocs != NULL)
{
- struct elf_i386_dyn_relocs **pp;
- struct elf_i386_dyn_relocs *p;
+ struct elf_dyn_relocs **pp;
+ struct elf_dyn_relocs *p;
/* Add reloc counts against the indirect sym to the direct sym
list. Merge any entries against the same section. */
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)
if (q->sec == p->sec)
@@ -1407,39 +1387,14 @@ elf_i386_check_relocs (bfd *abfd,
h->pointer_equality_needed = 1;
if (info->shared)
{
- struct elf_i386_dyn_relocs *p;
- struct elf_i386_dyn_relocs **head;
-
/* We must copy these reloc types into the
output file. Create a reloc section in
dynobj and make room for this reloc. */
+ sreloc = _bfd_elf_create_ifunc_dyn_reloc
+ (abfd, info, sec, sreloc,
+ &((struct elf_i386_link_hash_entry *) h)->dyn_relocs);
if (sreloc == NULL)
- {
- if (htab->elf.dynobj == NULL)
- htab->elf.dynobj = abfd;
-
- sreloc = _bfd_elf_make_dynamic_reloc_section
- (sec, htab->elf.dynobj, 2, abfd, FALSE);
-
- if (sreloc == NULL)
- 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;
+ return FALSE;
}
break;
@@ -1669,8 +1624,8 @@ elf_i386_check_relocs (bfd *abfd,
&& (h->root.type == bfd_link_hash_defweak
|| !h->def_regular)))
{
- struct elf_i386_dyn_relocs *p;
- struct elf_i386_dyn_relocs **head;
+ struct elf_dyn_relocs *p;
+ struct elf_dyn_relocs **head;
/* We must copy these reloc types into the output file.
Create a reloc section in dynobj and make room for
@@ -1707,7 +1662,7 @@ elf_i386_check_relocs (bfd *abfd,
return FALSE;
vpp = &elf_section_data (s)->local_dynrel;
- head = (struct elf_i386_dyn_relocs **)vpp;
+ head = (struct elf_dyn_relocs **)vpp;
}
p = *head;
@@ -1808,8 +1763,8 @@ elf_i386_gc_sweep_hook (bfd *abfd,
if (r_symndx >= symtab_hdr->sh_info)
{
struct elf_i386_link_hash_entry *eh;
- struct elf_i386_dyn_relocs **pp;
- struct elf_i386_dyn_relocs *p;
+ struct elf_dyn_relocs **pp;
+ struct elf_dyn_relocs *p;
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
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)
{
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;
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 elf_i386_link_hash_table *htab;
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)
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. */
if (h->type == STT_GNU_IFUNC
&& h->def_regular)
- {
- asection *plt, *gotplt, *relplt;
-
- /* 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;
- }
+ return _bfd_elf_allocate_ifunc_dyn_relocs (info, h,
+ &eh->dyn_relocs,
+ PLT_ENTRY_SIZE, 4);
else if (htab->elf.dynamic_sections_created
&& 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 - .". */
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; )
{
@@ -2352,7 +2193,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
if (htab->is_vxworks)
{
- struct elf_i386_dyn_relocs **pp;
+ struct elf_dyn_relocs **pp;
for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
{
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)
{
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)
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)
{
- 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);
p != NULL;
p = p->next)
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 5947a3e..617832a 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -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. */
};
-/* 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. */
struct elf64_x86_64_link_hash_entry
@@ -424,7 +403,7 @@ struct elf64_x86_64_link_hash_entry
struct elf_link_hash_entry elf;
/* 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_NORMAL 1
@@ -726,14 +705,14 @@ elf64_x86_64_copy_indirect_symbol (struct bfd_link_info *info,
{
if (edir->dyn_relocs != NULL)
{
- struct elf64_x86_64_dyn_relocs **pp;
- struct elf64_x86_64_dyn_relocs *p;
+ struct elf_dyn_relocs **pp;
+ struct elf_dyn_relocs *p;
/* Add reloc counts against the indirect sym to the direct sym
list. Merge any entries against the same section. */
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)
if (q->sec == p->sec)
@@ -1192,41 +1171,14 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
h->pointer_equality_needed = 1;
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
file. Create a reloc section in dynobj and
make room for this reloc. */
+ sreloc = _bfd_elf_create_ifunc_dyn_reloc
+ (abfd, info, sec, sreloc,
+ &((struct elf64_x86_64_link_hash_entry *) h)->dyn_relocs);
if (sreloc == NULL)
- {
- if (htab->elf.dynobj == NULL)
- htab->elf.dynobj = abfd;
-
- sreloc = _bfd_elf_make_dynamic_reloc_section
- (sec, htab->elf.dynobj, 3, abfd, TRUE);
-
- if (sreloc == NULL)
- 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;
+ return FALSE;
}
break;
@@ -1500,8 +1452,8 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
&& (h->root.type == bfd_link_hash_defweak
|| !h->def_regular)))
{
- struct elf64_x86_64_dyn_relocs *p;
- struct elf64_x86_64_dyn_relocs **head;
+ struct elf_dyn_relocs *p;
+ struct elf_dyn_relocs **head;
/* We must copy these reloc types into the output file.
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
rules. */
vpp = &(elf_section_data (s)->local_dynrel);
- head = (struct elf64_x86_64_dyn_relocs **)vpp;
+ head = (struct elf_dyn_relocs **)vpp;
}
p = *head;
@@ -1548,7 +1500,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
{
bfd_size_type amt = sizeof *p;
- p = ((struct elf64_x86_64_dyn_relocs *)
+ p = ((struct elf_dyn_relocs *)
bfd_alloc (htab->elf.dynobj, amt));
if (p == NULL)
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)
{
struct elf64_x86_64_link_hash_entry *eh;
- struct elf64_x86_64_dyn_relocs **pp;
- struct elf64_x86_64_dyn_relocs *p;
+ struct elf_dyn_relocs **pp;
+ struct elf_dyn_relocs *p;
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
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)
{
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;
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 elf64_x86_64_link_hash_table *htab;
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)
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. */
if (h->type == STT_GNU_IFUNC
&& h->def_regular)
- {
- asection *plt, *gotplt, *relplt;
-
- /* 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
- .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;
- }
+ return _bfd_elf_allocate_ifunc_dyn_relocs (info, h,
+ &eh->dyn_relocs,
+ PLT_ENTRY_SIZE,
+ GOT_ENTRY_SIZE);
else if (htab->elf.dynamic_sections_created
&& 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. */
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; )
{
@@ -2260,7 +2098,7 @@ static bfd_boolean
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_dyn_relocs *p;
+ struct elf_dyn_relocs *p;
if (h->root.type == bfd_link_hash_warning)
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)
{
- 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);
p != NULL;
p = p->next)