diff options
author | Ulrich Drepper <drepper@redhat.com> | 2009-05-31 23:45:33 -0700 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2009-05-31 23:45:33 -0700 |
commit | 74414708355a922a514d5c76183eca6931c4488a (patch) | |
tree | 60dd084df2e9f02464f66b0da2068f4561856458 | |
parent | 963cb6fcb47ca212c0c57cc57bd7510f6549579c (diff) | |
download | glibc-74414708355a922a514d5c76183eca6931c4488a.tar.gz glibc-74414708355a922a514d5c76183eca6931c4488a.tar.xz glibc-74414708355a922a514d5c76183eca6931c4488a.zip |
Finish IFUNC support for x86 and x86-64.
Add support for the IRELAIVE relocation and IFUNC in static executables.
-rw-r--r-- | ChangeLog | 27 | ||||
-rw-r--r-- | csu/elf-init.c | 30 | ||||
-rw-r--r-- | elf/elf.h | 6 | ||||
-rw-r--r-- | include/libc-symbols.h | 17 | ||||
-rw-r--r-- | sysdeps/generic/dl-irel.h | 23 | ||||
-rw-r--r-- | sysdeps/i386/dl-irel.h | 44 | ||||
-rw-r--r-- | sysdeps/i386/dl-machine.h | 24 | ||||
-rw-r--r-- | sysdeps/x86_64/dl-irel.h | 44 | ||||
-rw-r--r-- | sysdeps/x86_64/dl-machine.h | 12 |
9 files changed, 225 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog index 1de4c0dd4f..65a9fb7b55 100644 --- a/ChangeLog +++ b/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> * sysdeps/x86_64/multiarch/init-arch.h: Define COMMON_CPUID_INDEX_1 diff --git a/csu/elf-init.c b/csu/elf-init.c index 27eae1550b..5a99a3a400 100644 --- a/csu/elf-init.c +++ b/csu/elf-init.c @@ -36,6 +36,20 @@ #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. */ 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. */ #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. */ { const size_t size = __preinit_array_end - __preinit_array_start; diff --git a/elf/elf.h b/elf/elf.h index 062ef00f57..8fdf74b099 100644 --- a/elf/elf.h +++ b/elf/elf.h @@ -1177,8 +1177,9 @@ typedef struct pointer to code and to argument, returning the TLS offset for the symbol. */ +#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */ /* Keep this the last entry. */ -#define R_386_NUM 42 +#define R_386_NUM 43 /* 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 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. */ diff --git a/include/libc-symbols.h b/include/libc-symbols.h index d53bcb9b77..68da77c58e 100644 --- a/include/libc-symbols.h +++ b/include/libc-symbols.h @@ -845,4 +845,21 @@ for linking") } \ __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 */ diff --git a/sysdeps/generic/dl-irel.h b/sysdeps/generic/dl-irel.h new file mode 100644 index 0000000000..4d7b481e81 --- /dev/null +++ b/sysdeps/generic/dl-irel.h @@ -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 */ diff --git a/sysdeps/i386/dl-irel.h b/sysdeps/i386/dl-irel.h new file mode 100644 index 0000000000..4acb862c69 --- /dev/null +++ b/sysdeps/i386/dl-irel.h @@ -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 */ diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h index 0e15878d4e..efa929e57f 100644 --- a/sysdeps/i386/dl-machine.h +++ b/sysdeps/i386/dl-machine.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; if (sym != NULL + && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1) && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)) 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, MIN (sym->st_size, refsym->st_size)); break; + case R_386_IRELATIVE: + value = map->l_addr + *reloc_addr; + value = ((Elf32_Addr (*) (void)) value) (); + *reloc_addr = value; + break; default: _dl_reloc_bad_type (map, r_type, 0); 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; if (sym != NULL + && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1) && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)) 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)); break; # 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: /* We add these checks in the version to relocate ld.so only if we are still debugging. */ @@ -703,6 +715,12 @@ elf_machine_lazy_rel (struct link_map *map, # 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 _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->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 _dl_reloc_bad_type (map, r_type, 1); } diff --git a/sysdeps/x86_64/dl-irel.h b/sysdeps/x86_64/dl-irel.h new file mode 100644 index 0000000000..442ab71d26 --- /dev/null +++ b/sysdeps/x86_64/dl-irel.h @@ -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 */ diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h index 4444ae0a71..1b5ce8e981 100644 --- a/sysdeps/x86_64/dl-machine.h +++ b/sysdeps/x86_64/dl-machine.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); if (sym != NULL + && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1) && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)) value = ((Elf64_Addr (*) (void)) value) (); @@ -442,6 +443,11 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc, } break; # endif + case R_X86_64_IRELATIVE: + value = map->l_addr + reloc->r_addend; + value = ((Elf64_Addr (*) (void)) value) (); + *reloc_addr = value; + break; default: _dl_reloc_bad_type (map, r_type, 0); 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)]) + 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 _dl_reloc_bad_type (map, r_type, 1); } |