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:
Nick Clifton 2009-04-30 15:47:13 +00:00
parent b22a5a4185
commit d8045f234d
33 changed files with 824 additions and 70 deletions

View file

@ -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>
* elf32-arm.c (elf32_arm_check_relocs): Give errors for absolute

View file

@ -4608,6 +4608,12 @@ typedef struct bfd_symbol
/* This symbol was created by bfd_get_synthetic_symtab. */
#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;
/* A pointer to the section to which this symbol is

View file

@ -1297,6 +1297,9 @@ struct bfd_elf_section_data
/* A pointer to the bfd section used for dynamic relocs. */
asection *sreloc;
/* A pointer to the bfd section used for dynamic relocs against ifunc symbols. */
asection *indirect_relocs;
union {
/* Group name, if this section is a member of a group. */
const char *name;
@ -1559,6 +1562,11 @@ struct elf_obj_tdata
bfd_size_type build_id_size;
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
specific extensions to this structure. */
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 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. */
extern asection _bfd_elf_large_com_section;

View file

@ -6399,6 +6399,8 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"),
if ((flags & BSF_THREAD_LOCAL) != 0)
type = STT_TLS;
else if ((flags & BSF_GNU_INDIRECT_FUNCTION) != 0)
type = STT_GNU_IFUNC;
else if ((flags & BSF_FUNCTION) != 0)
type = STT_FUNC;
else if ((flags & BSF_OBJECT) != 0)
@ -8977,15 +8979,23 @@ _bfd_elf_set_osabi (bfd * abfd,
i_ehdrp = elf_elfheader (abfd);
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.
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_elf_is_function_type (unsigned int type)
{
return (type == STT_FUNC);
return (type == STT_FUNC
|| type == STT_GNU_IFUNC);
}

View file

@ -1196,6 +1196,25 @@ elf_i386_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_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. */
@ -1473,6 +1492,12 @@ elf_i386_check_relocs (bfd *abfd,
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
@ -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_entry *eh;
struct elf_i386_dyn_relocs *p;
bfd_boolean use_indirect_section = FALSE;
if (h->root.type == bfd_link_hash_indirect)
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)
{
/* 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;
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);
@ -2877,6 +2916,12 @@ elf_i386_relocate_section (bfd *output_bfd,
|| 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
@ -2925,7 +2970,16 @@ elf_i386_relocate_section (bfd *output_bfd,
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);
@ -4045,6 +4099,24 @@ elf_i386_hash_symbol (struct elf_link_hash_entry *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_NAME "elf32-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)
#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"
@ -4106,15 +4181,10 @@ elf_i386_hash_symbol (struct elf_link_hash_entry *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);
@ -4122,10 +4192,12 @@ elf_i386_post_process_headers (bfd *abfd,
}
#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. */

View file

@ -161,6 +161,12 @@ static reloc_howto_type x86_64_elf_howto_table[] =
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. */
struct elf_reloc_map
{
@ -977,6 +983,25 @@ 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_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. */
@ -1003,7 +1028,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
sym_hashes = elf_sym_hashes (abfd);
sreloc = NULL;
rel_end = relocs + sec->reloc_count;
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
dynamic library if we manage to avoid copy relocs for the
symbol. */
if ((info->shared
&& (sec->flags & SEC_ALLOC) != 0
&& (((r_type != R_X86_64_PC8)
&& (r_type != R_X86_64_PC16)
&& (r_type != R_X86_64_PC32)
&& (r_type != R_X86_64_PC64))
&& (! IS_X86_64_PCREL_TYPE (r_type)
|| (h != NULL
&& (! SYMBOLIC_BIND (info, h)
|| 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)
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
@ -1324,6 +1351,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
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)
@ -1336,10 +1364,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
}
p->count += 1;
if (r_type == R_X86_64_PC8
|| r_type == R_X86_64_PC16
|| r_type == R_X86_64_PC32
|| r_type == R_X86_64_PC64)
if (IS_X86_64_PCREL_TYPE (r_type))
p->pc_count += 1;
}
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_entry *eh;
struct elf64_x86_64_dyn_relocs *p;
bfd_boolean use_indirect_section = FALSE;
if (h->root.type == bfd_link_hash_indirect)
return TRUE;
@ -1728,7 +1754,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
&& !info->shared
&& h->dynindx == -1
&& 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)
{
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
symbol in PIEs. */
else if (h->dynindx == -1
&& !h->forced_local)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
}
&& ! h->forced_local
&& ! bfd_elf_link_record_dynamic_symbol (info, h))
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)
{
/* 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.
Undefined weak syms won't yet be marked as dynamic. */
if (h->dynindx == -1
&& !h->forced_local)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
}
&& ! h->forced_local
&& ! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
/* If that succeeded, we know we'll be keeping all the
relocs. */
@ -1872,7 +1906,10 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
{
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);
@ -2674,11 +2711,14 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
&& (h == NULL
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak)
&& ((r_type != R_X86_64_PC8
&& r_type != R_X86_64_PC16
&& r_type != R_X86_64_PC32
&& r_type != R_X86_64_PC64)
|| !SYMBOL_CALLS_LOCAL (info, h)))
&& (! IS_X86_64_PCREL_TYPE (r_type)
|| ! SYMBOL_CALLS_LOCAL (info, h)))
|| (! info->shared
&& h != NULL
&& 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
&& !info->shared
&& h != NULL
@ -2718,13 +2758,10 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
become local. */
else if (h != NULL
&& h->dynindx != -1
&& (r_type == R_X86_64_PC8
|| r_type == R_X86_64_PC16
|| r_type == R_X86_64_PC32
|| r_type == R_X86_64_PC64
|| !info->shared
|| !SYMBOLIC_BIND (info, h)
|| !h->def_regular))
&& (IS_X86_64_PCREL_TYPE (r_type)
|| ! info->shared
|| ! SYMBOLIC_BIND (info, h)
|| ! h->def_regular))
{
outrel.r_info = ELF64_R_INFO (h->dynindx, r_type);
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);
loc = sreloc->contents;
@ -3660,11 +3706,12 @@ elf64_x86_64_section_from_shdr (bfd *abfd,
static bfd_boolean
elf64_x86_64_add_symbol_hook (bfd *abfd,
struct bfd_link_info *info ATTRIBUTE_UNUSED,
struct bfd_link_info *info,
Elf_Internal_Sym *sym,
const char **namep ATTRIBUTE_UNUSED,
flagword *flagsp ATTRIBUTE_UNUSED,
asection **secp, bfd_vma *valp)
asection **secp,
bfd_vma *valp)
{
asection *lcomm;
@ -3687,6 +3734,10 @@ elf64_x86_64_add_symbol_hook (bfd *abfd,
*valp = sym->st_size;
break;
}
if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
return TRUE;
}
@ -3914,6 +3965,9 @@ static const struct bfd_elf_special_section
#define elf_backend_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"
/* FreeBSD support. */
@ -3926,9 +3980,6 @@ static const struct bfd_elf_special_section
#undef ELF_OSABI
#define ELF_OSABI ELFOSABI_FREEBSD
#undef elf_backend_post_process_headers
#define elf_backend_post_process_headers _bfd_elf_set_osabi
#undef elf64_bed
#define elf64_bed elf64_x86_64_fbsd_bed

View file

@ -1311,6 +1311,9 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic)
case STT_SRELC:
sym->symbol.flags |= BSF_SRELC;
break;
case STT_GNU_IFUNC:
sym->symbol.flags |= BSF_GNU_INDIRECT_FUNCTION;
break;
}
if (dynamic)

