PATCH: Make STT_GNU_IFUNC symbol dynamic
H.J. Lu
hjl.tools@gmail.com
Sun May 24 02:39:00 GMT 2009
On Sat, May 23, 2009 at 04:54:37PM -0700, H.J. Lu wrote:
> On Sat, May 23, 2009 at 2:44 PM, Ulrich Drepper <drepper@redhat.com> wrote:
> > -----BEGIN PGP SIGNED MESSAGE-----
> > Hash: SHA1
> >
> > H.J. Lu wrote:
> >> Which tool will generate the new relocation? Will it be internal to linker.
> >
> > The code the compiler generates contains ordinary calls. Â The assembler
> > will have to refrain from optimizing calls to static IFUNC functions.
>
> Assembler will always generate PLT relocation for @PLT. I don't think
> we need to change the assembler.
>
> > But the real logic is entirely internal to the static linker. Â For every
> > local IFUNC symbol create a PLT slot. Â This slot has no global symbol
> > attached and the relocation should be R_*_IRELATIVE (my proposed name).
> > Â This relocation works like a R_*_RELATIVE relocation but it uses the
> > return value as for SHT_GNU_IFUNC symbols. Â The reason we need such a
> > relocation is that we have no symbol at runtime. Â We cannot use a normal
> > PLT slot relocation since this would perform a global name lookup, which
> > is wrong. Â The R_*_IRELATIVE relocation is also more efficient.
> >
> >
>
> I took a look. It isn't hard to implement. Should it be R_*_IJUMP_SLOT
> since it will be processed closer to R_*_JUMP_SLOT than R_*_RELATIVE?
> My linker only patch for x86-64 is ready for test. I just need to
> verify it works
> with glibc on x86-64.
>
This patch works with the modified glibc. I am also enclosing
glibc patch for reference.
H.J.
---
bfd/
2009-05-23 H.J. Lu <hongjiu.lu@intel.com>
* elf64-x86-64.c (elf64_x86_64_finish_dynamic_symbol): Generate
R_X86_64_IJUMP_SLOT relocation for local STT_GNU_IFUNC symbol.
* elflink.c (_bfd_elf_symbol_refs_local_p): Return FALSE on
STT_GNU_IFUNC symbol.
(_bfd_elf_link_hash_hide_symbol): Don't clean plt on
STT_GNU_IFUNC symbol.
include/elf/
2009-05-23 H.J. Lu <hongjiu.lu@intel.com>
* x86-64.h (R_X86_64_IJUMP_SLOT): New.
Index: bfd/elflink.c
===================================================================
--- bfd/elflink.c (revision 5932)
+++ bfd/elflink.c (working copy)
@@ -2845,6 +2845,10 @@ _bfd_elf_symbol_refs_local_p (struct elf
if (h == NULL)
return TRUE;
+ /* STT_GNU_IFUNC symbol must go through PLT. */
+ if (h->type == STT_GNU_IFUNC)
+ return FALSE;
+
/* STV_HIDDEN or STV_INTERNAL ones must be local. */
if (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
|| ELF_ST_VISIBILITY (h->other) == STV_INTERNAL)
@@ -6669,8 +6673,12 @@ _bfd_elf_link_hash_hide_symbol (struct b
struct elf_link_hash_entry *h,
bfd_boolean force_local)
{
- h->plt = elf_hash_table (info)->init_plt_offset;
- h->needs_plt = 0;
+ /* STT_GNU_IFUNC symbol must go through PLT. */
+ if (ELF_ST_TYPE (h->type) != STT_GNU_IFUNC)
+ {
+ h->plt = elf_hash_table (info)->init_plt_offset;
+ h->needs_plt = 0;
+ }
if (force_local)
{
h->forced_local = 1;
Index: bfd/elf64-x86-64.c
===================================================================
--- bfd/elf64-x86-64.c (revision 5933)
+++ bfd/elf64-x86-64.c (working copy)
@@ -3328,7 +3328,10 @@ elf64_x86_64_finish_dynamic_symbol (bfd
/* This symbol has an entry in the procedure linkage table. Set
it up. */
- if (h->dynindx == -1
+ if ((h->dynindx == -1
+ && !(h->forced_local
+ && h->def_regular
+ && ELF_ST_TYPE (h->type) == STT_GNU_IFUNC))
|| htab->splt == NULL
|| htab->sgotplt == NULL
|| htab->srelplt == NULL)
@@ -3381,8 +3384,18 @@ elf64_x86_64_finish_dynamic_symbol (bfd
rela.r_offset = (htab->sgotplt->output_section->vma
+ htab->sgotplt->output_offset
+ got_offset);
- rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_JUMP_SLOT);
- rela.r_addend = 0;
+ if (h->dynindx != -1)
+ {
+ rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_JUMP_SLOT);
+ rela.r_addend = 0;
+ }
+ else
+ {
+ rela.r_info = ELF64_R_INFO (0, R_X86_64_IJUMP_SLOT);
+ rela.r_addend = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ }
loc = htab->srelplt->contents + plt_index * sizeof (Elf64_External_Rela);
bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
Index: include/elf/x86-64.h
===================================================================
--- include/elf/x86-64.h (revision 5933)
+++ include/elf/x86-64.h (working copy)
@@ -71,6 +71,7 @@ START_RELOC_NUMBERS (elf_x86_64_reloc_ty
RELOC_NUMBER (R_X86_64_TLSDESC_CALL, 35) /* Relaxable call through TLS
descriptor. */
RELOC_NUMBER (R_X86_64_TLSDESC, 36) /* 2x64-bit TLS descriptor. */
+ RELOC_NUMBER (R_X86_64_IJUMP_SLOT,37) /* Create indirect PLT entry */
RELOC_NUMBER (R_X86_64_GNU_VTINHERIT, 250) /* GNU C++ hack */
RELOC_NUMBER (R_X86_64_GNU_VTENTRY, 251) /* GNU C++ hack */
END_RELOC_NUMBERS (R_X86_64_max)
-------------- next part --------------
diff --git a/elf/elf.h b/elf/elf.h
index 062ef00..e13001d 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -2625,8 +2625,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_IJUMP_SLOT 37 /* Create indirect PLT entry */
-#define R_X86_64_NUM 37
+#define R_X86_64_NUM 38
/* AM33 relocations. */
diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h
index 4444ae0..8878dd0 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,12 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
}
break;
# endif
+ case R_X86_64_IJUMP_SLOT:
+ value = map->l_addr + reloc->r_addend;
+ value = ((DL_FIXUP_VALUE_TYPE (*) (void))
+ DL_FIXUP_VALUE_ADDR (value)) ();
+ *reloc_addr = value;
+ break;
default:
_dl_reloc_bad_type (map, r_type, 0);
break;
@@ -488,6 +495,13 @@ 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_IJUMP_SLOT, 0))
+ {
+ Elf64_Addr value = map->l_addr + reloc->r_addend;
+ value = ((DL_FIXUP_VALUE_TYPE (*) (void))
+ DL_FIXUP_VALUE_ADDR (value)) ();
+ *reloc_addr = value;
+ }
else
_dl_reloc_bad_type (map, r_type, 1);
}
More information about the Libc-alpha
mailing list