mirror of
https://sourceware.org/git/glibc.git
synced 2025-07-29 11:41:21 +03:00
Finish IFUNC support for x86 and x86-64.
Add support for the IRELAIVE relocation and IFUNC in static executables.
This commit is contained in:
27
ChangeLog
27
ChangeLog
@ -1,3 +1,30 @@
|
|||||||
|
2009-05-29 H.J. Lu <hongjiu.lu@intel.com>
|
||||||
|
|
||||||
|
* csu/elf-init.c: Include <link.h> and <dl-irel.h> if LIBC_NONSHARED
|
||||||
|
is not defined.
|
||||||
|
(__rela_iplt_start): New declaration.
|
||||||
|
(__rela_iplt_end): Likewise.
|
||||||
|
(__rel_iplt_start): Likewise.
|
||||||
|
(__rel_iplt_end): Likewise.
|
||||||
|
(__libc_csu_init): Process __rela_iplt_start and __rel_iplt_start.
|
||||||
|
* elf/elf.h (R_386_IRELATIVE): New macro.
|
||||||
|
(R_X86_64_IRELATIVE): New macro.
|
||||||
|
(R_386_NUM): Updated.
|
||||||
|
(R_X86_64_NUM): Likewise.
|
||||||
|
* include/libc-symbols.h (libc_ifunc_hidden_def1): New macro.
|
||||||
|
(libc_ifunc_hidden_def): New macro.
|
||||||
|
* sysdeps/generic/dl-irel.h: New file.
|
||||||
|
* sysdeps/i386/dl-irel.h: New file.
|
||||||
|
* sysdeps/x86_64/dl-irel.h: New file.
|
||||||
|
* sysdeps/i386/dl-machine.h (elf_machine_rel): Handle R_386_IRELATIVE.
|
||||||
|
(elf_machine_rela): Check SHN_UNDEF for STT_GNU_IFUNC symbol.
|
||||||
|
Handle R_386_IRELATIVE.
|
||||||
|
(elf_machine_lazy_rel): Handle R_386_IRELATIVE.
|
||||||
|
(elf_machine_lazy_rela): Likewise.
|
||||||
|
* sysdeps/x86_64/dl-machine.h (elf_machine_rela): Handle
|
||||||
|
R_X86_64_IRELATIVE.
|
||||||
|
(elf_machine_lazy_rel): Handle R_X86_64_IRELATIVE.
|
||||||
|
|
||||||
2009-05-31 Ulrich Drepper <drepper@redhat.com>
|
2009-05-31 Ulrich Drepper <drepper@redhat.com>
|
||||||
|
|
||||||
* sysdeps/x86_64/multiarch/init-arch.h: Define COMMON_CPUID_INDEX_1
|
* sysdeps/x86_64/multiarch/init-arch.h: Define COMMON_CPUID_INDEX_1
|
||||||
|
@ -36,6 +36,20 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifndef LIBC_NONSHARED
|
||||||
|
# include <link.h>
|
||||||
|
# include <dl-irel.h>
|
||||||
|
|
||||||
|
# ifdef ELF_MACHINE_IRELA
|
||||||
|
extern const ElfW(Rela) __rela_iplt_start [];
|
||||||
|
extern const ElfW(Rela) __rela_iplt_end [];
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifdef ELF_MACHINE_IREL
|
||||||
|
extern const ElfW(Rel) __rel_iplt_start [];
|
||||||
|
extern const ElfW(Rel) __rel_iplt_end [];
|
||||||
|
# endif
|
||||||
|
#endif /* LIBC_NONSHARED */
|
||||||
|
|
||||||
/* These magic symbols are provided by the linker. */
|
/* These magic symbols are provided by the linker. */
|
||||||
extern void (*__preinit_array_start []) (int, char **, char **)
|
extern void (*__preinit_array_start []) (int, char **, char **)
|
||||||
@ -67,6 +81,22 @@ __libc_csu_init (int argc, char **argv, char **envp)
|
|||||||
the dynamic linker (before initializing any shared object. */
|
the dynamic linker (before initializing any shared object. */
|
||||||
|
|
||||||
#ifndef LIBC_NONSHARED
|
#ifndef LIBC_NONSHARED
|
||||||
|
# ifdef ELF_MACHINE_IRELA
|
||||||
|
{
|
||||||
|
const size_t size = __rela_iplt_end - __rela_iplt_start;
|
||||||
|
for (size_t i = 0; i < size; i++)
|
||||||
|
elf_irela (&__rela_iplt_start [i]);
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifdef ELF_MACHINE_IREL
|
||||||
|
{
|
||||||
|
const size_t size = __rel_iplt_end - __rel_iplt_start;
|
||||||
|
for (size_t i = 0; i < size; i++)
|
||||||
|
elf_irel (&__rel_iplt_start [i]);
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
/* For static executables, preinit happens rights before init. */
|
/* For static executables, preinit happens rights before init. */
|
||||||
{
|
{
|
||||||
const size_t size = __preinit_array_end - __preinit_array_start;
|
const size_t size = __preinit_array_end - __preinit_array_start;
|
||||||
|
@ -1177,8 +1177,9 @@ typedef struct
|
|||||||
pointer to code and to
|
pointer to code and to
|
||||||
argument, returning the TLS
|
argument, returning the TLS
|
||||||
offset for the symbol. */
|
offset for the symbol. */
|
||||||
|
#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */
|
||||||
/* Keep this the last entry. */
|
/* Keep this the last entry. */
|
||||||
#define R_386_NUM 42
|
#define R_386_NUM 43
|
||||||
|
|
||||||
/* SUN SPARC specific definitions. */
|
/* SUN SPARC specific definitions. */
|
||||||
|
|
||||||
@ -2625,8 +2626,9 @@ typedef Elf32_Addr Elf32_Conflict;
|
|||||||
#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS
|
#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS
|
||||||
descriptor. */
|
descriptor. */
|
||||||
#define R_X86_64_TLSDESC 36 /* TLS descriptor. */
|
#define R_X86_64_TLSDESC 36 /* TLS descriptor. */
|
||||||
|
#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */
|
||||||
|
|
||||||
#define R_X86_64_NUM 37
|
#define R_X86_64_NUM 38
|
||||||
|
|
||||||
|
|
||||||
/* AM33 relocations. */
|
/* AM33 relocations. */
|
||||||
|
@ -845,4 +845,21 @@ for linking")
|
|||||||
} \
|
} \
|
||||||
__asm__ (".type " #name ", %gnu_indirect_function");
|
__asm__ (".type " #name ", %gnu_indirect_function");
|
||||||
|
|
||||||
|
#ifdef HAVE_ASM_SET_DIRECTIVE
|
||||||
|
# define libc_ifunc_hidden_def1(local, name) \
|
||||||
|
__asm__ (declare_symbol_alias_1_stringify (ASM_GLOBAL_DIRECTIVE) \
|
||||||
|
" " #local "\n\t" \
|
||||||
|
".hidden " #local "\n\t" \
|
||||||
|
".set " #local ", " #name);
|
||||||
|
#else
|
||||||
|
# define libc_ifunc_hidden_def1(local, name) \
|
||||||
|
__asm__ (declare_symbol_alias_1_stringify (ASM_GLOBAL_DIRECTIVE) \
|
||||||
|
" " #local "\n\t" \
|
||||||
|
".hidden " #local "\n\t" \
|
||||||
|
#local " = " #name);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define libc_ifunc_hidden_def(name) \
|
||||||
|
libc_ifunc_hidden_def1 (__GI_##name, name)
|
||||||
|
|
||||||
#endif /* libc-symbols.h */
|
#endif /* libc-symbols.h */
|
||||||
|
23
sysdeps/generic/dl-irel.h
Normal file
23
sysdeps/generic/dl-irel.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/* Machine-dependent ELF indirect relocation inline functions.
|
||||||
|
Copyright (C) 2009 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library 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
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, write to the Free
|
||||||
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
|
02111-1307 USA. */
|
||||||
|
|
||||||
|
#ifndef _DL_IREL_h
|
||||||
|
#define _DL_IREL_H
|
||||||
|
|
||||||
|
#endif /* dl-irel.h */
|
44
sysdeps/i386/dl-irel.h
Normal file
44
sysdeps/i386/dl-irel.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/* Machine-dependent ELF indirect relocation inline functions.
|
||||||
|
i386 version.
|
||||||
|
Copyright (C) 2009 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library 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
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, write to the Free
|
||||||
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
|
02111-1307 USA. */
|
||||||
|
|
||||||
|
#ifndef _DL_IREL_H
|
||||||
|
#define _DL_IREL_H
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define ELF_MACHINE_IREL 1
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
__attribute ((always_inline))
|
||||||
|
elf_irel (const Elf32_Rel *reloc)
|
||||||
|
{
|
||||||
|
Elf32_Addr *const reloc_addr = (void *) reloc->r_offset;
|
||||||
|
const unsigned long int r_type = ELF32_R_TYPE (reloc->r_info);
|
||||||
|
|
||||||
|
if (__builtin_expect (r_type == R_386_IRELATIVE, 1))
|
||||||
|
{
|
||||||
|
Elf64_Addr value = ((Elf32_Addr (*) (void)) (*reloc_addr)) ();
|
||||||
|
*reloc_addr = value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_exit (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* dl-irel.h */
|
@ -345,6 +345,7 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
|
|||||||
Elf32_Addr value = sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value;
|
Elf32_Addr value = sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value;
|
||||||
|
|
||||||
if (sym != NULL
|
if (sym != NULL
|
||||||
|
&& __builtin_expect (sym->st_shndx != SHN_UNDEF, 1)
|
||||||
&& __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC,
|
&& __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC,
|
||||||
0))
|
0))
|
||||||
value = ((Elf32_Addr (*) (void)) value) ();
|
value = ((Elf32_Addr (*) (void)) value) ();
|
||||||
@ -471,6 +472,11 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
|
|||||||
memcpy (reloc_addr_arg, (void *) value,
|
memcpy (reloc_addr_arg, (void *) value,
|
||||||
MIN (sym->st_size, refsym->st_size));
|
MIN (sym->st_size, refsym->st_size));
|
||||||
break;
|
break;
|
||||||
|
case R_386_IRELATIVE:
|
||||||
|
value = map->l_addr + *reloc_addr;
|
||||||
|
value = ((Elf32_Addr (*) (void)) value) ();
|
||||||
|
*reloc_addr = value;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
_dl_reloc_bad_type (map, r_type, 0);
|
_dl_reloc_bad_type (map, r_type, 0);
|
||||||
break;
|
break;
|
||||||
@ -500,6 +506,7 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
|
|||||||
Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
|
Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
|
||||||
|
|
||||||
if (sym != NULL
|
if (sym != NULL
|
||||||
|
&& __builtin_expect (sym->st_shndx != SHN_UNDEF, 1)
|
||||||
&& __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC,
|
&& __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC,
|
||||||
0))
|
0))
|
||||||
value = ((Elf32_Addr (*) (void)) value) ();
|
value = ((Elf32_Addr (*) (void)) value) ();
|
||||||
@ -609,6 +616,11 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
|
|||||||
MIN (sym->st_size, refsym->st_size));
|
MIN (sym->st_size, refsym->st_size));
|
||||||
break;
|
break;
|
||||||
# endif /* !RESOLVE_CONFLICT_FIND_MAP */
|
# endif /* !RESOLVE_CONFLICT_FIND_MAP */
|
||||||
|
case R_386_IRELATIVE:
|
||||||
|
value = map->l_addr + reloc->r_addend;
|
||||||
|
value = ((Elf32_Addr (*) (void)) value) ();
|
||||||
|
*reloc_addr = value;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* We add these checks in the version to relocate ld.so only
|
/* We add these checks in the version to relocate ld.so only
|
||||||
if we are still debugging. */
|
if we are still debugging. */
|
||||||
@ -703,6 +715,12 @@ elf_machine_lazy_rel (struct link_map *map,
|
|||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (__builtin_expect (r_type == R_386_IRELATIVE, 0))
|
||||||
|
{
|
||||||
|
Elf32_Addr value = map->l_addr + *reloc_addr;
|
||||||
|
value = ((Elf32_Addr (*) (void)) value) ();
|
||||||
|
*reloc_addr = value;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
_dl_reloc_bad_type (map, r_type, 1);
|
_dl_reloc_bad_type (map, r_type, 1);
|
||||||
}
|
}
|
||||||
@ -726,6 +744,12 @@ elf_machine_lazy_rela (struct link_map *map,
|
|||||||
td->arg = (void*)reloc;
|
td->arg = (void*)reloc;
|
||||||
td->entry = _dl_tlsdesc_resolve_rela;
|
td->entry = _dl_tlsdesc_resolve_rela;
|
||||||
}
|
}
|
||||||
|
else if (__builtin_expect (r_type == R_386_IRELATIVE, 0))
|
||||||
|
{
|
||||||
|
Elf32_Addr value = map->l_addr + reloc->r_addend;
|
||||||
|
value = ((Elf32_Addr (*) (void)) value) ();
|
||||||
|
*reloc_addr = value;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
_dl_reloc_bad_type (map, r_type, 1);
|
_dl_reloc_bad_type (map, r_type, 1);
|
||||||
}
|
}
|
||||||
|
44
sysdeps/x86_64/dl-irel.h
Normal file
44
sysdeps/x86_64/dl-irel.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/* Machine-dependent ELF indirect relocation inline functions.
|
||||||
|
x86-64 version.
|
||||||
|
Copyright (C) 2009 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library 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
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, write to the Free
|
||||||
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
|
02111-1307 USA. */
|
||||||
|
|
||||||
|
#ifndef _DL_IREL_H
|
||||||
|
#define _DL_IREL_H
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define ELF_MACHINE_IRELA 1
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
__attribute ((always_inline))
|
||||||
|
elf_irela (const Elf64_Rela *reloc)
|
||||||
|
{
|
||||||
|
Elf64_Addr *const reloc_addr = (void *) reloc->r_offset;
|
||||||
|
const unsigned long int r_type = ELF64_R_TYPE (reloc->r_info);
|
||||||
|
|
||||||
|
if (__builtin_expect (r_type == R_X86_64_IRELATIVE, 1))
|
||||||
|
{
|
||||||
|
Elf64_Addr value = ((Elf64_Addr (*) (void)) reloc->r_addend) ();
|
||||||
|
*reloc_addr = value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_exit (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* dl-irel.h */
|
@ -297,6 +297,7 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
|
|||||||
: (Elf64_Addr) sym_map->l_addr + sym->st_value);
|
: (Elf64_Addr) sym_map->l_addr + sym->st_value);
|
||||||
|
|
||||||
if (sym != NULL
|
if (sym != NULL
|
||||||
|
&& __builtin_expect (sym->st_shndx != SHN_UNDEF, 1)
|
||||||
&& __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC,
|
&& __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC,
|
||||||
0))
|
0))
|
||||||
value = ((Elf64_Addr (*) (void)) value) ();
|
value = ((Elf64_Addr (*) (void)) value) ();
|
||||||
@ -442,6 +443,11 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
# endif
|
# endif
|
||||||
|
case R_X86_64_IRELATIVE:
|
||||||
|
value = map->l_addr + reloc->r_addend;
|
||||||
|
value = ((Elf64_Addr (*) (void)) value) ();
|
||||||
|
*reloc_addr = value;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
_dl_reloc_bad_type (map, r_type, 0);
|
_dl_reloc_bad_type (map, r_type, 0);
|
||||||
break;
|
break;
|
||||||
@ -488,6 +494,12 @@ elf_machine_lazy_rel (struct link_map *map,
|
|||||||
td->entry = (void*)(D_PTR (map, l_info[ADDRIDX (DT_TLSDESC_PLT)])
|
td->entry = (void*)(D_PTR (map, l_info[ADDRIDX (DT_TLSDESC_PLT)])
|
||||||
+ map->l_addr);
|
+ map->l_addr);
|
||||||
}
|
}
|
||||||
|
else if (__builtin_expect (r_type == R_X86_64_IRELATIVE, 0))
|
||||||
|
{
|
||||||
|
Elf64_Addr value = map->l_addr + reloc->r_addend;
|
||||||
|
value = ((Elf64_Addr (*) (void)) value) ();
|
||||||
|
*reloc_addr = value;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
_dl_reloc_bad_type (map, r_type, 1);
|
_dl_reloc_bad_type (map, r_type, 1);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user