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:
H.J. Lu 2009-06-18 00:45:14 +00:00
parent d9942914aa
commit e03a8ed803
5 changed files with 294 additions and 368 deletions

View file

@ -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>
* elf32-arm.c (create_got_section): Get existing .rela.got

View file

@ -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;

View file

@ -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;
}

View file

@ -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)

View file

@ -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)