View file

@ -2749,6 +2749,13 @@ _bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data)
dynobj = elf_hash_table (eif->info)->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))
{
eif->failed = TRUE;
@ -12533,3 +12540,70 @@ _bfd_elf_make_dynamic_reloc_section (asection * 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;
}

View file

@ -297,6 +297,12 @@ CODE_FRAGMENT
. {* This symbol was created by bfd_get_synthetic_symtab. *}
.#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;
.
. {* 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_CONSTRUCTOR) ? 'C' : ' ',
(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_FUNCTION)
? 'F'
@ -669,6 +675,8 @@ bfd_decode_symclass (asymbol *symbol)
}
if (bfd_is_ind_section (symbol->section))
return 'I';
if (symbol->flags & BSF_GNU_INDIRECT_FUNCTION)
return 'i';
if (symbol->flags & BSF_WEAK)
{
/* If weak, determine if it's specifically an object

View file

@ -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>
* NEWS: Tweak verilog support description.

View file

@ -1238,9 +1238,38 @@ dump_relocations (FILE * file,
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)
{
@ -6913,6 +6942,12 @@ get_symbol_type (unsigned int type)
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);
}
else

View file

@ -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>
* elfcpp.h (SHT_GNU_INCREMENTAL_INPUTS): Define.

View file

@ -478,6 +478,7 @@ enum STT
STT_COMMON = 5,
STT_TLS = 6,
STT_LOOS = 10,
STT_GNU_IFUNC = 10,
STT_HIOS = 12,
STT_LOPROC = 13,
STT_HIPROC = 15,

View file

@ -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>
* NEWS: Add item about discriminator support.

View file

@ -5,6 +5,11 @@
* 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.
Changes in 2.19:

View file

@ -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
else if ((type = md_elf_symbol_type (typename, sym, elfsym)) != -1)
;

View file

@ -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_ENTRY)
return 0;
if (fixP->fx_addsy != NULL
&& symbol_get_bfdsym (fixP->fx_addsy)->flags & BSF_GNU_INDIRECT_FUNCTION)
return 0;
#endif
return 1;
}

View file

@ -6327,6 +6327,11 @@ The types supported are:
@itemx function
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
@itemx object
Mark the symbol as being a data object.

View file

@ -114,8 +114,20 @@ if { ([istarget "*-*-*elf*"]
run_elf_list_test "section5" "" "-al" "-SW" "| grep \" \\\\.test\\\[0-9\\\]\""
run_dump_test "struct"
run_dump_test "symtab"
run_dump_test "symver"
run_elf_list_test "type" "" "" "-s" "| grep \"1 \\\[FIONTC\\\]\""
run_dump_test "symver"
# 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 "section7"
}

View file

@ -1,5 +1,5 @@
Symbol table '.symtab' contains 6 entries:
Symbol table '.symtab' contains 7 entries:
Num: Value[ ]* Size Type Bind Vis Ndx Name
0: 0+0 0 NOTYPE LOCAL DEFAULT UND
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
4: 0+0 0 SECTION LOCAL DEFAULT 4
5: 0+0 0 NOTYPE LOCAL DEFAULT 4 \$d
6: 0+0 0 SECTION LOCAL DEFAULT 5

View 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

View 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

View file

@ -1,5 +1,6 @@
.: 0+0 1 FUNC LOCAL DEFAULT . function
.: 0+1 1 IFUNC LOCAL DEFAULT . indirect_function
.: 0+0 1 OBJECT LOCAL DEFAULT . 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

View file

@ -2,6 +2,10 @@
.size function,1
.type function,%function
function:
.byte 0x0
.size indirect_function,1
.type indirect_function,%gnu_indirect_function
indirect_function:
.byte 0x0
.data
.type object,%object

View file

@ -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>
* dwarf2.h (DW_LNE_set_discriminator): New enum value.

View file

@ -569,6 +569,7 @@
#define STT_RELC 8 /* Complex relocation expression */
#define STT_SRELC 9 /* Signed Complex relocation expression */
#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_LOPROC 13 /* Processor-specific semantics */
#define STT_HIPROC 15 /* Processor-specific semantics */

View file

@ -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>
* emulparams/elf32moxie.sh (STACK_ADDR): Move default stack

View file

@ -15,6 +15,10 @@
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.
* 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
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

View file

@ -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>
* ld-arm/movw-shared-1.d, ld-arm/movw-shared-1.s,

View file

@ -1,5 +1,5 @@
# 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.
#
@ -26,16 +26,17 @@ proc section_check {} {
global ld
global srcdir
global subdir
# The usage of .lcomm in asm.s is incompatible with ia64 and ppc coff.
if { [istarget ia64-*-*]
|| [istarget powerpc*-*-aix*] || [istarget powerpc-*-beos*]
|| [istarget powerpc*-*-aix*]
|| [istarget powerpc-*-beos*]
|| [istarget rs6000-*-*] } {
return
}
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]} {
unresolved $test
@ -55,15 +56,15 @@ proc section_check {} {
set ldflags "--check-sections -T $srcdir/$subdir/script -e foo"
# 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 [prune_warnings $exec_output]
# Make sure that we got some output from the linker
if [string match "" $exec_output] then {
fail $test
}
}
# Now remove our expected error message
regsub -all ".*: section .data .* overlaps section .text .*" $exec_output "" exec_output
@ -78,5 +79,3 @@ proc section_check {} {
}
section_check

View 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"
}

View 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

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