include/elf
2009-04-30 Nick Clifton <nickc@redhat.com> * common.h (STT_GNU_IFUNC): Define. elfcpp 2009-04-30 Nick Clifton <nickc@redhat.com> * (enum STT): Add STT_GNU_IFUNC. gas 2009-04-30 Nick Clifton <nickc@redhat.com> * config/obj-elf.c (obj_elf_type): Add support for a gnu_indirect_function type. * config/tc-i386.c (tc_i386_fix_adjustable): Do not adjust fixups against indirect function symbols. * doc/as.texinfo (.type): Document the support for the gnu_indirect_function symbol type. * NEWS: Mention the new feature. gas/testsuite 2009-04-30 Nick Clifton <nickc@redhat.com> * gas/elf/elf.exp: Extend type test to include an ifunc symbol. Provide an alternative test for targets which do not support ifunc symbols. (type.s): Add entry for an ifunc symbol. (type.e): Add ifunc entry to expected symbol dump. (section2.e-armelf): Add entry for ifunc symbol. (type-noifunc.s): New file. (type-noifunc.e): New file. bfd/ 2009-04-30 Nick Clifton <nickc@redhat.com> * elf-bfd.h (struct bfd_elf_section_data): Add indirect_relocs section pointer. (struct elf_obj_data): Add has_ifunc_symbols boolean. * elf.c (swap_out_syms): Convert BSF_GNU_INDIRECT_FUNCTION flags into a STT_GNU_IFUNC symbol type. (_bfd_elf_is_function_type): Accept STT_GNU_IFUNC as a function type. (_bfd_elf_set_osabi): Set the osasbi field to ELFOSABI_LINUX if the binary contains ifunc symbols. * elfcode.h (elf_slurp_symbol_table): Translate the STT_GNU_IFUNC symbol type into a BSF_GNU_INDIRECT_FUNCTION flag. * elf32-i386.c (is_indirect_function): New function. (elf_i386_check_relocs): Create an ifunc output section. (allocate_dynrelocs): Create dynamic relocs in the ifunc output section if necessary. (elf_i386_relocate_section): Emit a reloc against an ifunc symbol if necessary. (elf_i386_add_symbol_hook): New function. Set the has_ifunc_symbols field of the elf_obj_data structure if an ifunc symbol is encountered. (elf_backend_post_process_headers): Define. (elf_backend_add_symbol_hook): Define. (elf_i386_post_process_headers): Rename to elf_i388_fbsd_post_process_headers. * elf64-x86_64.c (IS_X86_64_PCREL_TYPE): New macro. (is_indirect_function): New function. (elf64_x86_64_check_relocs): Create an ifunc output section. (allocate_dynrelocs): Create dynamic relocs in the ifunc output section if necessary. (elf64_x86_64_relocate_section): Emit a reloc against an ifunc symbol if necessary. (elf_i386_add_symbol_hook): Set the has_ifunc_symbols field of the elf_obj_data structure if an ifunc symbol is encountered. (elf_backend_post_process_headers): Define. * elflink.c (_bfd_elf_adjust_dynamic_symbol): Always create a PLT if we have ifunc symbols to handle. (get_ifunc_reloc_section_name): New function. Computes the name for an ifunc section. (_bfd_elf_make_ifunc_reloc_section): New function. Creates a section to hold ifunc relocs. * syms.c (BSF_GNU_INDIRECT_FUNCTION): Define. (bfd_print_symbol_vandf): Handle ifunc symbols. (bfd_decode_symclass): Likewise. * bfd-in2.h: Regenerate. binutils 2009-04-30 Nick Clifton <nickc@redhat.com> * readelf.c (dump_relocations): Display a relocation against an ifunc symbol as if it were a function invocation. (get_symbol_type): Handle STT_GNU_IFUNC. ld 2009-04-30 Nick Clifton <nickc@redhat.com> * NEWS: Mention support for IFUNC symbols. ld/testsuite 2009-04-30 Nick Clifton <nickc@redhat.com> * ld-ifunc: New directory. * ld-ifunc/ifunc.exp: New file: Run the IFUNC tests. * ld-ifunc/prog.c: New file. * ld-ifunc/lib.c: New file.
This commit is contained in:
parent
b22a5a4185
commit
d8045f234d
33 changed files with 824 additions and 70 deletions
|
@ -1,3 +1,50 @@
|
||||||
|
2009-04-30 Nick Clifton <nickc@redhat.com>
|
||||||
|
|
||||||
|
* elf-bfd.h (struct bfd_elf_section_data): Add indirect_relocs
|
||||||
|
section pointer.
|
||||||
|
(struct elf_obj_data): Add has_ifunc_symbols boolean.
|
||||||
|
* elf.c (swap_out_syms): Convert BSF_GNU_INDIRECT_FUNCTION flags
|
||||||
|
into a STT_GNU_IFUNC symbol type.
|
||||||
|
(_bfd_elf_is_function_type): Accept STT_GNU_IFUNC as a function
|
||||||
|
type.
|
||||||
|
(_bfd_elf_set_osabi): Set the osasbi field to ELFOSABI_LINUX if
|
||||||
|
the binary contains ifunc symbols.
|
||||||
|
* elfcode.h (elf_slurp_symbol_table): Translate the STT_GNU_IFUNC
|
||||||
|
symbol type into a BSF_GNU_INDIRECT_FUNCTION flag.
|
||||||
|
* elf32-i386.c (is_indirect_function): New function.
|
||||||
|
(elf_i386_check_relocs): Create an ifunc output section.
|
||||||
|
(allocate_dynrelocs): Create dynamic relocs in the ifunc output
|
||||||
|
section if necessary.
|
||||||
|
(elf_i386_relocate_section): Emit a reloc against an ifunc symbol
|
||||||
|
if necessary.
|
||||||
|
(elf_i386_add_symbol_hook): New function. Set the
|
||||||
|
has_ifunc_symbols field of the elf_obj_data structure if an ifunc
|
||||||
|
symbol is encountered.
|
||||||
|
(elf_backend_post_process_headers): Define.
|
||||||
|
(elf_backend_add_symbol_hook): Define.
|
||||||
|
(elf_i386_post_process_headers): Rename to
|
||||||
|
elf_i388_fbsd_post_process_headers.
|
||||||
|
* elf64-x86_64.c (IS_X86_64_PCREL_TYPE): New macro.
|
||||||
|
(is_indirect_function): New function.
|
||||||
|
(elf64_x86_64_check_relocs): Create an ifunc output section.
|
||||||
|
(allocate_dynrelocs): Create dynamic relocs in the ifunc output
|
||||||
|
section if necessary.
|
||||||
|
(elf64_x86_64_relocate_section): Emit a reloc against an ifunc
|
||||||
|
symbol if necessary.
|
||||||
|
(elf_i386_add_symbol_hook): Set the has_ifunc_symbols field of the
|
||||||
|
elf_obj_data structure if an ifunc symbol is encountered.
|
||||||
|
(elf_backend_post_process_headers): Define.
|
||||||
|
* elflink.c (_bfd_elf_adjust_dynamic_symbol): Always create a PLT
|
||||||
|
if we have ifunc symbols to handle.
|
||||||
|
(get_ifunc_reloc_section_name): New function. Computes the name
|
||||||
|
for an ifunc section.
|
||||||
|
(_bfd_elf_make_ifunc_reloc_section): New function. Creates a
|
||||||
|
section to hold ifunc relocs.
|
||||||
|
* syms.c (BSF_GNU_INDIRECT_FUNCTION): Define.
|
||||||
|
(bfd_print_symbol_vandf): Handle ifunc symbols.
|
||||||
|
(bfd_decode_symclass): Likewise.
|
||||||
|
* bfd-in2.h: Regenerate.
|
||||||
|
|
||||||
2009-04-30 Joseph Myers <joseph@codesourcery.com>
|
2009-04-30 Joseph Myers <joseph@codesourcery.com>
|
||||||
|
|
||||||
* elf32-arm.c (elf32_arm_check_relocs): Give errors for absolute
|
* elf32-arm.c (elf32_arm_check_relocs): Give errors for absolute
|
||||||
|
|
|
@ -4608,6 +4608,12 @@ typedef struct bfd_symbol
|
||||||
/* This symbol was created by bfd_get_synthetic_symtab. */
|
/* This symbol was created by bfd_get_synthetic_symtab. */
|
||||||
#define BSF_SYNTHETIC (1 << 21)
|
#define BSF_SYNTHETIC (1 << 21)
|
||||||
|
|
||||||
|
/* This symbol is an indirect code object. Unrelated to BSF_INDIRECT.
|
||||||
|
The dynamic linker will compute the value of this symbol by
|
||||||
|
calling the function that it points to. BSF_FUNCTION must
|
||||||
|
also be also set. */
|
||||||
|
#define BSF_GNU_INDIRECT_FUNCTION (1 << 22)
|
||||||
|
|
||||||
flagword flags;
|
flagword flags;
|
||||||
|
|
||||||
/* A pointer to the section to which this symbol is
|
/* A pointer to the section to which this symbol is
|
||||||
|
|
|
@ -1297,6 +1297,9 @@ struct bfd_elf_section_data
|
||||||
/* A pointer to the bfd section used for dynamic relocs. */
|
/* A pointer to the bfd section used for dynamic relocs. */
|
||||||
asection *sreloc;
|
asection *sreloc;
|
||||||
|
|
||||||
|
/* A pointer to the bfd section used for dynamic relocs against ifunc symbols. */
|
||||||
|
asection *indirect_relocs;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
/* Group name, if this section is a member of a group. */
|
/* Group name, if this section is a member of a group. */
|
||||||
const char *name;
|
const char *name;
|
||||||
|
@ -1559,6 +1562,11 @@ struct elf_obj_tdata
|
||||||
bfd_size_type build_id_size;
|
bfd_size_type build_id_size;
|
||||||
bfd_byte *build_id;
|
bfd_byte *build_id;
|
||||||
|
|
||||||
|
/* True if the bfd contains symbols that have the STT_GNU_IFUNC
|
||||||
|
symbol type. Used to set the osabi field in the ELF header
|
||||||
|
structure. */
|
||||||
|
bfd_boolean has_ifunc_symbols;
|
||||||
|
|
||||||
/* An identifier used to distinguish different target
|
/* An identifier used to distinguish different target
|
||||||
specific extensions to this structure. */
|
specific extensions to this structure. */
|
||||||
enum elf_object_id object_id;
|
enum elf_object_id object_id;
|
||||||
|
@ -2139,6 +2147,9 @@ extern int _bfd_elf_obj_attrs_arg_type (bfd *, int, int);
|
||||||
extern void _bfd_elf_parse_attributes (bfd *, Elf_Internal_Shdr *);
|
extern void _bfd_elf_parse_attributes (bfd *, Elf_Internal_Shdr *);
|
||||||
extern bfd_boolean _bfd_elf_merge_object_attributes (bfd *, bfd *);
|
extern bfd_boolean _bfd_elf_merge_object_attributes (bfd *, bfd *);
|
||||||
|
|
||||||
|
extern asection * _bfd_elf_make_ifunc_reloc_section
|
||||||
|
(bfd *, asection *, bfd *, unsigned int);
|
||||||
|
|
||||||
/* Large common section. */
|
/* Large common section. */
|
||||||
extern asection _bfd_elf_large_com_section;
|
extern asection _bfd_elf_large_com_section;
|
||||||
|
|
||||||
|
|
14
bfd/elf.c
14
bfd/elf.c
|
@ -6399,6 +6399,8 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"),
|
||||||
|
|
||||||
if ((flags & BSF_THREAD_LOCAL) != 0)
|
if ((flags & BSF_THREAD_LOCAL) != 0)
|
||||||
type = STT_TLS;
|
type = STT_TLS;
|
||||||
|
else if ((flags & BSF_GNU_INDIRECT_FUNCTION) != 0)
|
||||||
|
type = STT_GNU_IFUNC;
|
||||||
else if ((flags & BSF_FUNCTION) != 0)
|
else if ((flags & BSF_FUNCTION) != 0)
|
||||||
type = STT_FUNC;
|
type = STT_FUNC;
|
||||||
else if ((flags & BSF_OBJECT) != 0)
|
else if ((flags & BSF_OBJECT) != 0)
|
||||||
|
@ -8977,15 +8979,23 @@ _bfd_elf_set_osabi (bfd * abfd,
|
||||||
i_ehdrp = elf_elfheader (abfd);
|
i_ehdrp = elf_elfheader (abfd);
|
||||||
|
|
||||||
i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi;
|
i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi;
|
||||||
|
|
||||||
|
/* To make things simpler for the loader on Linux systems we set the
|
||||||
|
osabi field to ELFOSABI_LINUX if the binary contains symbols of
|
||||||
|
the STT_GNU_IFUNC type. */
|
||||||
|
if (i_ehdrp->e_ident[EI_OSABI] == ELFOSABI_NONE
|
||||||
|
&& elf_tdata (abfd)->has_ifunc_symbols)
|
||||||
|
i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_LINUX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return TRUE for ELF symbol types that represent functions.
|
/* Return TRUE for ELF symbol types that represent functions.
|
||||||
This is the default version of this function, which is sufficient for
|
This is the default version of this function, which is sufficient for
|
||||||
most targets. It returns true if TYPE is STT_FUNC. */
|
most targets. It returns true if TYPE is STT_FUNC or STT_GNU_IFUNC. */
|
||||||
|
|
||||||
bfd_boolean
|
bfd_boolean
|
||||||
_bfd_elf_is_function_type (unsigned int type)
|
_bfd_elf_is_function_type (unsigned int type)
|
||||||
{
|
{
|
||||||
return (type == STT_FUNC);
|
return (type == STT_FUNC
|
||||||
|
|| type == STT_GNU_IFUNC);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1196,6 +1196,25 @@ elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd,
|
||||||
return TRUE;
|
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
|
/* Look through the relocs for a section during the first phase, and
|
||||||
calculate needed space in the global offset table, procedure linkage
|
calculate needed space in the global offset table, procedure linkage
|
||||||
table, and dynamic reloc sections. */
|
table, and dynamic reloc sections. */
|
||||||
|
@ -1473,6 +1492,12 @@ elf_i386_check_relocs (bfd *abfd,
|
||||||
|
|
||||||
if (sreloc == NULL)
|
if (sreloc == NULL)
|
||||||
return FALSE;
|
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
|
/* If this is a global symbol, we count the number of
|
||||||
|
@ -1815,6 +1840,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||||
struct elf_i386_link_hash_table *htab;
|
struct elf_i386_link_hash_table *htab;
|
||||||
struct elf_i386_link_hash_entry *eh;
|
struct elf_i386_link_hash_entry *eh;
|
||||||
struct elf_i386_dyn_relocs *p;
|
struct elf_i386_dyn_relocs *p;
|
||||||
|
bfd_boolean use_indirect_section = FALSE;
|
||||||
|
|
||||||
if (h->root.type == bfd_link_hash_indirect)
|
if (h->root.type == bfd_link_hash_indirect)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -2036,6 +2062,16 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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)
|
else if (ELIMINATE_COPY_RELOCS)
|
||||||
{
|
{
|
||||||
/* For the non-shared case, discard space for relocs against
|
/* For the non-shared case, discard space for relocs against
|
||||||
|
@ -2074,7 +2110,10 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||||
{
|
{
|
||||||
asection *sreloc;
|
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);
|
BFD_ASSERT (sreloc != NULL);
|
||||||
sreloc->size += p->count * sizeof (Elf32_External_Rel);
|
sreloc->size += p->count * sizeof (Elf32_External_Rel);
|
||||||
|
@ -2877,6 +2916,12 @@ elf_i386_relocate_section (bfd *output_bfd,
|
||||||
|| h->root.type != bfd_link_hash_undefweak)
|
|| h->root.type != bfd_link_hash_undefweak)
|
||||||
&& (r_type != R_386_PC32
|
&& (r_type != R_386_PC32
|
||||||
|| !SYMBOL_CALLS_LOCAL (info, h)))
|
|| !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
|
|| (ELIMINATE_COPY_RELOCS
|
||||||
&& !info->shared
|
&& !info->shared
|
||||||
&& h != NULL
|
&& h != NULL
|
||||||
|
@ -2925,7 +2970,16 @@ elf_i386_relocate_section (bfd *output_bfd,
|
||||||
outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
|
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);
|
BFD_ASSERT (sreloc != NULL && sreloc->contents != NULL);
|
||||||
|
|
||||||
|
@ -4045,6 +4099,24 @@ elf_i386_hash_symbol (struct elf_link_hash_entry *h)
|
||||||
return _bfd_elf_hash_symbol (h);
|
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_SYM bfd_elf32_i386_vec
|
||||||
#define TARGET_LITTLE_NAME "elf32-i386"
|
#define TARGET_LITTLE_NAME "elf32-i386"
|
||||||
#define ELF_ARCH bfd_arch_i386
|
#define ELF_ARCH bfd_arch_i386
|
||||||
|
@ -4089,6 +4161,9 @@ elf_i386_hash_symbol (struct elf_link_hash_entry *h)
|
||||||
((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
|
((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
|
||||||
#define elf_backend_plt_sym_val elf_i386_plt_sym_val
|
#define elf_backend_plt_sym_val elf_i386_plt_sym_val
|
||||||
#define elf_backend_hash_symbol elf_i386_hash_symbol
|
#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"
|
#include "elf32-target.h"
|
||||||
|
|
||||||
|
@ -4106,15 +4181,10 @@ elf_i386_hash_symbol (struct elf_link_hash_entry *h)
|
||||||
executables and (for simplicity) also all other object files. */
|
executables and (for simplicity) also all other object files. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
elf_i386_post_process_headers (bfd *abfd,
|
elf_i386_fbsd_post_process_headers (bfd *abfd, struct bfd_link_info *info)
|
||||||
struct bfd_link_info *info ATTRIBUTE_UNUSED)
|
|
||||||
{
|
{
|
||||||
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
|
#ifdef OLD_FREEBSD_ABI_LABEL
|
||||||
/* The ABI label supported by FreeBSD <= 4.0 is quite nonstandard. */
|
/* The ABI label supported by FreeBSD <= 4.0 is quite nonstandard. */
|
||||||
memcpy (&i_ehdrp->e_ident[EI_ABIVERSION], "FreeBSD", 8);
|
memcpy (&i_ehdrp->e_ident[EI_ABIVERSION], "FreeBSD", 8);
|
||||||
|
@ -4122,10 +4192,12 @@ elf_i386_post_process_headers (bfd *abfd,
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef elf_backend_post_process_headers
|
#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
|
#undef elf32_bed
|
||||||
#define elf32_bed elf32_i386_fbsd_bed
|
#define elf32_bed elf32_i386_fbsd_bed
|
||||||
|
|
||||||
|
#undef elf_backend_add_symbol_hook
|
||||||
|
|
||||||
#include "elf32-target.h"
|
#include "elf32-target.h"
|
||||||
|
|
||||||
/* VxWorks support. */
|
/* VxWorks support. */
|
||||||
|
|
|
@ -161,6 +161,12 @@ static reloc_howto_type x86_64_elf_howto_table[] =
|
||||||
FALSE)
|
FALSE)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define IS_X86_64_PCREL_TYPE(TYPE) \
|
||||||
|
( ((TYPE) == R_X86_64_PC8) \
|
||||||
|
|| ((TYPE) == R_X86_64_PC16) \
|
||||||
|
|| ((TYPE) == R_X86_64_PC32) \
|
||||||
|
|| ((TYPE) == R_X86_64_PC64))
|
||||||
|
|
||||||
/* Map BFD relocs to the x86_64 elf relocs. */
|
/* Map BFD relocs to the x86_64 elf relocs. */
|
||||||
struct elf_reloc_map
|
struct elf_reloc_map
|
||||||
{
|
{
|
||||||
|
@ -977,6 +983,25 @@ elf64_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
|
||||||
return TRUE;
|
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
|
/* Look through the relocs for a section during the first phase, and
|
||||||
calculate needed space in the global offset table, procedure
|
calculate needed space in the global offset table, procedure
|
||||||
linkage table, and dynamic reloc sections. */
|
linkage table, and dynamic reloc sections. */
|
||||||
|
@ -1003,7 +1028,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
||||||
sym_hashes = elf_sym_hashes (abfd);
|
sym_hashes = elf_sym_hashes (abfd);
|
||||||
|
|
||||||
sreloc = NULL;
|
sreloc = NULL;
|
||||||
|
|
||||||
rel_end = relocs + sec->reloc_count;
|
rel_end = relocs + sec->reloc_count;
|
||||||
for (rel = relocs; rel < rel_end; rel++)
|
for (rel = relocs; rel < rel_end; rel++)
|
||||||
{
|
{
|
||||||
|
@ -1259,13 +1284,9 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
||||||
may need to keep relocations for symbols satisfied by a
|
may need to keep relocations for symbols satisfied by a
|
||||||
dynamic library if we manage to avoid copy relocs for the
|
dynamic library if we manage to avoid copy relocs for the
|
||||||
symbol. */
|
symbol. */
|
||||||
|
|
||||||
if ((info->shared
|
if ((info->shared
|
||||||
&& (sec->flags & SEC_ALLOC) != 0
|
&& (sec->flags & SEC_ALLOC) != 0
|
||||||
&& (((r_type != R_X86_64_PC8)
|
&& (! IS_X86_64_PCREL_TYPE (r_type)
|
||||||
&& (r_type != R_X86_64_PC16)
|
|
||||||
&& (r_type != R_X86_64_PC32)
|
|
||||||
&& (r_type != R_X86_64_PC64))
|
|
||||||
|| (h != NULL
|
|| (h != NULL
|
||||||
&& (! SYMBOLIC_BIND (info, h)
|
&& (! SYMBOLIC_BIND (info, h)
|
||||||
|| h->root.type == bfd_link_hash_defweak
|
|| h->root.type == bfd_link_hash_defweak
|
||||||
|
@ -1293,6 +1314,12 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
||||||
|
|
||||||
if (sreloc == NULL)
|
if (sreloc == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
/* Create the ifunc section, even if we will not encounter an
|
||||||
|
indirect function symbol. 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
|
/* If this is a global symbol, we count the number of
|
||||||
|
@ -1324,6 +1351,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
||||||
if (p == NULL || p->sec != sec)
|
if (p == NULL || p->sec != sec)
|
||||||
{
|
{
|
||||||
bfd_size_type amt = sizeof *p;
|
bfd_size_type amt = sizeof *p;
|
||||||
|
|
||||||
p = ((struct elf64_x86_64_dyn_relocs *)
|
p = ((struct elf64_x86_64_dyn_relocs *)
|
||||||
bfd_alloc (htab->elf.dynobj, amt));
|
bfd_alloc (htab->elf.dynobj, amt));
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
|
@ -1336,10 +1364,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
||||||
}
|
}
|
||||||
|
|
||||||
p->count += 1;
|
p->count += 1;
|
||||||
if (r_type == R_X86_64_PC8
|
if (IS_X86_64_PCREL_TYPE (r_type))
|
||||||
|| r_type == R_X86_64_PC16
|
|
||||||
|| r_type == R_X86_64_PC32
|
|
||||||
|| r_type == R_X86_64_PC64)
|
|
||||||
p->pc_count += 1;
|
p->pc_count += 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1650,6 +1675,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
|
||||||
struct elf64_x86_64_link_hash_table *htab;
|
struct elf64_x86_64_link_hash_table *htab;
|
||||||
struct elf64_x86_64_link_hash_entry *eh;
|
struct elf64_x86_64_link_hash_entry *eh;
|
||||||
struct elf64_x86_64_dyn_relocs *p;
|
struct elf64_x86_64_dyn_relocs *p;
|
||||||
|
bfd_boolean use_indirect_section = FALSE;
|
||||||
|
|
||||||
if (h->root.type == bfd_link_hash_indirect)
|
if (h->root.type == bfd_link_hash_indirect)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -1728,7 +1754,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
|
||||||
&& !info->shared
|
&& !info->shared
|
||||||
&& h->dynindx == -1
|
&& h->dynindx == -1
|
||||||
&& elf64_x86_64_hash_entry (h)->tls_type == GOT_TLS_IE)
|
&& elf64_x86_64_hash_entry (h)->tls_type == GOT_TLS_IE)
|
||||||
h->got.offset = (bfd_vma) -1;
|
{
|
||||||
|
h->got.offset = (bfd_vma) -1;
|
||||||
|
}
|
||||||
else if (h->got.refcount > 0)
|
else if (h->got.refcount > 0)
|
||||||
{
|
{
|
||||||
asection *s;
|
asection *s;
|
||||||
|
@ -1827,13 +1855,21 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
|
||||||
/* Make sure undefined weak symbols are output as a dynamic
|
/* Make sure undefined weak symbols are output as a dynamic
|
||||||
symbol in PIEs. */
|
symbol in PIEs. */
|
||||||
else if (h->dynindx == -1
|
else if (h->dynindx == -1
|
||||||
&& !h->forced_local)
|
&& ! h->forced_local
|
||||||
{
|
&& ! bfd_elf_link_record_dynamic_symbol (info, h))
|
||||||
if (! bfd_elf_link_record_dynamic_symbol (info, h))
|
return FALSE;
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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)
|
else if (ELIMINATE_COPY_RELOCS)
|
||||||
{
|
{
|
||||||
/* For the non-shared case, discard space for relocs against
|
/* For the non-shared case, discard space for relocs against
|
||||||
|
@ -1850,11 +1886,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
|
||||||
/* Make sure this symbol is output as a dynamic symbol.
|
/* Make sure this symbol is output as a dynamic symbol.
|
||||||
Undefined weak syms won't yet be marked as dynamic. */
|
Undefined weak syms won't yet be marked as dynamic. */
|
||||||
if (h->dynindx == -1
|
if (h->dynindx == -1
|
||||||
&& !h->forced_local)
|
&& ! h->forced_local
|
||||||
{
|
&& ! bfd_elf_link_record_dynamic_symbol (info, h))
|
||||||
if (! bfd_elf_link_record_dynamic_symbol (info, h))
|
return FALSE;
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If that succeeded, we know we'll be keeping all the
|
/* If that succeeded, we know we'll be keeping all the
|
||||||
relocs. */
|
relocs. */
|
||||||
|
@ -1872,7 +1906,10 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
|
||||||
{
|
{
|
||||||
asection * sreloc;
|
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);
|
BFD_ASSERT (sreloc != NULL);
|
||||||
|
|
||||||
|
@ -2674,11 +2711,14 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
||||||
&& (h == NULL
|
&& (h == NULL
|
||||||
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|
||||||
|| h->root.type != bfd_link_hash_undefweak)
|
|| h->root.type != bfd_link_hash_undefweak)
|
||||||
&& ((r_type != R_X86_64_PC8
|
&& (! IS_X86_64_PCREL_TYPE (r_type)
|
||||||
&& r_type != R_X86_64_PC16
|
|| ! SYMBOL_CALLS_LOCAL (info, h)))
|
||||||
&& r_type != R_X86_64_PC32
|
|| (! info->shared
|
||||||
&& r_type != R_X86_64_PC64)
|
&& h != NULL
|
||||||
|| !SYMBOL_CALLS_LOCAL (info, h)))
|
&& h->dynindx != -1
|
||||||
|
&& ! h->forced_local
|
||||||
|
&& ((struct elf64_x86_64_link_hash_entry *) h)->dyn_relocs != NULL
|
||||||
|
&& is_indirect_symbol (output_bfd, h))
|
||||||
|| (ELIMINATE_COPY_RELOCS
|
|| (ELIMINATE_COPY_RELOCS
|
||||||
&& !info->shared
|
&& !info->shared
|
||||||
&& h != NULL
|
&& h != NULL
|
||||||
|
@ -2718,13 +2758,10 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
||||||
become local. */
|
become local. */
|
||||||
else if (h != NULL
|
else if (h != NULL
|
||||||
&& h->dynindx != -1
|
&& h->dynindx != -1
|
||||||
&& (r_type == R_X86_64_PC8
|
&& (IS_X86_64_PCREL_TYPE (r_type)
|
||||||
|| r_type == R_X86_64_PC16
|
|| ! info->shared
|
||||||
|| r_type == R_X86_64_PC32
|
|| ! SYMBOLIC_BIND (info, h)
|
||||||
|| r_type == R_X86_64_PC64
|
|| ! h->def_regular))
|
||||||
|| !info->shared
|
|
||||||
|| !SYMBOLIC_BIND (info, h)
|
|
||||||
|| !h->def_regular))
|
|
||||||
{
|
{
|
||||||
outrel.r_info = ELF64_R_INFO (h->dynindx, r_type);
|
outrel.r_info = ELF64_R_INFO (h->dynindx, r_type);
|
||||||
outrel.r_addend = rel->r_addend;
|
outrel.r_addend = rel->r_addend;
|
||||||
|
@ -2773,8 +2810,17 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
BFD_ASSERT (sreloc != NULL && sreloc->contents != NULL);
|
||||||
|
|
||||||
loc = sreloc->contents;
|
loc = sreloc->contents;
|
||||||
|
@ -3660,11 +3706,12 @@ elf64_x86_64_section_from_shdr (bfd *abfd,
|
||||||
|
|
||||||
static bfd_boolean
|
static bfd_boolean
|
||||||
elf64_x86_64_add_symbol_hook (bfd *abfd,
|
elf64_x86_64_add_symbol_hook (bfd *abfd,
|
||||||
struct bfd_link_info *info ATTRIBUTE_UNUSED,
|
struct bfd_link_info *info,
|
||||||
Elf_Internal_Sym *sym,
|
Elf_Internal_Sym *sym,
|
||||||
const char **namep ATTRIBUTE_UNUSED,
|
const char **namep ATTRIBUTE_UNUSED,
|
||||||
flagword *flagsp ATTRIBUTE_UNUSED,
|
flagword *flagsp ATTRIBUTE_UNUSED,
|
||||||
asection **secp, bfd_vma *valp)
|
asection **secp,
|
||||||
|
bfd_vma *valp)
|
||||||
{
|
{
|
||||||
asection *lcomm;
|
asection *lcomm;
|
||||||
|
|
||||||
|
@ -3687,6 +3734,10 @@ elf64_x86_64_add_symbol_hook (bfd *abfd,
|
||||||
*valp = sym->st_size;
|
*valp = sym->st_size;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
|
||||||
|
elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3914,6 +3965,9 @@ static const struct bfd_elf_special_section
|
||||||
#define elf_backend_hash_symbol \
|
#define elf_backend_hash_symbol \
|
||||||
elf64_x86_64_hash_symbol
|
elf64_x86_64_hash_symbol
|
||||||
|
|
||||||
|
#undef elf_backend_post_process_headers
|
||||||
|
#define elf_backend_post_process_headers _bfd_elf_set_osabi
|
||||||
|
|
||||||
#include "elf64-target.h"
|
#include "elf64-target.h"
|
||||||
|
|
||||||
/* FreeBSD support. */
|
/* FreeBSD support. */
|
||||||
|
@ -3926,9 +3980,6 @@ static const struct bfd_elf_special_section
|
||||||
#undef ELF_OSABI
|
#undef ELF_OSABI
|
||||||
#define ELF_OSABI ELFOSABI_FREEBSD
|
#define ELF_OSABI ELFOSABI_FREEBSD
|
||||||
|
|
||||||
#undef elf_backend_post_process_headers
|
|
||||||
#define elf_backend_post_process_headers _bfd_elf_set_osabi
|
|
||||||
|
|
||||||
#undef elf64_bed
|
#undef elf64_bed
|
||||||
#define elf64_bed elf64_x86_64_fbsd_bed
|
#define elf64_bed elf64_x86_64_fbsd_bed
|
||||||
|
|
||||||
|
|
|
@ -1311,6 +1311,9 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic)
|
||||||
case STT_SRELC:
|
case STT_SRELC:
|
||||||
sym->symbol.flags |= BSF_SRELC;
|
sym->symbol.flags |= BSF_SRELC;
|
||||||
break;
|
break;
|
||||||
|
case STT_GNU_IFUNC:
|
||||||
|
sym->symbol.flags |= BSF_GNU_INDIRECT_FUNCTION;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dynamic)
|
if (dynamic)
|
||||||
|
|
|
@ -2749,6 +2749,13 @@ _bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data)
|
||||||
dynobj = elf_hash_table (eif->info)->dynobj;
|
dynobj = elf_hash_table (eif->info)->dynobj;
|
||||||
bed = get_elf_backend_data (dynobj);
|
bed = get_elf_backend_data (dynobj);
|
||||||
|
|
||||||
|
|
||||||
|
if (h->type == STT_GNU_IFUNC
|
||||||
|
&& (bed->elf_osabi == ELFOSABI_LINUX
|
||||||
|
/* GNU/Linux is still using the default value 0. */
|
||||||
|
|| bed->elf_osabi == ELFOSABI_NONE))
|
||||||
|
h->needs_plt = 1;
|
||||||
|
|
||||||
if (! (*bed->elf_backend_adjust_dynamic_symbol) (eif->info, h))
|
if (! (*bed->elf_backend_adjust_dynamic_symbol) (eif->info, h))
|
||||||
{
|
{
|
||||||
eif->failed = TRUE;
|
eif->failed = TRUE;
|
||||||
|
@ -12533,3 +12540,70 @@ _bfd_elf_make_dynamic_reloc_section (asection * sec,
|
||||||
|
|
||||||
return reloc_sec;
|
return reloc_sec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns the name of the ifunc using dynamic reloc section associated with SEC. */
|
||||||
|
#define IFUNC_INFIX ".ifunc"
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
get_ifunc_reloc_section_name (bfd * abfd,
|
||||||
|
asection * sec)
|
||||||
|
{
|
||||||
|
const char * dot;
|
||||||
|
char * name;
|
||||||
|
const char * base_name;
|
||||||
|
unsigned int strndx = elf_elfheader (abfd)->e_shstrndx;
|
||||||
|
unsigned int shnam = elf_section_data (sec)->rel_hdr.sh_name;
|
||||||
|
|
||||||
|
base_name = bfd_elf_string_from_elf_section (abfd, strndx, shnam);
|
||||||
|
if (base_name == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
dot = strchr (base_name + 1, '.');
|
||||||
|
name = bfd_alloc (abfd, strlen (base_name) + strlen (IFUNC_INFIX) + 1);
|
||||||
|
sprintf (name, "%.*s%s%s", (int)(dot - base_name), base_name, IFUNC_INFIX, dot);
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Like _bfd_elf_make_dynamic_reloc_section but it creates a
|
||||||
|
section for holding relocs against symbols with the STT_GNU_IFUNC
|
||||||
|
type. The section is attached to the OWNER bfd but it is created
|
||||||
|
with a name based on SEC from ABFD. */
|
||||||
|
|
||||||
|
asection *
|
||||||
|
_bfd_elf_make_ifunc_reloc_section (bfd * abfd,
|
||||||
|
asection * sec,
|
||||||
|
bfd * owner,
|
||||||
|
unsigned int align)
|
||||||
|
{
|
||||||
|
asection * reloc_sec = elf_section_data (sec)->indirect_relocs;
|
||||||
|
|
||||||
|
if (reloc_sec == NULL)
|
||||||
|
{
|
||||||
|
const char * name = get_ifunc_reloc_section_name (abfd, sec);
|
||||||
|
|
||||||
|
if (name == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
reloc_sec = bfd_get_section_by_name (owner, name);
|
||||||
|
|
||||||
|
if (reloc_sec == 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;
|
||||||
|
|
||||||
|
reloc_sec = bfd_make_section_with_flags (owner, name, flags);
|
||||||
|
|
||||||
|
if (reloc_sec != NULL
|
||||||
|
&& ! bfd_set_section_alignment (owner, reloc_sec, align))
|
||||||
|
reloc_sec = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
elf_section_data (sec)->indirect_relocs = reloc_sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reloc_sec;
|
||||||
|
}
|
||||||
|
|
10
bfd/syms.c
10
bfd/syms.c
|
@ -297,6 +297,12 @@ CODE_FRAGMENT
|
||||||
. {* This symbol was created by bfd_get_synthetic_symtab. *}
|
. {* This symbol was created by bfd_get_synthetic_symtab. *}
|
||||||
.#define BSF_SYNTHETIC (1 << 21)
|
.#define BSF_SYNTHETIC (1 << 21)
|
||||||
.
|
.
|
||||||
|
. {* This symbol is an indirect code object. Unrelated to BSF_INDIRECT.
|
||||||
|
. The dynamic linker will compute the value of this symbol by
|
||||||
|
. calling the function that it points to. BSF_FUNCTION must
|
||||||
|
. also be also set. *}
|
||||||
|
.#define BSF_GNU_INDIRECT_FUNCTION (1 << 22)
|
||||||
|
.
|
||||||
. flagword flags;
|
. flagword flags;
|
||||||
.
|
.
|
||||||
. {* A pointer to the section to which this symbol is
|
. {* A pointer to the section to which this symbol is
|
||||||
|
@ -483,7 +489,7 @@ bfd_print_symbol_vandf (bfd *abfd, void *arg, asymbol *symbol)
|
||||||
(type & BSF_WEAK) ? 'w' : ' ',
|
(type & BSF_WEAK) ? 'w' : ' ',
|
||||||
(type & BSF_CONSTRUCTOR) ? 'C' : ' ',
|
(type & BSF_CONSTRUCTOR) ? 'C' : ' ',
|
||||||
(type & BSF_WARNING) ? 'W' : ' ',
|
(type & BSF_WARNING) ? 'W' : ' ',
|
||||||
(type & BSF_INDIRECT) ? 'I' : ' ',
|
(type & BSF_INDIRECT) ? 'I' : (type & BSF_GNU_INDIRECT_FUNCTION) ? 'i' : ' ',
|
||||||
(type & BSF_DEBUGGING) ? 'd' : (type & BSF_DYNAMIC) ? 'D' : ' ',
|
(type & BSF_DEBUGGING) ? 'd' : (type & BSF_DYNAMIC) ? 'D' : ' ',
|
||||||
((type & BSF_FUNCTION)
|
((type & BSF_FUNCTION)
|
||||||
? 'F'
|
? 'F'
|
||||||
|
@ -669,6 +675,8 @@ bfd_decode_symclass (asymbol *symbol)
|
||||||
}
|
}
|
||||||
if (bfd_is_ind_section (symbol->section))
|
if (bfd_is_ind_section (symbol->section))
|
||||||
return 'I';
|
return 'I';
|
||||||
|
if (symbol->flags & BSF_GNU_INDIRECT_FUNCTION)
|
||||||
|
return 'i';
|
||||||
if (symbol->flags & BSF_WEAK)
|
if (symbol->flags & BSF_WEAK)
|
||||||
{
|
{
|
||||||
/* If weak, determine if it's specifically an object
|
/* If weak, determine if it's specifically an object
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
2009-04-30 Nick Clifton <nickc@redhat.com>
|
||||||
|
|
||||||
|
* readelf.c (dump_relocations): Display a relocation against an
|
||||||
|
ifunc symbol as if it were a function invocation.
|
||||||
|
(get_symbol_type): Handle STT_GNU_IFUNC.
|
||||||
|
|
||||||
2009-04-29 Anthony Green <green@moxielogic.com>
|
2009-04-29 Anthony Green <green@moxielogic.com>
|
||||||
|
|
||||||
* NEWS: Tweak verilog support description.
|
* NEWS: Tweak verilog support description.
|
||||||
|
|
|
@ -1238,9 +1238,38 @@ dump_relocations (FILE * file,
|
||||||
|
|
||||||
printf (" ");
|
printf (" ");
|
||||||
|
|
||||||
print_vma (psym->st_value, LONG_HEX);
|
if (ELF_ST_TYPE (psym->st_info) == STT_GNU_IFUNC)
|
||||||
|
{
|
||||||
|
const char * name;
|
||||||
|
unsigned int len;
|
||||||
|
unsigned int width = is_32bit_elf ? 8 : 14;
|
||||||
|
|
||||||
printf (is_32bit_elf ? " " : " ");
|
/* Relocations against GNU_IFUNC symbols do not use the value
|
||||||
|
of the symbol as the address to relocate against. Instead
|
||||||
|
they invoke the function named by the symbol and use its
|
||||||
|
result as the address for relocation.
|
||||||
|
|
||||||
|
To indicate this to the user, do not display the value of
|
||||||
|
the symbol in the "Symbols's Value" field. Instead show
|
||||||
|
its name followed by () as a hint that the symbol is
|
||||||
|
invoked. */
|
||||||
|
|
||||||
|
if (strtab == NULL
|
||||||
|
|| psym->st_name == 0
|
||||||
|
|| psym->st_name >= strtablen)
|
||||||
|
name = "??";
|
||||||
|
else
|
||||||
|
name = strtab + psym->st_name;
|
||||||
|
|
||||||
|
len = print_symbol (width, name);
|
||||||
|
printf ("()%-*s", len <= width ? (width + 1) - len : 1, " ");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
print_vma (psym->st_value, LONG_HEX);
|
||||||
|
|
||||||
|
printf (is_32bit_elf ? " " : " ");
|
||||||
|
}
|
||||||
|
|
||||||
if (psym->st_name == 0)
|
if (psym->st_name == 0)
|
||||||
{
|
{
|
||||||
|
@ -6913,6 +6942,12 @@ get_symbol_type (unsigned int type)
|
||||||
return "HP_STUB";
|
return "HP_STUB";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type == STT_GNU_IFUNC
|
||||||
|
&& (elf_header.e_ident[EI_OSABI] == ELFOSABI_LINUX
|
||||||
|
/* GNU/Linux is still using the default value 0. */
|
||||||
|
|| elf_header.e_ident[EI_OSABI] == ELFOSABI_NONE))
|
||||||
|
return "IFUNC";
|
||||||
|
|
||||||
snprintf (buff, sizeof (buff), _("<OS specific>: %d"), type);
|
snprintf (buff, sizeof (buff), _("<OS specific>: %d"), type);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
2009-04-30 Nick Clifton <nickc@redhat.com>
|
||||||
|
|
||||||
|
* (enum STT): Add STT_GNU_IFUNC.
|
||||||
|
|
||||||
2009-03-20 Mikolaj Zalewski <mikolajz@google.com>
|
2009-03-20 Mikolaj Zalewski <mikolajz@google.com>
|
||||||
|
|
||||||
* elfcpp.h (SHT_GNU_INCREMENTAL_INPUTS): Define.
|
* elfcpp.h (SHT_GNU_INCREMENTAL_INPUTS): Define.
|
||||||
|
|
|
@ -478,6 +478,7 @@ enum STT
|
||||||
STT_COMMON = 5,
|
STT_COMMON = 5,
|
||||||
STT_TLS = 6,
|
STT_TLS = 6,
|
||||||
STT_LOOS = 10,
|
STT_LOOS = 10,
|
||||||
|
STT_GNU_IFUNC = 10,
|
||||||
STT_HIOS = 12,
|
STT_HIOS = 12,
|
||||||
STT_LOPROC = 13,
|
STT_LOPROC = 13,
|
||||||
STT_HIPROC = 15,
|
STT_HIPROC = 15,
|
||||||
|
|
|
@ -1,3 +1,13 @@
|
||||||
|
2009-04-30 Nick Clifton <nickc@redhat.com>
|
||||||
|
|
||||||
|
* config/obj-elf.c (obj_elf_type): Add support for a
|
||||||
|
gnu_indirect_function type.
|
||||||
|
* config/tc-i386.c (tc_i386_fix_adjustable): Do not adjust fixups
|
||||||
|
against indirect function symbols.
|
||||||
|
* doc/as.texinfo (.type): Document the support for the
|
||||||
|
gnu_indirect_function symbol type.
|
||||||
|
* NEWS: Mention the new feature.
|
||||||
|
|
||||||
2009-04-24 Cary Coutant <ccoutant@google.com>
|
2009-04-24 Cary Coutant <ccoutant@google.com>
|
||||||
|
|
||||||
* NEWS: Add item about discriminator support.
|
* NEWS: Add item about discriminator support.
|
||||||
|
|
5
gas/NEWS
5
gas/NEWS
|
@ -5,6 +5,11 @@
|
||||||
|
|
||||||
* Add support for Sunplus score architecture.
|
* Add support for Sunplus score architecture.
|
||||||
|
|
||||||
|
* The .type pseudo-op now accepts a type of STT_GNU_IFUNC which can be used to
|
||||||
|
indicate that if the symbol is the target of a relocation, its value should
|
||||||
|
not be use. Instead the function should be invoked and its result used as
|
||||||
|
the value.
|
||||||
|
|
||||||
* Add support for Lattice Mico32 (lm32) architecture.
|
* Add support for Lattice Mico32 (lm32) architecture.
|
||||||
|
|
||||||
Changes in 2.19:
|
Changes in 2.19:
|
||||||
|
|
|
@ -1664,6 +1664,20 @@ obj_elf_type (int ignore ATTRIBUTE_UNUSED)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (strcmp (typename, "gnu_indirect_function") == 0
|
||||||
|
|| strcmp (typename, "10") == 0
|
||||||
|
|| strcmp (typename, "STT_GNU_IFUNC") == 0)
|
||||||
|
{
|
||||||
|
const struct elf_backend_data *bed;
|
||||||
|
|
||||||
|
bed = get_elf_backend_data (stdoutput);
|
||||||
|
if (!(bed->elf_osabi == ELFOSABI_LINUX
|
||||||
|
/* GNU/Linux is still using the default value 0. */
|
||||||
|
|| bed->elf_osabi == ELFOSABI_NONE))
|
||||||
|
as_bad (_("symbol type \"%s\" is supported only by GNU targets"),
|
||||||
|
typename);
|
||||||
|
type = BSF_FUNCTION | BSF_GNU_INDIRECT_FUNCTION;
|
||||||
|
}
|
||||||
#ifdef md_elf_symbol_type
|
#ifdef md_elf_symbol_type
|
||||||
else if ((type = md_elf_symbol_type (typename, sym, elfsym)) != -1)
|
else if ((type = md_elf_symbol_type (typename, sym, elfsym)) != -1)
|
||||||
;
|
;
|
||||||
|
|
|
@ -2499,6 +2499,10 @@ tc_i386_fix_adjustable (fixS *fixP ATTRIBUTE_UNUSED)
|
||||||
|| fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
|
|| fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
|
||||||
|| fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
|
|| fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (fixP->fx_addsy != NULL
|
||||||
|
&& symbol_get_bfdsym (fixP->fx_addsy)->flags & BSF_GNU_INDIRECT_FUNCTION)
|
||||||
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6327,6 +6327,11 @@ The types supported are:
|
||||||
@itemx function
|
@itemx function
|
||||||
Mark the symbol as being a function name.
|
Mark the symbol as being a function name.
|
||||||
|
|
||||||
|
@item STT_GNU_IFUNC
|
||||||
|
@itemx gnu_indirect_function
|
||||||
|
Mark the symbol as an indirect function when evaluated during reloc
|
||||||
|
processing. (This is only supported on Linux targeted assemblers).
|
||||||
|
|
||||||
@item STT_OBJECT
|
@item STT_OBJECT
|
||||||
@itemx object
|
@itemx object
|
||||||
Mark the symbol as being a data object.
|
Mark the symbol as being a data object.
|
||||||
|
|
|
@ -114,8 +114,20 @@ if { ([istarget "*-*-*elf*"]
|
||||||
run_elf_list_test "section5" "" "-al" "-SW" "| grep \" \\\\.test\\\[0-9\\\]\""
|
run_elf_list_test "section5" "" "-al" "-SW" "| grep \" \\\\.test\\\[0-9\\\]\""
|
||||||
run_dump_test "struct"
|
run_dump_test "struct"
|
||||||
run_dump_test "symtab"
|
run_dump_test "symtab"
|
||||||
run_dump_test "symver"
|
run_dump_test "symver"
|
||||||
run_elf_list_test "type" "" "" "-s" "| grep \"1 \\\[FIONTC\\\]\""
|
|
||||||
|
# The MSP port sets the ELF header's OSABI field to ELFOSABI_STANDALONE.
|
||||||
|
# The non-eabi ARM ports sets it to ELFOSABI_ARM.
|
||||||
|
# So for these targets we cannot include an IFUNC symbol type
|
||||||
|
# in the symbol type test.
|
||||||
|
if { [istarget "msp*-*-*"]
|
||||||
|
|| [istarget "arm*-*-*"]
|
||||||
|
|| [istarget "xscale*-*-*"]} then {
|
||||||
|
run_elf_list_test "type-noifunc" "" "" "-s" "| grep \"1 \\\[FONTC\\\]\""
|
||||||
|
} else {
|
||||||
|
run_elf_list_test "type" "" "" "-s" "| grep \"1 \\\[FIONTC\\\]\""
|
||||||
|
}
|
||||||
|
|
||||||
run_dump_test "section6"
|
run_dump_test "section6"
|
||||||
run_dump_test "section7"
|
run_dump_test "section7"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
Symbol table '.symtab' contains 6 entries:
|
Symbol table '.symtab' contains 7 entries:
|
||||||
Num: Value[ ]* Size Type Bind Vis Ndx Name
|
Num: Value[ ]* Size Type Bind Vis Ndx Name
|
||||||
0: 0+0 0 NOTYPE LOCAL DEFAULT UND
|
0: 0+0 0 NOTYPE LOCAL DEFAULT UND
|
||||||
1: 0+0 0 SECTION LOCAL DEFAULT 1
|
1: 0+0 0 SECTION LOCAL DEFAULT 1
|
||||||
|
@ -7,3 +7,4 @@ Symbol table '.symtab' contains 6 entries:
|
||||||
3: 0+0 0 SECTION LOCAL DEFAULT 3
|
3: 0+0 0 SECTION LOCAL DEFAULT 3
|
||||||
4: 0+0 0 SECTION LOCAL DEFAULT 4
|
4: 0+0 0 SECTION LOCAL DEFAULT 4
|
||||||
5: 0+0 0 NOTYPE LOCAL DEFAULT 4 \$d
|
5: 0+0 0 NOTYPE LOCAL DEFAULT 4 \$d
|
||||||
|
6: 0+0 0 SECTION LOCAL DEFAULT 5
|
||||||
|
|
5
gas/testsuite/gas/elf/type-noifunc.e
Normal file
5
gas/testsuite/gas/elf/type-noifunc.e
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
.: 0+0 1 FUNC LOCAL DEFAULT . function
|
||||||
|
.: 0+0 1 OBJECT LOCAL DEFAULT . object
|
||||||
|
.: 0+1 1 TLS LOCAL DEFAULT . tls_object
|
||||||
|
..: 0+2 1 NOTYPE LOCAL DEFAULT . notype
|
||||||
|
..: 0+1 1 (COMMON|OBJECT) GLOBAL DEFAULT COM common
|
20
gas/testsuite/gas/elf/type-noifunc.s
Normal file
20
gas/testsuite/gas/elf/type-noifunc.s
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
.text
|
||||||
|
.size function,1
|
||||||
|
.type function,%function
|
||||||
|
function:
|
||||||
|
.byte 0x0
|
||||||
|
.data
|
||||||
|
.type object,%object
|
||||||
|
.size object,1
|
||||||
|
object:
|
||||||
|
.byte 0x0
|
||||||
|
.type tls_object,%tls_object
|
||||||
|
.size tls_object,1
|
||||||
|
tls_object:
|
||||||
|
.byte 0x0
|
||||||
|
.type notype,%notype
|
||||||
|
.size notype,1
|
||||||
|
notype:
|
||||||
|
.byte 0x0
|
||||||
|
.comm common, 1
|
||||||
|
.type common,STT_COMMON
|
|
@ -1,5 +1,6 @@
|
||||||
.: 0+0 1 FUNC LOCAL DEFAULT . function
|
.: 0+0 1 FUNC LOCAL DEFAULT . function
|
||||||
|
.: 0+1 1 IFUNC LOCAL DEFAULT . indirect_function
|
||||||
.: 0+0 1 OBJECT LOCAL DEFAULT . object
|
.: 0+0 1 OBJECT LOCAL DEFAULT . object
|
||||||
.: 0+1 1 TLS LOCAL DEFAULT . tls_object
|
.: 0+1 1 TLS LOCAL DEFAULT . tls_object
|
||||||
.: 0+2 1 NOTYPE LOCAL DEFAULT . notype
|
..: 0+2 1 NOTYPE LOCAL DEFAULT . notype
|
||||||
..: 0+1 1 (COMMON|OBJECT) GLOBAL DEFAULT COM common
|
..: 0+1 1 (COMMON|OBJECT) GLOBAL DEFAULT COM common
|
||||||
|
|
|
@ -2,6 +2,10 @@
|
||||||
.size function,1
|
.size function,1
|
||||||
.type function,%function
|
.type function,%function
|
||||||
function:
|
function:
|
||||||
|
.byte 0x0
|
||||||
|
.size indirect_function,1
|
||||||
|
.type indirect_function,%gnu_indirect_function
|
||||||
|
indirect_function:
|
||||||
.byte 0x0
|
.byte 0x0
|
||||||
.data
|
.data
|
||||||
.type object,%object
|
.type object,%object
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
2009-04-30 Nick Clifton <nickc@redhat.com>
|
||||||
|
|
||||||
|
* common.h (STT_GNU_IFUNC): Define.
|
||||||
|
|
||||||
2009-04-24 Cary Coutant <ccoutant@google.com>
|
2009-04-24 Cary Coutant <ccoutant@google.com>
|
||||||
|
|
||||||
* dwarf2.h (DW_LNE_set_discriminator): New enum value.
|
* dwarf2.h (DW_LNE_set_discriminator): New enum value.
|
||||||
|
|
|
@ -569,6 +569,7 @@
|
||||||
#define STT_RELC 8 /* Complex relocation expression */
|
#define STT_RELC 8 /* Complex relocation expression */
|
||||||
#define STT_SRELC 9 /* Signed Complex relocation expression */
|
#define STT_SRELC 9 /* Signed Complex relocation expression */
|
||||||
#define STT_LOOS 10 /* OS-specific semantics */
|
#define STT_LOOS 10 /* OS-specific semantics */
|
||||||
|
#define STT_GNU_IFUNC 10 /* Symbol is an indirect code object */
|
||||||
#define STT_HIOS 12 /* OS-specific semantics */
|
#define STT_HIOS 12 /* OS-specific semantics */
|
||||||
#define STT_LOPROC 13 /* Processor-specific semantics */
|
#define STT_LOPROC 13 /* Processor-specific semantics */
|
||||||
#define STT_HIPROC 15 /* Processor-specific semantics */
|
#define STT_HIPROC 15 /* Processor-specific semantics */
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
2009-04-30 Nick Clifton <nickc@redhat.com>
|
||||||
|
|
||||||
|
* NEWS: Mention support for IFUNC symbols.
|
||||||
|
|
||||||
2009-04-29 Anthony Green <green@moxielogic.com>
|
2009-04-29 Anthony Green <green@moxielogic.com>
|
||||||
|
|
||||||
* emulparams/elf32moxie.sh (STACK_ADDR): Move default stack
|
* emulparams/elf32moxie.sh (STACK_ADDR): Move default stack
|
||||||
|
|
4
ld/NEWS
4
ld/NEWS
|
@ -15,6 +15,10 @@
|
||||||
automatically in the presence of un-stripped debug information, as GDB
|
automatically in the presence of un-stripped debug information, as GDB
|
||||||
needs to be able to find the debug info sections by their full names.
|
needs to be able to find the debug info sections by their full names.
|
||||||
|
|
||||||
|
* For GNU/Linux systems the linker will now avoid processing any relocations
|
||||||
|
made against symbols of the STT_GNU_IFUNC type and instead emit them into
|
||||||
|
the resulting binary for processing by the loader.
|
||||||
|
|
||||||
* --as-needed now links in a dynamic library if it satisfies undefined
|
* --as-needed now links in a dynamic library if it satisfies undefined
|
||||||
symbols in regular objects, or in other dynamic libraries. In the
|
symbols in regular objects, or in other dynamic libraries. In the
|
||||||
latter case the library is not linked if it is found in a DT_NEEDED
|
latter case the library is not linked if it is found in a DT_NEEDED
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
2009-04-30 Nick Clifton <nickc@redhat.com>
|
||||||
|
|
||||||
|
* ld-ifunc: New directory.
|
||||||
|
* ld-ifunc/ifunc.exp: New file: Run the IFUNC tests.
|
||||||
|
* ld-ifunc/prog.c: New file.
|
||||||
|
* ld-ifunc/lib.c: New file.
|
||||||
|
|
||||||
2009-04-30 Joseph Myers <joseph@codesourcery.com>
|
2009-04-30 Joseph Myers <joseph@codesourcery.com>
|
||||||
|
|
||||||
* ld-arm/movw-shared-1.d, ld-arm/movw-shared-1.s,
|
* ld-arm/movw-shared-1.d, ld-arm/movw-shared-1.s,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Expect script for LD section checks tests
|
# Expect script for LD section checks tests
|
||||||
# Copyright 1999, 2001, 2003, 2007 Free Software Foundation, Inc.
|
# Copyright 1999, 2001, 2003, 2007, 2009 Free Software Foundation, Inc.
|
||||||
#
|
#
|
||||||
# This file is part of the GNU Binutils.
|
# This file is part of the GNU Binutils.
|
||||||
#
|
#
|
||||||
|
@ -26,16 +26,17 @@ proc section_check {} {
|
||||||
global ld
|
global ld
|
||||||
global srcdir
|
global srcdir
|
||||||
global subdir
|
global subdir
|
||||||
|
|
||||||
# The usage of .lcomm in asm.s is incompatible with ia64 and ppc coff.
|
# The usage of .lcomm in asm.s is incompatible with ia64 and ppc coff.
|
||||||
if { [istarget ia64-*-*]
|
if { [istarget ia64-*-*]
|
||||||
|| [istarget powerpc*-*-aix*] || [istarget powerpc-*-beos*]
|
|| [istarget powerpc*-*-aix*]
|
||||||
|
|| [istarget powerpc-*-beos*]
|
||||||
|| [istarget rs6000-*-*] } {
|
|| [istarget rs6000-*-*] } {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
set test "check sections 1"
|
set test "check sections 1"
|
||||||
|
|
||||||
set ldflags "--check-sections"
|
set ldflags "--check-sections -e foo"
|
||||||
|
|
||||||
if { ![ld_assemble $as $srcdir/$subdir/asm.s tmpdir/asm.o]} {
|
if { ![ld_assemble $as $srcdir/$subdir/asm.s tmpdir/asm.o]} {
|
||||||
unresolved $test
|
unresolved $test
|
||||||
|
@ -55,15 +56,15 @@ proc section_check {} {
|
||||||
set ldflags "--check-sections -T $srcdir/$subdir/script -e foo"
|
set ldflags "--check-sections -T $srcdir/$subdir/script -e foo"
|
||||||
|
|
||||||
# Perform the equivalent of invoking ld_simple_link
|
# Perform the equivalent of invoking ld_simple_link
|
||||||
# except that we need to massage the output futher.
|
# except that we need to massage the output further.
|
||||||
|
|
||||||
set exec_output [run_host_cmd "$ld" "-o tmpdir/asm.x $ldflags tmpdir/asm.o"]
|
set exec_output [run_host_cmd "$ld" "-o tmpdir/asm.x $ldflags tmpdir/asm.o"]
|
||||||
set exec_output [prune_warnings $exec_output]
|
set exec_output [prune_warnings $exec_output]
|
||||||
|
|
||||||
# Make sure that we got some output from the linker
|
# Make sure that we got some output from the linker
|
||||||
if [string match "" $exec_output] then {
|
if [string match "" $exec_output] then {
|
||||||
fail $test
|
fail $test
|
||||||
}
|
}
|
||||||
|
|
||||||
# Now remove our expected error message
|
# Now remove our expected error message
|
||||||
regsub -all ".*: section .data .* overlaps section .text .*" $exec_output "" exec_output
|
regsub -all ".*: section .data .* overlaps section .text .*" $exec_output "" exec_output
|
||||||
|
@ -78,5 +79,3 @@ proc section_check {} {
|
||||||
}
|
}
|
||||||
|
|
||||||
section_check
|
section_check
|
||||||
|
|
||||||
|
|
||||||
|
|
254
ld/testsuite/ld-ifunc/ifunc.exp
Normal file
254
ld/testsuite/ld-ifunc/ifunc.exp
Normal file
|
@ -0,0 +1,254 @@
|
||||||
|
# Expect script for linker support of IFUNC symbols and relocations.
|
||||||
|
#
|
||||||
|
# Copyright 2009 Free Software Foundation, Inc.
|
||||||
|
# Contributed by Red Hat.
|
||||||
|
#
|
||||||
|
# This file is part of the GNU Binutils.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
||||||
|
# MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
# Written by Nick Clifton <nickc@redhat.com>
|
||||||
|
|
||||||
|
|
||||||
|
# IFUNC support has only been implemented for the x86_64 and ix86 so far.
|
||||||
|
if {! ( [istarget "x86_64-*-elf*"]
|
||||||
|
|| [istarget "x86_64-*-linux*"]
|
||||||
|
|| [istarget "i?86-*-elf*"]
|
||||||
|
|| [istarget "i?86-*-linux*"]) } {
|
||||||
|
verbose "IFUNC tests not run - target does not support IFUNC"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
# We need a native system. FIXME: Strictly speaking this
|
||||||
|
# is not true, we just need to know how to create a fully
|
||||||
|
# linked executable, including the C and Z libraries, using
|
||||||
|
# the linker that is under test.
|
||||||
|
if ![isnative] {
|
||||||
|
verbose "IFUNC tests not run - not a native toolchain"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
# We need a working compiler. (Strictly speaking this is
|
||||||
|
# not true, we could use target specific assembler files).
|
||||||
|
if { [which $CC] == 0 } {
|
||||||
|
verbose "IFUNC tests not run - no compiler available"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
# A procedure to check the OS/ABI field in the ELF header of a binary file.
|
||||||
|
proc check_osabi { binary_file expected_osabi } {
|
||||||
|
global READELF
|
||||||
|
global READELFFLAGS
|
||||||
|
|
||||||
|
catch "exec $READELF $READELFFLAGS --file-header $binary_file > readelf.out" got
|
||||||
|
|
||||||
|
if ![string match "" $got] then {
|
||||||
|
verbose "proc check_osabi: Readelf produced unexpected out processing $binary_file: $got"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if { ![regexp "\n\[ \]*OS/ABI:\[ \]*(.+)\n\[ \]*ABI" \
|
||||||
|
[file_contents readelf.out] nil osabi] } {
|
||||||
|
verbose "proc check_osabi: Readelf failed to extract an ELF header from $binary_file"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if { $osabi == $expected_osabi } {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
verbose "Expected OSABI: $expected_osabi, Obtained osabi: $osabi"
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# A procedure to confirm that a file contains the IFUNC symbol.
|
||||||
|
# Returns -1 upon error, 0 if the symbol was not found and 1 if it was found.
|
||||||
|
proc contains_ifunc_symbol { binary_file } {
|
||||||
|
global READELF
|
||||||
|
global READELFFLAGS
|
||||||
|
|
||||||
|
catch "exec $READELF $READELFFLAGS --symbols $binary_file > readelf.out" got
|
||||||
|
|
||||||
|
if ![string match "" $got] then {
|
||||||
|
verbose "proc contains_ifunc_symbol: Readelf produced unexpected out processing $binary_file: $got"
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Look for a line like this:
|
||||||
|
# 58: 0000000000400600 30 IFUNC GLOBAL DEFAULT 12 library_func2
|
||||||
|
|
||||||
|
if { ![regexp ".*\[ \]*IFUNC\[ \]+GLOBAL\[ \]+DEFAULT\[ \]+\[UND0-9\]+\[ \]+library_func2\n" [file_contents readelf.out]] } {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# A procedure to confirm that a file contains a relocation that references an IFUNC symbol.
|
||||||
|
# Returns -1 upon error, 0 if the reloc was not found and 1 if it was found.
|
||||||
|
proc contains_ifunc_reloc { binary_file } {
|
||||||
|
global READELF
|
||||||
|
global READELFFLAGS
|
||||||
|
|
||||||
|
catch "exec $READELF $READELFFLAGS --relocs $binary_file > readelf.out" got
|
||||||
|
|
||||||
|
if ![string match "" $got] then {
|
||||||
|
verbose "proc contains_ifunc_reloc: Readelf produced unexpected out processing $binary_file: $got"
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
if [string match "" [file_contents readelf.out]] then {
|
||||||
|
verbose "No relocs found in $binary_file"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if { ![regexp "\\(\\)" [file_contents readelf.out]] } {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
set fails 0
|
||||||
|
|
||||||
|
# Create the object files, libraries and executables.
|
||||||
|
if ![ld_compile "$CC -c -shared -fPIC" "$srcdir/$subdir/prog.c" "tmpdir/shared_prog.o"] {
|
||||||
|
fail "Could not create a shared object file"
|
||||||
|
set fails [expr $fails + 1]
|
||||||
|
}
|
||||||
|
if ![ld_compile "$CC -c -static" "$srcdir/$subdir/prog.c" "tmpdir/static_prog.o"] {
|
||||||
|
fail "Could not create a static object file"
|
||||||
|
set fails [expr $fails + 1]
|
||||||
|
}
|
||||||
|
if ![ld_compile "$CC -c -shared -fPIC -DWITH_IFUNC" "$srcdir/$subdir/lib.c" "tmpdir/shared_ifunc.o"] {
|
||||||
|
fail "Could not create an object file containing an IFUNC symbol"
|
||||||
|
set fails [expr $fails + 1]
|
||||||
|
}
|
||||||
|
if ![ld_compile "$CC -c -static -DWITH_IFUNC" "$srcdir/$subdir/lib.c" "tmpdir/static_ifunc.o"] {
|
||||||
|
fail "Could not create a static object file containing an IFUNC symbol"
|
||||||
|
set fails [expr $fails + 1]
|
||||||
|
}
|
||||||
|
if ![ld_compile "$CC -c -static -DWITHOUT_IFUNC" "$srcdir/$subdir/lib.c" "tmpdir/static_noifunc.o"] {
|
||||||
|
fail "Could not create an ordinary static object file"
|
||||||
|
set fails [expr $fails + 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if { $fails != 0 } {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ![ld_simple_link $ld "tmpdir/libshared_ifunc.so" "-shared tmpdir/shared_ifunc.o"] {
|
||||||
|
fail "Could not create a shared library containing an IFUNC symbol"
|
||||||
|
set fails [expr $fails + 1]
|
||||||
|
}
|
||||||
|
if ![ar_simple_create $ar "" "tmpdir/libifunc.a" "tmpdir/static_ifunc.o"] {
|
||||||
|
fail "Could not create a static library containing an IFUNC symbol"
|
||||||
|
set fails [expr $fails + 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if { $fails != 0 } {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ![default_ld_link $ld "tmpdir/dynamic_prog" "-Ltmpdir tmpdir/shared_prog.o -Bdynamic -lshared_ifunc -rpath ./tmpdir"] {
|
||||||
|
fail "Could not link a dynamic executable"
|
||||||
|
set fails [expr $fails + 1]
|
||||||
|
}
|
||||||
|
if ![default_ld_link $ld "tmpdir/static_prog" "-Ltmpdir tmpdir/static_prog.o -lifunc"] {
|
||||||
|
fail "Could not link a static executable"
|
||||||
|
set fails [expr $fails + 1]
|
||||||
|
}
|
||||||
|
if ![default_ld_link $ld "tmpdir/static_nonifunc_prog" "-Ltmpdir tmpdir/static_prog.o tmpdir/static_noifunc.o"] {
|
||||||
|
fail "Could not link a non-ifunc using static executable"
|
||||||
|
set fails [expr $fails + 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if { $fails == 0 } {
|
||||||
|
pass "Building ifunc binaries"
|
||||||
|
set fails 0
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check the executables.
|
||||||
|
#
|
||||||
|
# The linked ifunc using executables should have an OSABI field of LINUX
|
||||||
|
# The linked non-ifunc using executable should have an OSABI field of NONE (aka System V).
|
||||||
|
|
||||||
|
if {! [check_osabi tmpdir/static_prog {UNIX - Linux}]} {
|
||||||
|
fail "Static ifunc-using executable does not have an OS/ABI field of LINUX"
|
||||||
|
set fails [expr $fails + 1]
|
||||||
|
}
|
||||||
|
if {! [check_osabi tmpdir/dynamic_prog {UNIX - Linux}]} {
|
||||||
|
fail "Dynamic ifunc-using executable does not have an OS/ABI field of LINUX"
|
||||||
|
set fails [expr $fails + 1]
|
||||||
|
}
|
||||||
|
if {! [check_osabi tmpdir/static_nonifunc_prog {UNIX - System V}]} {
|
||||||
|
fail "Static non-ifunc-using executable does not have an OS/ABI field of System V"
|
||||||
|
set fails [expr $fails + 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
# The linked ifunc using executables should contain an IFUNC symbol,
|
||||||
|
# The non-ifunc using executable should not.
|
||||||
|
|
||||||
|
if {[contains_ifunc_symbol tmpdir/static_prog] != 1} {
|
||||||
|
fail "Static ifunc-using executable does not contain an IFUNC symbol"
|
||||||
|
set fails [expr $fails + 1]
|
||||||
|
}
|
||||||
|
if {[contains_ifunc_symbol tmpdir/dynamic_prog] != 1} {
|
||||||
|
fail "Dynamic ifunc-using executable does not contain an IFUNC symbol"
|
||||||
|
set fails [expr $fails + 1]
|
||||||
|
}
|
||||||
|
if {[contains_ifunc_symbol tmpdir/static_nonifunc_prog] != 0} {
|
||||||
|
fail "Static non-ifunc-using executable contains an IFUNC symbol"
|
||||||
|
set fails [expr $fails + 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
# The linked ifunc using executablea should contain a dynamic reloc referencing the IFUNC symbol.
|
||||||
|
# (Even the static executable which should have a dynamic section created for it).
|
||||||
|
# The non-ifunc using executable should not.
|
||||||
|
|
||||||
|
if {[contains_ifunc_reloc tmpdir/static_prog] != 1} {
|
||||||
|
fail "Static ifunc-using executable does not contain a reloc against an IFUNC symbol"
|
||||||
|
set fails [expr $fails + 1]
|
||||||
|
}
|
||||||
|
if {[contains_ifunc_reloc tmpdir/dynamic_prog] != 1} {
|
||||||
|
fail "Dynamic ifunc-using executable does not contain a reloc against an IFUNC symbol"
|
||||||
|
set fails [expr $fails + 1]
|
||||||
|
}
|
||||||
|
if {[contains_ifunc_reloc tmpdir/static_nonifunc_prog] == 1} {
|
||||||
|
fail "Static non-ifunc-using executable contains a reloc against an IFUNC symbol!"
|
||||||
|
set fails [expr $fails + 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if { $fails == 0 } {
|
||||||
|
pass "Checking ifunc binaries"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Clean up, unless we are being verbose, in which case we leave the files available.
|
||||||
|
if { $verbose < 1 } {
|
||||||
|
remote_file host delete "tmpdir/shared_prog.o"
|
||||||
|
remote_file host delete "tmpdir/static_prog.o"
|
||||||
|
remote_file host delete "tmpdir/shared_ifunc.o"
|
||||||
|
remote_file host delete "tmpdir/static_ifunc.o"
|
||||||
|
remote_file host delete "tmpdir/static_noifunc.o"
|
||||||
|
remote_file host delete "tmpdir/libshared_ifunc.so"
|
||||||
|
remote_file host delete "tmpdir/libifunc.a"
|
||||||
|
remote_file host delete "tmpdir/dynamic_prog"
|
||||||
|
remote_file host delete "tmpdir/static_prog"
|
||||||
|
remote_file host delete "tmpdir/static_nonifunc_prog"
|
||||||
|
}
|
26
ld/testsuite/ld-ifunc/lib.c
Normal file
26
ld/testsuite/ld-ifunc/lib.c
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
int
|
||||||
|
library_func1 (void)
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int global = 1;
|
||||||
|
|
||||||
|
#ifdef WITH_IFUNC
|
||||||
|
|
||||||
|
static int minus_one (void) { return -1; }
|
||||||
|
static int zero (void) { return 0; }
|
||||||
|
|
||||||
|
void * library_func2_ifunc (void) __asm__ ("library_func2");
|
||||||
|
void * library_func2_ifunc (void) { return global ? minus_one : zero ; }
|
||||||
|
__asm__(".type library_func2, %gnu_indirect_function");
|
||||||
|
|
||||||
|
#else /* WITHOUT_IFUNC */
|
||||||
|
|
||||||
|
int
|
||||||
|
library_func2 (void)
|
||||||
|
{
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
46
ld/testsuite/ld-ifunc/prog.c
Normal file
46
ld/testsuite/ld-ifunc/prog.c
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
extern int printf (const char *, ...);
|
||||||
|
|
||||||
|
extern int library_func1 (void);
|
||||||
|
extern int library_func2 (void);
|
||||||
|
extern int global;
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
int res = -1;
|
||||||
|
|
||||||
|
res += library_func1 ();
|
||||||
|
res += library_func2 ();
|
||||||
|
|
||||||
|
switch (res)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
if (global)
|
||||||
|
printf ("ifunc working correctly\n");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf ("wrong value returned by library_func2\n");
|
||||||
|
res = -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
if (global)
|
||||||
|
printf ("wrong value returned by library_func2\n");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf ("ifunc working correctly\n");
|
||||||
|
res = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
printf ("non-ifunc testcase\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
printf ("ifunc function not evaluated at run-time, res = %x\n", res);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
Loading…
Reference in a new issue