This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
PATCH: Fix STT_GNU_IFUNC pointer equality
- From: "H.J. Lu" <hongjiu dot lu at intel dot com>
- To: binutils at sources dot redhat dot com
- Cc: libc at lucon dot org
- Date: Tue, 2 Jun 2009 22:27:17 -0700
- Subject: PATCH: Fix STT_GNU_IFUNC pointer equality
- Reply-to: "H.J. Lu" <hjl dot tools at gmail dot com>
Hi,
I am checking in this patch to fix STT_GNU_IFUNC pointer equality.
I will submit run-time testcases for glibc.
H.J.
----
2009-06-02 H.J. Lu <hongjiu.lu@intel.com>
* elf32-i386.c (elf_i386_allocate_dynrelocs): Allocate
GOT entry for STT_GNU_IFUNC symbol with pointer equality.
(elf_i386_relocate_section): Adjust R_386_GOT32 relocation
against STT_GNU_IFUNC symbols for static executables.
(elf_i386_finish_dynamic_symbol): Load GOT entry with
PLT entry for STT_GNU_IFUNC symbol with pointer equality.
* elf64-x86-64.c (elf64_x86_64_allocate_dynrelocs): Allocate
GOT entry for STT_GNU_IFUNC symbol with pointer equality.
(elf64_x86_64_finish_dynamic_symbol): Load GOT entry with
PLT entry for STT_GNU_IFUNC symbol with pointer equality.
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc \
../binutils/src binutils
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/elf32-i386.c binutils/bfd/elf32-i386.c
--- ../binutils/src/bfd/elf32-i386.c 2009-06-02 22:12:08.000000000 -0700
+++ binutils/bfd/elf32-i386.c 2009-06-02 22:18:33.000000000 -0700
@@ -2003,10 +2003,26 @@ elf_i386_allocate_dynrelocs (struct elf_
/* STT_GNU_IFUNC symbol uses .got.plt, not .got. But for
shared library, we must go through GOT and we can't
use R_386_IRELATIVE unless it is forced local. */
- if (!info->shared
+ if (info->executable
|| info->symbolic
|| h->forced_local)
- h->got.refcount = 0;
+ {
+ if (h->pointer_equality_needed
+ && htab->sgot != NULL)
+ {
+ /* We can't use .got.plt, which contains the real
+ function addres, since we need pointer equality.
+ We will load the GOT entry with the PLT entry
+ in elf_i386_finish_dynamic_symbol and don't
+ need GOT relocation. */
+ h->got.offset = htab->sgot->size;
+ htab->sgot->size += 4;
+ eh->tlsdesc_got = (bfd_vma) -1;
+ goto skip_relgot;
+ }
+ else
+ h->got.refcount = 0;
+ }
}
else if (htab->elf.dynamic_sections_created
&& h->plt.refcount > 0)
@@ -2153,6 +2169,7 @@ elf_i386_allocate_dynrelocs (struct elf_
else
h->got.offset = (bfd_vma) -1;
+skip_relgot:
if (eh->dyn_relocs == NULL)
return TRUE;
@@ -2966,11 +2983,16 @@ elf_i386_relocate_section (bfd *output_b
relocation += gotplt->output_offset;
}
else
- relocation = (base_got->output_section->vma
- + base_got->output_offset + off
- - gotplt->output_section->vma
- - gotplt->output_offset);
-
+ {
+ relocation = (base_got->output_section->vma
+ + base_got->output_offset + off
+ - gotplt->output_section->vma
+ - gotplt->output_offset);
+ /* Adjust for static executables. */
+ if (htab->splt == NULL)
+ relocation += gotplt->output_offset;
+ }
+
goto do_relocation;
case R_386_GOTOFF:
@@ -4113,8 +4135,28 @@ elf_i386_finish_dynamic_symbol (bfd *out
of a version file, we just want to emit a RELATIVE reloc.
The entry in the global offset table will already have been
initialized in the relocate_section function. */
- if (info->shared
- && SYMBOL_REFERENCES_LOCAL (info, h))
+ if ((info->executable
+ || info->symbolic
+ || h->forced_local)
+ && h->def_regular
+ && h->pointer_equality_needed
+ && h->type == STT_GNU_IFUNC)
+ {
+ /* The STT_GNU_IFUNC symbol is locally defined. But we can't
+ use .got.plt, which contains the real function addres,
+ since we need pointer equality. We load the GOT entry
+ with the PLT entry without relocation. */
+ asection *plt = htab->splt ? htab->splt : htab->iplt;
+ if (htab->sgot == NULL
+ || h->plt.offset == (bfd_vma) -1)
+ abort ();
+ bfd_put_32 (output_bfd, (plt->output_section->vma
+ + plt->output_offset + h->plt.offset),
+ htab->sgot->contents + h->got.offset);
+ return TRUE;
+ }
+ else if (info->shared
+ && SYMBOL_REFERENCES_LOCAL (info, h))
{
BFD_ASSERT((h->got.offset & 1) != 0);
rel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/elf64-x86-64.c binutils/bfd/elf64-x86-64.c
--- ../binutils/src/bfd/elf64-x86-64.c 2009-06-02 22:12:08.000000000 -0700
+++ binutils/bfd/elf64-x86-64.c 2009-06-02 22:17:08.000000000 -0700
@@ -1841,10 +1841,26 @@ elf64_x86_64_allocate_dynrelocs (struct
/* STT_GNU_IFUNC symbol uses .got.plt, not .got. But for
shared library, we must go through GOT and we can't
use R_X86_64_IRELATIVE unless it is forced local. */
- if (!info->shared
+ if (info->executable
|| info->symbolic
|| h->forced_local)
- h->got.refcount = 0;
+ {
+ if (h->pointer_equality_needed
+ && htab->sgot != NULL)
+ {
+ /* We can't use .got.plt, which contains the real
+ function addres, since we need pointer equality.
+ We will load the GOT entry with the PLT entry
+ in elf64_x86_64_finish_dynamic_symbol and don't
+ need GOT relocation. */
+ h->got.offset = htab->sgot->size;
+ htab->sgot->size += GOT_ENTRY_SIZE;
+ eh->tlsdesc_got = (bfd_vma) -1;
+ goto skip_relgot;
+ }
+ else
+ h->got.refcount = 0;
+ }
}
else if (htab->elf.dynamic_sections_created
&& h->plt.refcount > 0)
@@ -1971,6 +1987,7 @@ elf64_x86_64_allocate_dynrelocs (struct
else
h->got.offset = (bfd_vma) -1;
+skip_relgot:
if (eh->dyn_relocs == NULL)
return TRUE;
@@ -3727,8 +3744,28 @@ elf64_x86_64_finish_dynamic_symbol (bfd
of a version file, we just want to emit a RELATIVE reloc.
The entry in the global offset table will already have been
initialized in the relocate_section function. */
- if (info->shared
- && SYMBOL_REFERENCES_LOCAL (info, h))
+ if ((info->executable
+ || info->symbolic
+ || h->forced_local)
+ && h->def_regular
+ && h->pointer_equality_needed
+ && h->type == STT_GNU_IFUNC)
+ {
+ /* The STT_GNU_IFUNC symbol is locally defined. But we can't
+ use .got.plt, which contains the real function addres,
+ since we need pointer equality. We load the GOT entry
+ with the PLT entry without relocation. */
+ asection *plt = htab->splt ? htab->splt : htab->iplt;
+ if (htab->sgot == NULL
+ || h->plt.offset == (bfd_vma) -1)
+ abort ();
+ bfd_put_64 (output_bfd, (plt->output_section->vma
+ + plt->output_offset + h->plt.offset),
+ htab->sgot->contents + h->got.offset);
+ return TRUE;
+ }
+ else if (info->shared
+ && SYMBOL_REFERENCES_LOCAL (info, h))
{
if (!h->def_regular)
return FALSE;