binutils/binutils-2.19.51.0.2-ifunc....

1069 lines
35 KiB
Diff

diff -rcp ../delme/binutils-2.19.51.0.2/bfd/bfd-in2.h ./bfd/bfd-in2.h
*** ../delme/binutils-2.19.51.0.2/bfd/bfd-in2.h 2009-02-04 18:21:50.000000000 +0000
--- ./bfd/bfd-in2.h 2009-03-05 11:59:49.000000000 +0000
*************** typedef struct bfd_symbol
*** 4568,4573 ****
--- 4568,4579 ----
/* 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
diff -rcp ../delme/binutils-2.19.51.0.2/bfd/elf32-i386.c ./bfd/elf32-i386.c
*** ../delme/binutils-2.19.51.0.2/bfd/elf32-i386.c 2009-02-04 18:21:50.000000000 +0000
--- ./bfd/elf32-i386.c 2009-04-08 16:11:48.000000000 +0100
*************** elf_i386_tls_transition (struct bfd_link
*** 1206,1211 ****
--- 1206,1230 ----
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. */
*************** elf_i386_check_relocs (bfd *abfd,
*** 1483,1488 ****
--- 1502,1513 ----
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
*************** allocate_dynrelocs (struct elf_link_hash
*** 1831,1836 ****
--- 1856,1862 ----
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;
*************** allocate_dynrelocs (struct elf_link_hash
*** 2052,2057 ****
--- 2078,2093 ----
}
}
}
+ 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
*************** allocate_dynrelocs (struct elf_link_hash
*** 2090,2096 ****
{
asection *sreloc;
! sreloc = elf_section_data (p->sec)->sreloc;
BFD_ASSERT (sreloc != NULL);
sreloc->size += p->count * sizeof (Elf32_External_Rel);
--- 2126,2135 ----
{
asection *sreloc;
! if (use_indirect_section)
! sreloc = elf_section_data (p->sec)->indirect_relocs;
! else
! sreloc = elf_section_data (p->sec)->sreloc;
BFD_ASSERT (sreloc != NULL);
sreloc->size += p->count * sizeof (Elf32_External_Rel);
*************** elf_i386_relocate_section (bfd *output_b
*** 2894,2899 ****
--- 2933,2944 ----
|| 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
*************** elf_i386_relocate_section (bfd *output_b
*** 2942,2948 ****
outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
}
! sreloc = elf_section_data (input_section)->sreloc;
BFD_ASSERT (sreloc != NULL && sreloc->contents != NULL);
--- 2987,3002 ----
outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
}
! 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);
*************** elf_i386_hash_symbol (struct elf_link_ha
*** 4068,4073 ****
--- 4122,4146 ----
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,
+ struct bfd_link_info *info,
+ Elf_Internal_Sym *sym,
+ const char **namep,
+ flagword *flagsp,
+ asection **secp,
+ bfd_vma *valp)
+ {
+ if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+ elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+
+ return _bfd_elf_add_sharable_symbol (abfd, info, sym, namep, flagsp,
+ secp, valp);
+ }
+
#define TARGET_LITTLE_SYM bfd_elf32_i386_vec
#define TARGET_LITTLE_NAME "elf32-i386"
#define ELF_ARCH bfd_arch_i386
*************** elf_i386_hash_symbol (struct elf_link_ha
*** 4113,4121 ****
#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 \
! _bfd_elf_add_sharable_symbol
! #define elf_backend_section_from_bfd_section \
_bfd_elf_sharable_section_from_bfd_section
#define elf_backend_symbol_processing \
_bfd_elf_sharable_symbol_processing
--- 4186,4194 ----
#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
!
! #define elf_backend_section_from_bfd_section \
_bfd_elf_sharable_section_from_bfd_section
#define elf_backend_symbol_processing \
_bfd_elf_sharable_symbol_processing
*************** elf_i386_hash_symbol (struct elf_link_ha
*** 4128,4133 ****
--- 4201,4209 ----
#define elf_backend_merge_symbol \
_bfd_elf_sharable_merge_symbol
+ #undef elf_backend_post_process_headers
+ #define elf_backend_post_process_headers _bfd_elf_set_osabi
+
#include "elf32-target.h"
/* FreeBSD support. */
*************** elf_i386_hash_symbol (struct elf_link_ha
*** 4144,4158 ****
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_Internal_Ehdr *i_ehdrp;
!
! 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);
--- 4220,4229 ----
executables and (for simplicity) also all other object files. */
static void
! elf_i386_post_process_headers (bfd *abfd, struct bfd_link_info *info)
{
! _bfd_elf_set_osabi (abfd, info);
#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);
diff -rcp ../delme/binutils-2.19.51.0.2/bfd/elf64-x86-64.c ./bfd/elf64-x86-64.c
*** ../delme/binutils-2.19.51.0.2/bfd/elf64-x86-64.c 2009-02-04 18:21:50.000000000 +0000
--- ./bfd/elf64-x86-64.c 2009-04-08 16:07:11.000000000 +0100
*************** static reloc_howto_type x86_64_elf_howto
*** 161,166 ****
--- 161,172 ----
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
{
*************** elf64_x86_64_tls_transition (struct bfd_
*** 987,992 ****
--- 993,1017 ----
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. */
*************** elf64_x86_64_check_relocs (bfd *abfd, st
*** 1013,1019 ****
sym_hashes = elf_sym_hashes (abfd);
sreloc = NULL;
!
rel_end = relocs + sec->reloc_count;
for (rel = relocs; rel < rel_end; rel++)
{
--- 1038,1044 ----
sym_hashes = elf_sym_hashes (abfd);
sreloc = NULL;
!
rel_end = relocs + sec->reloc_count;
for (rel = relocs; rel < rel_end; rel++)
{
*************** elf64_x86_64_check_relocs (bfd *abfd, st
*** 1269,1281 ****
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))
|| (h != NULL
&& (! SYMBOLIC_BIND (info, h)
|| h->root.type == bfd_link_hash_defweak
--- 1294,1302 ----
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
! && (! IS_X86_64_PCREL_TYPE (r_type)
|| (h != NULL
&& (! SYMBOLIC_BIND (info, h)
|| h->root.type == bfd_link_hash_defweak
*************** elf64_x86_64_check_relocs (bfd *abfd, st
*** 1303,1308 ****
--- 1324,1335 ----
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
*************** elf64_x86_64_check_relocs (bfd *abfd, st
*** 1334,1339 ****
--- 1361,1367 ----
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)
*************** elf64_x86_64_check_relocs (bfd *abfd, st
*** 1346,1355 ****
}
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)
p->pc_count += 1;
}
break;
--- 1374,1380 ----
}
p->count += 1;
! if (IS_X86_64_PCREL_TYPE (r_type))
p->pc_count += 1;
}
break;
*************** allocate_dynrelocs (struct elf_link_hash
*** 1666,1671 ****
--- 1691,1697 ----
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;
*************** allocate_dynrelocs (struct elf_link_hash
*** 1744,1750 ****
&& !info->shared
&& h->dynindx == -1
&& elf64_x86_64_hash_entry (h)->tls_type == GOT_TLS_IE)
! h->got.offset = (bfd_vma) -1;
else if (h->got.refcount > 0)
{
asection *s;
--- 1770,1778 ----
&& !info->shared
&& h->dynindx == -1
&& elf64_x86_64_hash_entry (h)->tls_type == GOT_TLS_IE)
! {
! h->got.offset = (bfd_vma) -1;
! }
else if (h->got.refcount > 0)
{
asection *s;
*************** allocate_dynrelocs (struct elf_link_hash
*** 1843,1855 ****
/* 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;
! }
}
}
else if (ELIMINATE_COPY_RELOCS)
{
/* For the non-shared case, discard space for relocs against
--- 1871,1891 ----
/* Make sure undefined weak symbols are output as a dynamic
symbol in PIEs. */
else if (h->dynindx == -1
! && ! 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
*************** allocate_dynrelocs (struct elf_link_hash
*** 1866,1876 ****
/* 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;
! }
/* If that succeeded, we know we'll be keeping all the
relocs. */
--- 1902,1910 ----
/* 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
! && ! bfd_elf_link_record_dynamic_symbol (info, h))
! return FALSE;
/* If that succeeded, we know we'll be keeping all the
relocs. */
*************** allocate_dynrelocs (struct elf_link_hash
*** 1888,1894 ****
{
asection * sreloc;
! sreloc = elf_section_data (p->sec)->sreloc;
BFD_ASSERT (sreloc != NULL);
--- 1922,1931 ----
{
asection * sreloc;
! if (use_indirect_section)
! sreloc = elf_section_data (p->sec)->indirect_relocs;
! else
! sreloc = elf_section_data (p->sec)->sreloc;
BFD_ASSERT (sreloc != NULL);
*************** elf64_x86_64_relocate_section (bfd *outp
*** 2691,2701 ****
&& (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)))
|| (ELIMINATE_COPY_RELOCS
&& !info->shared
&& h != NULL
--- 2728,2741 ----
&& (h == NULL
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak)
! && (! 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
*************** elf64_x86_64_relocate_section (bfd *outp
*** 2735,2747 ****
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))
{
outrel.r_info = ELF64_R_INFO (h->dynindx, r_type);
outrel.r_addend = rel->r_addend;
--- 2775,2784 ----
become local. */
else if (h != NULL
&& h->dynindx != -1
! && (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;
*************** elf64_x86_64_relocate_section (bfd *outp
*** 2790,2796 ****
}
}
! sreloc = elf_section_data (input_section)->sreloc;
BFD_ASSERT (sreloc != NULL && sreloc->contents != NULL);
--- 2827,2842 ----
}
}
! 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);
*************** elf64_x86_64_add_symbol_hook (bfd *abfd,
*** 3712,3717 ****
--- 3758,3766 ----
break;
}
+ if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+ elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+
return _bfd_elf_add_sharable_symbol (abfd, info, sym, namep, flagsp,
secp, valp);
}
*************** static const struct bfd_elf_special_sect
*** 3958,3963 ****
--- 4007,4015 ----
#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. */
*************** static const struct bfd_elf_special_sect
*** 3970,3978 ****
#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
--- 4022,4027 ----
diff -rcp ../delme/binutils-2.19.51.0.2/bfd/elf-bfd.h ./bfd/elf-bfd.h
*** ../delme/binutils-2.19.51.0.2/bfd/elf-bfd.h 2009-02-04 18:21:50.000000000 +0000
--- ./bfd/elf-bfd.h 2009-03-13 16:48:34.000000000 +0000
*************** struct bfd_elf_section_data
*** 1294,1299 ****
--- 1294,1302 ----
/* 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;
*************** struct elf_obj_tdata
*** 1556,1561 ****
--- 1559,1569 ----
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;
*************** extern int _bfd_elf_obj_attrs_arg_type (
*** 2158,2163 ****
--- 2166,2174 ----
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;
diff -rcp ../delme/binutils-2.19.51.0.2/bfd/elf.c ./bfd/elf.c
*** ../delme/binutils-2.19.51.0.2/bfd/elf.c 2009-02-04 18:21:50.000000000 +0000
--- ./bfd/elf.c 2009-03-13 16:49:37.000000000 +0000
*************** Unable to find equivalent output section
*** 6508,6513 ****
--- 6508,6515 ----
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)
*************** _bfd_elf_set_osabi (bfd * abfd,
*** 9014,9028 ****
i_ehdrp = elf_elfheader (abfd);
i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi;
}
/* 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. */
bfd_boolean
_bfd_elf_is_function_type (unsigned int type)
{
! return (type == STT_FUNC);
}
--- 9016,9038 ----
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 or STT_GNU_IFUNC. */
bfd_boolean
_bfd_elf_is_function_type (unsigned int type)
{
! return (type == STT_FUNC
! || type == STT_GNU_IFUNC);
}
diff -rcp ../delme/binutils-2.19.51.0.2/bfd/elfcode.h ./bfd/elfcode.h
*** ../delme/binutils-2.19.51.0.2/bfd/elfcode.h 2009-04-08 16:23:16.000000000 +0100
--- ./bfd/elfcode.h 2009-03-05 11:54:03.000000000 +0000
*************** elf_slurp_symbol_table (bfd *abfd, asymb
*** 1371,1376 ****
--- 1371,1379 ----
case STT_SRELC:
sym->symbol.flags |= BSF_SRELC;
break;
+ case STT_GNU_IFUNC:
+ sym->symbol.flags |= BSF_GNU_INDIRECT_FUNCTION;
+ break;
}
if (dynamic)
diff -rcp ../delme/binutils-2.19.51.0.2/bfd/elflink.c ./bfd/elflink.c
*** ../delme/binutils-2.19.51.0.2/bfd/elflink.c 2009-02-04 18:21:50.000000000 +0000
--- ./bfd/elflink.c 2009-03-05 11:54:03.000000000 +0000
*************** _bfd_elf_adjust_dynamic_symbol (struct e
*** 2776,2781 ****
--- 2776,2788 ----
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;
*************** _bfd_elf_sharable_merge_symbol
*** 12806,12808 ****
--- 12813,12882 ----
return TRUE;
}
+
+ /* 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;
+ }
diff -rcp ../delme/binutils-2.19.51.0.2/bfd/syms.c ./bfd/syms.c
*** ../delme/binutils-2.19.51.0.2/bfd/syms.c 2009-02-04 18:14:57.000000000 +0000
--- ./bfd/syms.c 2009-03-05 11:54:05.000000000 +0000
*************** CODE_FRAGMENT
*** 297,302 ****
--- 297,308 ----
. {* 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
*************** bfd_print_symbol_vandf (bfd *abfd, void
*** 483,489 ****
(type & BSF_WEAK) ? 'w' : ' ',
(type & BSF_CONSTRUCTOR) ? 'C' : ' ',
(type & BSF_WARNING) ? 'W' : ' ',
! (type & BSF_INDIRECT) ? 'I' : ' ',
(type & BSF_DEBUGGING) ? 'd' : (type & BSF_DYNAMIC) ? 'D' : ' ',
((type & BSF_FUNCTION)
? 'F'
--- 489,495 ----
(type & BSF_WEAK) ? 'w' : ' ',
(type & BSF_CONSTRUCTOR) ? 'C' : ' ',
(type & BSF_WARNING) ? 'W' : ' ',
! (type & BSF_INDIRECT) ? 'I' : (type & BSF_GNU_INDIRECT_FUNCTION) ? 'i' : ' ',
(type & BSF_DEBUGGING) ? 'd' : (type & BSF_DYNAMIC) ? 'D' : ' ',
((type & BSF_FUNCTION)
? 'F'
*************** bfd_decode_symclass (asymbol *symbol)
*** 669,674 ****
--- 675,682 ----
}
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
diff -rcp ../delme/binutils-2.19.51.0.2/binutils/readelf.c ./binutils/readelf.c
*** ../delme/binutils-2.19.51.0.2/binutils/readelf.c 2009-02-04 18:21:50.000000000 +0000
--- ./binutils/readelf.c 2009-03-05 11:53:48.000000000 +0000
*************** dump_relocations (FILE *file,
*** 1247,1255 ****
printf (" ");
- print_vma (psym->st_value, LONG_HEX);
! printf (is_32bit_elf ? " " : " ");
if (psym->st_name == 0)
{
--- 1247,1285 ----
printf (" ");
! if (ELF_ST_TYPE (psym->st_info) == STT_GNU_IFUNC)
! {
! const char * name;
! unsigned int len;
! unsigned int width = is_32bit_elf ? 8 : 14;
!
! /* 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)
{
*************** get_symbol_type (unsigned int type)
*** 7166,7171 ****
--- 7196,7207 ----
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
diff -rcp ../delme/binutils-2.19.51.0.2/elfcpp/elfcpp.h ./elfcpp/elfcpp.h
*** ../delme/binutils-2.19.51.0.2/elfcpp/elfcpp.h 2009-02-04 18:14:52.000000000 +0000
--- ./elfcpp/elfcpp.h 2009-03-05 11:53:39.000000000 +0000
*************** enum STT
*** 476,481 ****
--- 476,482 ----
STT_COMMON = 5,
STT_TLS = 6,
STT_LOOS = 10,
+ STT_GNU_IFUNC = 10,
STT_HIOS = 12,
STT_LOPROC = 13,
STT_HIPROC = 15,
diff -rcp ../delme/binutils-2.19.51.0.2/gas/config/obj-elf.c ./gas/config/obj-elf.c
*** ../delme/binutils-2.19.51.0.2/gas/config/obj-elf.c 2009-02-04 18:21:50.000000000 +0000
--- ./gas/config/obj-elf.c 2009-03-05 11:53:52.000000000 +0000
*************** obj_elf_type (int ignore ATTRIBUTE_UNUSE
*** 1706,1711 ****
--- 1706,1725 ----
}
}
}
+ 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)
;
diff -rcp ../delme/binutils-2.19.51.0.2/gas/config/tc-i386.c ./gas/config/tc-i386.c
*** ../delme/binutils-2.19.51.0.2/gas/config/tc-i386.c 2009-02-04 18:14:55.000000000 +0000
--- ./gas/config/tc-i386.c 2009-03-05 11:53:53.000000000 +0000
*************** tc_i386_fix_adjustable (fixS *fixP ATTRI
*** 2499,2504 ****
--- 2499,2508 ----
|| 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;
}
diff -rcp ../delme/binutils-2.19.51.0.2/gas/doc/as.texinfo ./gas/doc/as.texinfo
*** ../delme/binutils-2.19.51.0.2/gas/doc/as.texinfo 2009-01-06 17:48:21.000000000 +0000
--- ./gas/doc/as.texinfo 2009-03-05 11:53:52.000000000 +0000
*************** The types supported are:
*** 6277,6282 ****
--- 6277,6287 ----
@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.
diff -rcp ../delme/binutils-2.19.51.0.2/gas/NEWS ./gas/NEWS
*** ../delme/binutils-2.19.51.0.2/gas/NEWS 2009-01-06 17:48:20.000000000 +0000
--- ./gas/NEWS 2009-03-05 11:54:03.000000000 +0000
***************
*** 1,5 ****
--- 1,10 ----
-*- text -*-
+ * 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:
diff -rcp ../delme/binutils-2.19.51.0.2/gas/testsuite/gas/elf/type.e ./gas/testsuite/gas/elf/type.e
*** ../delme/binutils-2.19.51.0.2/gas/testsuite/gas/elf/type.e 2007-11-03 20:40:37.000000000 +0000
--- ./gas/testsuite/gas/elf/type.e 2009-03-05 11:53:56.000000000 +0000
***************
*** 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
--- 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+1 1 (COMMON|OBJECT) GLOBAL DEFAULT COM common
diff -rcp ../delme/binutils-2.19.51.0.2/gas/testsuite/gas/elf/type.s ./gas/testsuite/gas/elf/type.s
*** ../delme/binutils-2.19.51.0.2/gas/testsuite/gas/elf/type.s 2007-11-03 20:40:37.000000000 +0000
--- ./gas/testsuite/gas/elf/type.s 2009-03-05 11:53:56.000000000 +0000
***************
*** 3,8 ****
--- 3,12 ----
.type function,%function
function:
.byte 0x0
+ .size indirect_function,1
+ .type indirect_function,%gnu_indirect_function
+ indirect_function:
+ .byte 0x0
.data
.type object,%object
.size object,1
diff -rcp ../delme/binutils-2.19.51.0.2/include/elf/common.h ./include/elf/common.h
*** ../delme/binutils-2.19.51.0.2/include/elf/common.h 2009-02-04 18:21:50.000000000 +0000
--- ./include/elf/common.h 2009-03-05 11:53:39.000000000 +0000
***************
*** 549,554 ****
--- 549,555 ----
#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 /* Application-specific semantics */
#define STT_HIPROC 15 /* Application-specific semantics */
diff -rcp ../delme/binutils-2.19.51.0.2/ld/NEWS ./ld/NEWS
*** ../delme/binutils-2.19.51.0.2/ld/NEWS 2009-04-08 16:22:56.000000000 +0100
--- ./ld/NEWS 2009-03-05 11:53:45.000000000 +0000
***************
*** 1,5 ****
--- 1,9 ----
-*- text -*-
+ * 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