aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2009-05-31 23:45:33 -0700
committerUlrich Drepper <drepper@redhat.com>2009-05-31 23:45:33 -0700
commit74414708355a922a514d5c76183eca6931c4488a (patch)
tree60dd084df2e9f02464f66b0da2068f4561856458
parent963cb6fcb47ca212c0c57cc57bd7510f6549579c (diff)
downloadglibc-74414708355a922a514d5c76183eca6931c4488a.zip
glibc-74414708355a922a514d5c76183eca6931c4488a.tar.gz
glibc-74414708355a922a514d5c76183eca6931c4488a.tar.bz2
Finish IFUNC support for x86 and x86-64.
Add support for the IRELAIVE relocation and IFUNC in static executables.
-rw-r--r--ChangeLog27
-rw-r--r--csu/elf-init.c30
-rw-r--r--elf/elf.h6
-rw-r--r--include/libc-symbols.h17
-rw-r--r--sysdeps/generic/dl-irel.h23
-rw-r--r--sysdeps/i386/dl-irel.h44
-rw-r--r--sysdeps/i386/dl-machine.h24
-rw-r--r--sysdeps/x86_64/dl-irel.h44
-rw-r--r--sysdeps/x86_64/dl-machine.h12
9 files changed, 225 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 1de4c0d..65a9fb7 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 27eae15..5a99a3a 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 062ef00..8fdf74b 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 d53bcb9..68da77c 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 0000000..4d7b481
--- /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 0000000..4acb862
--- /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 0e15878..efa929e 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 0000000..442ab71
--- /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 4444ae0..1b5ce8e 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);
}