type = bfd_get_8 (abfd, contents + offset - 2);
if (r_type == R_386_TLS_GD)
{
- /* Check transition from LD access model. Only
+ /* Check transition from GD access model. Only
leal foo@tlsgd(,%reg,1), %eax; call ___tls_get_addr
leal foo@tlsgd(%reg), %eax; call ___tls_get_addr; nop
can transit to different access model. */
return FALSE;
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ /* Use strncmp to check ___tls_get_addr since ___tls_get_addr
+ may be versioned. */
return (h != NULL
&& h->root.root.string != NULL
&& (ELF32_R_TYPE (rel[1].r_info) == R_386_PC32
|| ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32)
- && (strcmp (h->root.root.string, "___tls_get_addr") == 0));
+ && (strncmp (h->root.root.string, "___tls_get_addr",
+ 15) == 0));
case R_386_TLS_IE:
/* Check transition from IE access model:
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_GNU_IFUNC
+ && (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. */
this reloc. */
if (sreloc == NULL)
{
- const char *name;
- bfd *dynobj;
- unsigned int strndx = elf_elfheader (abfd)->e_shstrndx;
- unsigned int shnam = elf_section_data (sec)->rel_hdr.sh_name;
-
- name = bfd_elf_string_from_elf_section (abfd, strndx, shnam);
- if (name == NULL)
- return FALSE;
-
- if (! CONST_STRNEQ (name, ".rel")
- || strcmp (bfd_get_section_name (abfd, sec),
- name + 4) != 0)
- {
- (*_bfd_error_handler)
- (_("%B: bad relocation section name `%s\'"),
- abfd, name);
- }
-
if (htab->elf.dynobj == NULL)
htab->elf.dynobj = abfd;
- dynobj = htab->elf.dynobj;
- sreloc = bfd_get_section_by_name (dynobj, name);
+ sreloc = _bfd_elf_make_dynamic_reloc_section
+ (sec, htab->elf.dynobj, 2, abfd, /*rela?*/ FALSE);
+
if (sreloc == NULL)
- {
- flagword flags;
-
- flags = (SEC_HAS_CONTENTS | SEC_READONLY
- | SEC_IN_MEMORY | SEC_LINKER_CREATED);
- if ((sec->flags & SEC_ALLOC) != 0)
- flags |= SEC_ALLOC | SEC_LOAD;
- sreloc = bfd_make_section_with_flags (dynobj,
- name,
- flags);
- if (sreloc == NULL
- || ! bfd_set_section_alignment (dynobj, sreloc, 2))
- return FALSE;
- }
- elf_section_data (sec)->sreloc = sreloc;
+ return FALSE;
+
+ /* Create the ifunc section as well, even if we have not encountered a
+ indirect function symbol yet. We may not even see one in the input
+ object file, but we can still encounter them in libraries. */
+ (void) _bfd_elf_make_ifunc_reloc_section
+ (abfd, sec, htab->elf.dynobj, 2);
}
/* If this is a global symbol, we count the number of
struct elf_i386_link_hash_table *htab;
struct elf_i386_link_hash_entry *eh;
struct elf_i386_dyn_relocs *p;
+ bfd_boolean use_indirect_section = FALSE;
if (h->root.type == bfd_link_hash_indirect)
return TRUE;
}
}
}
+ else if (is_indirect_symbol (info->output_bfd, h)
+ && h->dynindx == -1
+ && ! h->forced_local)
+ {
+ if (bfd_elf_link_record_dynamic_symbol (info, h)
+ && h->dynindx != -1)
+ use_indirect_section = TRUE;
+ else
+ return FALSE;
+ }
else if (ELIMINATE_COPY_RELOCS)
{
/* For the non-shared case, discard space for relocs against
/* Finally, allocate space. */
for (p = eh->dyn_relocs; p != NULL; p = p->next)
{
- asection *sreloc = elf_section_data (p->sec)->sreloc;
+ asection *sreloc;
+
+ if (use_indirect_section)
+ 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 (Elf32_External_Rel);
}
/* 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,
/* 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)
{
|| h->root.type != bfd_link_hash_undefweak)
&& (r_type != R_386_PC32
|| !SYMBOL_CALLS_LOCAL (info, h)))
+ || (! info->shared
+ && h != NULL
+ && h->dynindx != -1
+ && ! h->forced_local
+ && ((struct elf_i386_link_hash_entry *) h)->dyn_relocs != NULL
+ && is_indirect_symbol (output_bfd, h))
|| (ELIMINATE_COPY_RELOCS
&& !info->shared
&& h != NULL
outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
}
- sreloc = elf_section_data (input_section)->sreloc;
- if (sreloc == NULL)
- abort ();
+ if (! info->shared
+ && h != NULL
+ && h->dynindx != -1
+ && ! h->forced_local
+ && is_indirect_symbol (output_bfd, h)
+ && elf_section_data (input_section)->indirect_relocs != NULL
+ && elf_section_data (input_section)->indirect_relocs->contents != NULL)
+ 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 (Elf32_External_Rel);
+
bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
/* If this reloc is against an external symbol, we do
return _bfd_elf_hash_symbol (h);
}
+/* Hook called by the linker routine which adds symbols from an object
+ file. */
+
+static bfd_boolean
+elf_i386_add_symbol_hook (bfd * abfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info * info ATTRIBUTE_UNUSED,
+ Elf_Internal_Sym * sym,
+ const char ** namep ATTRIBUTE_UNUSED,
+ flagword * flagsp ATTRIBUTE_UNUSED,
+ asection ** secp ATTRIBUTE_UNUSED,
+ bfd_vma * valp ATTRIBUTE_UNUSED)
+{
+ if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+ elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+
+ return TRUE;
+}
+
#define TARGET_LITTLE_SYM bfd_elf32_i386_vec
#define TARGET_LITTLE_NAME "elf32-i386"
#define ELF_ARCH bfd_arch_i386
((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
#define elf_backend_plt_sym_val elf_i386_plt_sym_val
#define elf_backend_hash_symbol elf_i386_hash_symbol
+#define elf_backend_add_symbol_hook elf_i386_add_symbol_hook
+#undef elf_backend_post_process_headers
+#define elf_backend_post_process_headers _bfd_elf_set_osabi
#include "elf32-target.h"
executables and (for simplicity) also all other object files. */
static void
-elf_i386_post_process_headers (bfd *abfd,
- struct bfd_link_info *info ATTRIBUTE_UNUSED)
+elf_i386_fbsd_post_process_headers (bfd *abfd, struct bfd_link_info *info)
{
- Elf_Internal_Ehdr *i_ehdrp;
+ _bfd_elf_set_osabi (abfd, info);
- i_ehdrp = elf_elfheader (abfd);
-
- /* Put an ABI label supported by FreeBSD >= 4.1. */
- i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi;
#ifdef OLD_FREEBSD_ABI_LABEL
/* The ABI label supported by FreeBSD <= 4.0 is quite nonstandard. */
memcpy (&i_ehdrp->e_ident[EI_ABIVERSION], "FreeBSD", 8);
}
#undef elf_backend_post_process_headers
-#define elf_backend_post_process_headers elf_i386_post_process_headers
+#define elf_backend_post_process_headers elf_i386_fbsd_post_process_headers
#undef elf32_bed
#define elf32_bed elf32_i386_fbsd_bed
+#undef elf_backend_add_symbol_hook
+
#include "elf32-target.h"
/* VxWorks support. */