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
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
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)
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
10
bfd/syms.c
10
bfd/syms.c
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
5
gas/NEWS
5
gas/NEWS
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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+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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
4
ld/NEWS
4
ld/NEWS
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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"
|
||||
}
|
|
@ -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
|
|
@ -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 New Issue