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. */
if (sreloc == NULL)
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
{
asection *sreloc;
- sreloc = elf_section_data (p->sec)->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);
|| 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 (! 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);
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;
-
- i_ehdrp = elf_elfheader (abfd);
+ _bfd_elf_set_osabi (abfd, info);
- /* 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. */