* 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>
+
+ * 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
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;
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;
+}
#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
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
{
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)
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;
&& (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
return FALSE;
vpp = &elf_section_data (s)->local_dynrel;
- head = (struct elf_i386_dyn_relocs **)vpp;
+ head = (struct elf_dyn_relocs **)vpp;
}
p = *head;
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
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)
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;
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)
{
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; )
{
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)
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;
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)
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
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
{
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)
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;
&& (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
/* 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;
{
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;
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
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)
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;
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)
{
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; )
{
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;
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)