This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PATCH: Fix STT_GNU_IFUNC pointer equality


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;


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]