aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf64-x86-64.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/elf64-x86-64.c')
-rw-r--r--bfd/elf64-x86-64.c69
1 files changed, 57 insertions, 12 deletions
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 7eecb22..1ea033b 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -974,6 +974,26 @@ elf64_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
return TRUE;
}
+/* Returns true if the hash entry refers to a symbol
+ marked for indirect handling during reloc processing. */
+
+static bfd_boolean
+is_indirect_symbol (bfd * abfd, struct elf_link_hash_entry * h)
+{
+ const struct elf_backend_data * bed;
+
+ if (abfd == NULL || h == NULL)
+ return FALSE;
+
+ bed = get_elf_backend_data (abfd);
+
+ return h->type == STT_IFUNC
+ && bed != NULL
+ && (bed->elf_osabi == ELFOSABI_LINUX
+ /* GNU/Linux is still using the default value 0. */
+ || bed->elf_osabi == ELFOSABI_NONE);
+}
+
/* Look through the relocs for a section during the first phase, and
calculate needed space in the global offset table, procedure
linkage table, and dynamic reloc sections. */
@@ -1255,7 +1275,10 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
If on the other hand, we are creating an executable, we
may need to keep relocations for symbols satisfied by a
dynamic library if we manage to avoid copy relocs for the
- symbol. */
+ symbol.
+
+ Also we must keep any relocations against IFUNC symbols as
+ they will be evaluated at load time. */
if ((info->shared
&& (sec->flags & SEC_ALLOC) != 0
&& (((r_type != R_X86_64_PC8)
@@ -1271,7 +1294,8 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
&& (sec->flags & SEC_ALLOC) != 0
&& h != NULL
&& (h->root.type == bfd_link_hash_defweak
- || !h->def_regular)))
+ || !h->def_regular))
+ || is_indirect_symbol (abfd, h))
{
struct elf64_x86_64_dyn_relocs *p;
struct elf64_x86_64_dyn_relocs **head;
@@ -1291,6 +1315,9 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
return FALSE;
}
+ if (is_indirect_symbol (abfd, h))
+ (void) _bfd_elf_make_ifunc_reloc_section (abfd, sec, htab->elf.dynobj, 2);
+
/* If this is a global symbol, we count the number of
relocations we need for this symbol. */
if (h != NULL)
@@ -1830,6 +1857,13 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
}
}
}
+ else if (is_indirect_symbol (info->output_bfd, h))
+ {
+ if (h->dynindx == -1
+ && ! h->forced_local
+ && ! bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+ }
else if (ELIMINATE_COPY_RELOCS)
{
/* For the non-shared case, discard space for relocs against
@@ -1866,7 +1900,16 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
/* Finally, allocate space. */
for (p = eh->dyn_relocs; p != NULL; p = p->next)
{
- asection *sreloc = elf_section_data (p->sec)->sreloc;
+ asection * sreloc;
+
+ if (! info->shared
+ && is_indirect_symbol (info->output_bfd, h))
+ sreloc = elf_section_data (p->sec)->indirect_relocs;
+ else
+ sreloc = elf_section_data (p->sec)->sreloc;
+
+ BFD_ASSERT (sreloc != NULL);
+
sreloc->size += p->count * sizeof (Elf64_External_Rela);
}
@@ -1970,7 +2013,6 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
srel->size += p->count * sizeof (Elf64_External_Rela);
if ((p->sec->output_section->flags & SEC_READONLY) != 0)
info->flags |= DF_TEXTREL;
-
}
}
}
@@ -2039,7 +2081,7 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
/* Allocate global sym .plt and .got entries, and space for global
sym dynamic relocs. */
- elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, (PTR) info);
+ elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info);
/* For every jump slot reserved in the sgotplt, reloc_count is
incremented. However, when we reserve space for TLS descriptors,
@@ -2170,8 +2212,7 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
/* If any dynamic relocs apply to a read-only section,
then we need a DT_TEXTREL entry. */
if ((info->flags & DF_TEXTREL) == 0)
- elf_link_hash_traverse (&htab->elf, readonly_dynrelocs,
- (PTR) info);
+ elf_link_hash_traverse (&htab->elf, readonly_dynrelocs, info);
if ((info->flags & DF_TEXTREL) != 0)
{
@@ -2680,7 +2721,8 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
&& ((h->def_dynamic
&& !h->def_regular)
|| h->root.type == bfd_link_hash_undefweak
- || h->root.type == bfd_link_hash_undefined)))
+ || h->root.type == bfd_link_hash_undefined))
+ || is_indirect_symbol (output_bfd, h))
{
Elf_Internal_Rela outrel;
bfd_byte *loc;
@@ -2766,9 +2808,12 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
}
}
- sreloc = elf_section_data (input_section)->sreloc;
- if (sreloc == NULL)
- abort ();
+ if ((! info->shared) && is_indirect_symbol (output_bfd, h))
+ sreloc = elf_section_data (input_section)->indirect_relocs;
+ else
+ sreloc = elf_section_data (input_section)->sreloc;
+
+ BFD_ASSERT (sreloc != NULL && sreloc->contents != NULL);
loc = sreloc->contents;
loc += sreloc->reloc_count++ * sizeof (Elf64_External_Rela);
@@ -2778,7 +2823,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
not want to fiddle with the addend. Otherwise, we
need to include the symbol value so that it becomes
an addend for the dynamic reloc. */
- if (! relocate)
+ if (! relocate || is_indirect_symbol (output_bfd, h))
continue;
}