PATCH: Fix STT_GNU_IFUNC pointer for i386 and x86-64

H.J. Lu hjl.tools@gmail.com
Tue Jun 2 17:35:00 GMT 2009


On Mon, Jun 1, 2009 at 9:45 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Mon, Jun 1, 2009 at 6:08 AM, H.J. Lu <hongjiu.lu@intel.com> wrote:
>> I am checking this patch to support STT_GNU_IFUNC for i386 and x86-64.
>> Tested with STT_GNU_IFUNC symbols in shared library, dynamic executable
>> and static executable.
>
> Hi Ulrich, Jakub,
>
> I found a few problems with STT_GNU_IFUNC when I was writing
> STT_GNU_IFUNC testcases for glibc. I will submit glibc patches and
> check in a linker fix soon.
>
>

Hi Ulrich, Jakub,

I checked in this patch to fix STT_GNU_IFUNC pointer for i386 and
x86-64. Please make sure that your linker has this fix. I will submit
glibc testcases later, which will fail without this fix.

Thanks.

-- 
H.J.
---
bfd/

2009-06-02  H.J. Lu  <hongjiu.lu@intel.com>

	* elf32-i386.c (elf_i386_check_relocs): Increment
	got.refcount for R_386_GOT32/R_386_GOTOFF relocations
	against STT_GNU_IFUNC symbol.
	(elf_i386_allocate_dynrelocs): Set got.refcount to 0 if
	local STT_GNU_IFUNC definition is used.
	(elf_i386_relocate_section): Handle got.offset != -1 for
	R_386_GOT32/R_386_GOTOFF relocations against STT_GNU_IFUNC
	symbol.

	* elf64-x86-64.c (elf64_x86_64_check_relocs): Increment
	got.refcount for R_X86_64_GOTPCREL/R_X86_64_GOTPCREL64
	relocations against STT_GNU_IFUNC symbol.
	(elf64_x86_64_allocate_dynrelocs): Set got.refcount to 0 if
	local STT_GNU_IFUNC definition is used.
	(elf64_x86_64_relocate_section): Handle got.offset != -1
	for R_X86_64_GOTPCREL/R_X86_64_GOTPCREL64 relocations against
	STT_GNU_IFUNC symbol.

ld/testsuite/

2009-06-02  H.J. Lu  <hongjiu.lu@intel.com>

	* ld-ifunc/ifunc-5-i386.d: Renamed to ...
	* ld-ifunc/ifunc-5a-i386.d: This.

	* ld-ifunc/ifunc-5-x86-64.d: Renamed to ...
	* ld-ifunc/ifunc-5a-x86-64.d: This.

	* ld-ifunc/ifunc-5b-i386.d: New.
	* ld-ifunc/ifunc-5b-x86-64.d: Likewise.
	* ld-ifunc/ifunc-6a-i386.d: Likewise.
	* ld-ifunc/ifunc-6a-x86-64.d: Likewise.
	* ld-ifunc/ifunc-6b-i386.d: Likewise.
	* ld-ifunc/ifunc-6b-x86-64.d: Likewise.
	* ld-ifunc/ifunc-6-i386.s: Likewise.
	* ld-ifunc/ifunc-6-x86-64.s: Likewise.
	* ld-ifunc/ifunc-7a-i386.d: Likewise.
	* ld-ifunc/ifunc-7a-x86-64.d: Likewise.
	* ld-ifunc/ifunc-7b-i386.d: Likewise.
	* ld-ifunc/ifunc-7b-x86-64.d: Likewise.
	* ld-ifunc/ifunc-7-i386.s: Likewise.
	* ld-ifunc/ifunc-7-x86-64.s: Likewise.
-------------- next part --------------
bfd/

2009-06-02  H.J. Lu  <hongjiu.lu@intel.com>

	* elf32-i386.c (elf_i386_check_relocs): Increment
	got.refcount for R_386_GOT32/R_386_GOTOFF relocations
	against STT_GNU_IFUNC symbol.
	(elf_i386_allocate_dynrelocs): Set got.refcount to 0 if
	local STT_GNU_IFUNC definition is used.
	(elf_i386_relocate_section): Handle got.offset != -1 for
	R_386_GOT32/R_386_GOTOFF relocations against STT_GNU_IFUNC
	symbol.

	* elf64-x86-64.c (elf64_x86_64_check_relocs): Increment
	got.refcount for R_X86_64_GOTPCREL/R_X86_64_GOTPCREL64
	relocations against STT_GNU_IFUNC symbol.
	(elf64_x86_64_allocate_dynrelocs): Set got.refcount to 0 if
	local STT_GNU_IFUNC definition is used.
	(elf64_x86_64_relocate_section): Handle got.offset != -1
	for R_X86_64_GOTPCREL/R_X86_64_GOTPCREL64 relocations against
	STT_GNU_IFUNC symbol.

ld/testsuite/

2009-06-02  H.J. Lu  <hongjiu.lu@intel.com>

	* ld-ifunc/ifunc-5-i386.d: Renamed to ...
	* ld-ifunc/ifunc-5a-i386.d: This.

	* ld-ifunc/ifunc-5-x86-64.d: Renamed to ...
	* ld-ifunc/ifunc-5a-x86-64.d: This.

	* ld-ifunc/ifunc-5b-i386.d: New.
	* ld-ifunc/ifunc-5b-x86-64.d: Likewise.
	* ld-ifunc/ifunc-6a-i386.d: Likewise.
	* ld-ifunc/ifunc-6a-x86-64.d: Likewise.
	* ld-ifunc/ifunc-6b-i386.d: Likewise.
	* ld-ifunc/ifunc-6b-x86-64.d: Likewise.
	* ld-ifunc/ifunc-6-i386.s: Likewise.
	* ld-ifunc/ifunc-6-x86-64.s: Likewise.
	* ld-ifunc/ifunc-7a-i386.d: Likewise.
	* ld-ifunc/ifunc-7a-x86-64.d: Likewise.
	* ld-ifunc/ifunc-7b-i386.d: Likewise.
	* ld-ifunc/ifunc-7b-x86-64.d: Likewise.
	* ld-ifunc/ifunc-7-i386.s: Likewise.
	* ld-ifunc/ifunc-7-x86-64.s: Likewise.

Index: ld/testsuite/ChangeLog
===================================================================
Index: ld/testsuite/ld-ifunc/ifunc-5a-i386.d
===================================================================
--- ld/testsuite/ld-ifunc/ifunc-5a-i386.d	(revision 0)
+++ ld/testsuite/ld-ifunc/ifunc-5a-i386.d	(revision 6052)
@@ -0,0 +1,9 @@
+#source: ifunc-5-i386.s
+#ld: -m elf_i386
+#as: --32
+#readelf: -r --wide
+#target: x86_64-*-* i?86-*-*
+
+Relocation section '.rel.plt' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_386_IRELATIVE[ ]*
Index: ld/testsuite/ld-ifunc/ifunc-6a-i386.d
===================================================================
--- ld/testsuite/ld-ifunc/ifunc-6a-i386.d	(revision 0)
+++ ld/testsuite/ld-ifunc/ifunc-6a-i386.d	(revision 6052)
@@ -0,0 +1,9 @@
+#source: ifunc-6-i386.s
+#ld: -m elf_i386
+#as: --32
+#readelf: -r --wide
+#target: x86_64-*-* i?86-*-*
+
+Relocation section '.rel.plt' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_386_IRELATIVE[ ]*
Index: ld/testsuite/ld-ifunc/ifunc-7a-i386.d
===================================================================
--- ld/testsuite/ld-ifunc/ifunc-7a-i386.d	(revision 0)
+++ ld/testsuite/ld-ifunc/ifunc-7a-i386.d	(revision 6052)
@@ -0,0 +1,9 @@
+#source: ifunc-7-i386.s
+#ld: -m elf_i386
+#as: --32
+#readelf: -r --wide
+#target: x86_64-*-* i?86-*-*
+
+Relocation section '.rel.plt' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_386_IRELATIVE[ ]*
Index: ld/testsuite/ld-ifunc/ifunc-7-x86-64.s
===================================================================
--- ld/testsuite/ld-ifunc/ifunc-7-x86-64.s	(revision 0)
+++ ld/testsuite/ld-ifunc/ifunc-7-x86-64.s	(revision 6052)
@@ -0,0 +1,20 @@
+	.text
+	.type foo, %gnu_indirect_function
+.globl foo
+	.type	foo, @function
+foo:
+	ret
+	.size	foo, .-foo
+	.hidden foo
+	.type start,"function"
+	.global start
+start:
+	.type _start,"function"
+	.global _start
+_start:
+	.type __start,"function"
+	.global __start
+__start:
+	.type __start,"function"
+	call	foo@PLT
+	movq    foo@GOTPCREL(%rip), %rax
Index: ld/testsuite/ld-ifunc/ifunc-6-i386.s
===================================================================
--- ld/testsuite/ld-ifunc/ifunc-6-i386.s	(revision 0)
+++ ld/testsuite/ld-ifunc/ifunc-6-i386.s	(revision 6052)
@@ -0,0 +1,24 @@
+	.text
+	.type foo, %gnu_indirect_function
+.globl foo
+	.type	foo, @function
+foo:
+	ret
+	.size	foo, .-foo
+	.protected foo
+	.type start,"function"
+	.global start
+start:
+	.type _start,"function"
+	.global _start
+_start:
+	.type __start,"function"
+	.global __start
+__start:
+	.type __start,"function"
+	call	.L6
+.L6:
+	popl	%ebx
+	addl	$_GLOBAL_OFFSET_TABLE_+[.-.L6], %ebx
+	call	foo@PLT
+	leal	foo@GOT(%ebx), %eax
Index: ld/testsuite/ld-ifunc/ifunc-5a-x86-64.d
===================================================================
--- ld/testsuite/ld-ifunc/ifunc-5a-x86-64.d	(revision 0)
+++ ld/testsuite/ld-ifunc/ifunc-5a-x86-64.d	(revision 6052)
@@ -0,0 +1,8 @@
+#source: ifunc-5-x86-64.s
+#ld:
+#readelf: -r --wide
+#target: x86_64-*-*
+
+Relocation section '.rela.plt' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_X86_64_IRELATIVE[ ]+[0-9a-f]*
Index: ld/testsuite/ld-ifunc/ifunc-6a-x86-64.d
===================================================================
--- ld/testsuite/ld-ifunc/ifunc-6a-x86-64.d	(revision 0)
+++ ld/testsuite/ld-ifunc/ifunc-6a-x86-64.d	(revision 6052)
@@ -0,0 +1,8 @@
+#source: ifunc-6-x86-64.s
+#ld:
+#readelf: -r --wide
+#target: x86_64-*-*
+
+Relocation section '.rela.plt' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_X86_64_IRELATIVE[ ]+[0-9a-f]*
Index: ld/testsuite/ld-ifunc/ifunc-7a-x86-64.d
===================================================================
--- ld/testsuite/ld-ifunc/ifunc-7a-x86-64.d	(revision 0)
+++ ld/testsuite/ld-ifunc/ifunc-7a-x86-64.d	(revision 6052)
@@ -0,0 +1,8 @@
+#source: ifunc-7-x86-64.s
+#ld:
+#readelf: -r --wide
+#target: x86_64-*-*
+
+Relocation section '.rela.plt' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_X86_64_IRELATIVE[ ]+[0-9a-f]*
Index: ld/testsuite/ld-ifunc/ifunc-5b-i386.d
===================================================================
--- ld/testsuite/ld-ifunc/ifunc-5b-i386.d	(revision 0)
+++ ld/testsuite/ld-ifunc/ifunc-5b-i386.d	(revision 6052)
@@ -0,0 +1,13 @@
+#source: ifunc-5-i386.s
+#ld: -shared -m elf_i386 -z nocombreloc
+#as: --32
+#readelf: -r --wide
+#target: x86_64-*-* i?86-*-*
+
+Relocation section '.rel.got' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_386_GLOB_DAT[ ]+foo\(\)[ ]+foo
+#...
+Relocation section '.rel.plt' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_386_JUMP_SLOT[ ]+foo\(\)[ ]+foo
Index: ld/testsuite/ld-ifunc/ifunc-6b-i386.d
===================================================================
--- ld/testsuite/ld-ifunc/ifunc-6b-i386.d	(revision 0)
+++ ld/testsuite/ld-ifunc/ifunc-6b-i386.d	(revision 6052)
@@ -0,0 +1,13 @@
+#source: ifunc-6-i386.s
+#ld: -shared -m elf_i386 -z nocombreloc
+#as: --32
+#readelf: -r --wide
+#target: x86_64-*-* i?86-*-*
+
+Relocation section '.rel.got' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_386_GLOB_DAT[ ]+foo\(\)[ ]+foo
+#...
+Relocation section '.rel.plt' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_386_IRELATIVE[ ]*
Index: ld/testsuite/ld-ifunc/ifunc-6-x86-64.s
===================================================================
--- ld/testsuite/ld-ifunc/ifunc-6-x86-64.s	(revision 0)
+++ ld/testsuite/ld-ifunc/ifunc-6-x86-64.s	(revision 6052)
@@ -0,0 +1,20 @@
+	.text
+	.type foo, %gnu_indirect_function
+.globl foo
+	.type	foo, @function
+foo:
+	ret
+	.size	foo, .-foo
+	.protected foo
+	.type start,"function"
+	.global start
+start:
+	.type _start,"function"
+	.global _start
+_start:
+	.type __start,"function"
+	.global __start
+__start:
+	.type __start,"function"
+	call	foo@PLT
+	movq    foo@GOTPCREL(%rip), %rax
Index: ld/testsuite/ld-ifunc/ifunc-7b-i386.d
===================================================================
--- ld/testsuite/ld-ifunc/ifunc-7b-i386.d	(revision 0)
+++ ld/testsuite/ld-ifunc/ifunc-7b-i386.d	(revision 6052)
@@ -0,0 +1,9 @@
+#source: ifunc-7-i386.s
+#ld: -shared -m elf_i386
+#as: --32
+#readelf: -r --wide
+#target: x86_64-*-* i?86-*-*
+
+Relocation section '.rel.plt' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_386_IRELATIVE[ ]*
Index: ld/testsuite/ld-ifunc/ifunc-7-i386.s
===================================================================
--- ld/testsuite/ld-ifunc/ifunc-7-i386.s	(revision 0)
+++ ld/testsuite/ld-ifunc/ifunc-7-i386.s	(revision 6052)
@@ -0,0 +1,24 @@
+	.text
+	.type foo, %gnu_indirect_function
+.globl foo
+	.type	foo, @function
+foo:
+	ret
+	.size	foo, .-foo
+	.hidden foo
+	.type start,"function"
+	.global start
+start:
+	.type _start,"function"
+	.global _start
+_start:
+	.type __start,"function"
+	.global __start
+__start:
+	.type __start,"function"
+	call	.L6
+.L6:
+	popl	%ebx
+	addl	$_GLOBAL_OFFSET_TABLE_+[.-.L6], %ebx
+	call	foo@PLT
+	leal	foo@GOT(%ebx), %eax
Index: ld/testsuite/ld-ifunc/ifunc-5b-x86-64.d
===================================================================
--- ld/testsuite/ld-ifunc/ifunc-5b-x86-64.d	(revision 0)
+++ ld/testsuite/ld-ifunc/ifunc-5b-x86-64.d	(revision 6052)
@@ -0,0 +1,12 @@
+#source: ifunc-5-x86-64.s
+#ld: -shared -z nocombreloc
+#readelf: -r --wide
+#target: x86_64-*-*
+
+Relocation section '.rela.got' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_X86_64_GLOB_DAT[ ]+foo\(\)[ ]+foo \+ 0
+#...
+Relocation section '.rela.plt' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_X86_64_JUMP_SLOT[ ]+foo\(\)[ ]+foo \+ 0
Index: ld/testsuite/ld-ifunc/ifunc-6b-x86-64.d
===================================================================
--- ld/testsuite/ld-ifunc/ifunc-6b-x86-64.d	(revision 0)
+++ ld/testsuite/ld-ifunc/ifunc-6b-x86-64.d	(revision 6052)
@@ -0,0 +1,12 @@
+#source: ifunc-6-x86-64.s
+#ld: -shared -z nocombreloc
+#readelf: -r --wide
+#target: x86_64-*-*
+
+Relocation section '.rela.got' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_X86_64_GLOB_DAT[ ]+foo\(\)[ ]+foo \+ 0
+#...
+Relocation section '.rela.plt' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_X86_64_IRELATIVE[ ]+[0-9a-f]*
Index: ld/testsuite/ld-ifunc/ifunc-7b-x86-64.d
===================================================================
--- ld/testsuite/ld-ifunc/ifunc-7b-x86-64.d	(revision 0)
+++ ld/testsuite/ld-ifunc/ifunc-7b-x86-64.d	(revision 6052)
@@ -0,0 +1,8 @@
+#source: ifunc-7-x86-64.s
+#ld: -shared
+#readelf: -r --wide
+#target: x86_64-*-*
+
+Relocation section '.rela.plt' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_X86_64_IRELATIVE[ ]+[0-9a-f]*
Index: ld/testsuite/ld-ifunc/ifunc-5-i386.d
===================================================================
--- ld/testsuite/ld-ifunc/ifunc-5-i386.d	(revision 6031)
+++ ld/testsuite/ld-ifunc/ifunc-5-i386.d	(working copy)
@@ -1,8 +0,0 @@
-#ld: -m elf_i386
-#as: --32
-#readelf: -r --wide
-#target: x86_64-*-* i?86-*-*
-
-#...
-[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_386_IRELATIVE[ ]*
-#pass
Index: ld/testsuite/ld-ifunc/ifunc-5-x86-64.d
===================================================================
--- ld/testsuite/ld-ifunc/ifunc-5-x86-64.d	(revision 6031)
+++ ld/testsuite/ld-ifunc/ifunc-5-x86-64.d	(working copy)
@@ -1,7 +0,0 @@
-#ld:
-#readelf: -r --wide
-#target: x86_64-*-*
-
-#...
-[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_X86_64_IRELATIVE[ ]+[0-9a-f]*
-#pass
Index: bfd/elf64-x86-64.c
===================================================================
--- bfd/elf64-x86-64.c	(revision 6031)
+++ bfd/elf64-x86-64.c	(working copy)
@@ -1126,6 +1126,7 @@ elf64_x86_64_check_relocs (bfd *abfd, st
 
 		case R_X86_64_GOTPCREL:
 		case R_X86_64_GOTPCREL64:
+		  h->got.refcount += 1;
 		  if (htab->sgot == NULL
 		      && !elf64_x86_64_create_got_section (htab->elf.dynobj,
 							   info))
@@ -1837,8 +1838,13 @@ elf64_x86_64_allocate_dynrelocs (struct 
       if (h->dynindx == -1 || h->forced_local)
 	eh->dyn_relocs = NULL;
 
-      /* STT_GNU_IFUNC symbol uses .got.plt, not .got.  */
-      h->got.refcount = 0;
+      /* 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 
+	  || info->symbolic
+	  || h->forced_local)
+	h->got.refcount = 0;
     }
   else if (htab->elf.dynamic_sections_created
 	   && h->plt.refcount > 0)
@@ -2616,49 +2622,51 @@ elf64_x86_64_relocate_section (bfd *outp
 	      base_got = htab->sgot;
 	      off = h->got.offset;
 
-	      if (base_got == NULL
-		  || off != (bfd_vma) -1)
+	      if (base_got == NULL)
 		abort ();
 
-	      /* We can't use h->got.offset here to save state, or
-		 even just remember the offset, as finish_dynamic_symbol
-		 would use that as offset into .got.  */
-
-	      if (htab->splt != NULL)
-		{
-		  plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
-		  off = (plt_index + 3) * GOT_ENTRY_SIZE;
-		  base_got = htab->sgotplt;
-		}
-	      else
-		{
-		  plt_index = h->plt.offset / PLT_ENTRY_SIZE;
-		  off = plt_index * GOT_ENTRY_SIZE;
-		  base_got = htab->igotplt;
-		}
-
-	      if (h->dynindx == -1
-		  || h->forced_local
-		  || info->symbolic)
+	      if (off == (bfd_vma) -1)
 		{
-		  /* This references the local defitionion.  We must 
-		     initialize this entry in the global offset table.
-		     Since the offset must always be a multiple of 8, we
-		     use the least significant bit to record whether we
-		     have initialized it already.
+		  /* We can't use h->got.offset here to save state, or
+		     even just remember the offset, as finish_dynamic_symbol
+		     would use that as offset into .got.  */
 
-		     When doing a dynamic link, we create a .rela.got
-		     relocation entry to initialize the value.	This is
-		     done in the finish_dynamic_symbol routine.	 */
-		  if ((off & 1) != 0)
-		    off &= ~1;
+		  if (htab->splt != NULL)
+		    {
+		      plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
+		      off = (plt_index + 3) * GOT_ENTRY_SIZE;
+		      base_got = htab->sgotplt;
+		    }
 		  else
 		    {
-		      bfd_put_64 (output_bfd, relocation,
-				  base_got->contents + off);
-		      /* Note that this is harmless for the GOTPLT64 case,
-		         as -1 | 1 still is -1.  */
-		      h->got.offset |= 1;
+		      plt_index = h->plt.offset / PLT_ENTRY_SIZE;
+		      off = plt_index * GOT_ENTRY_SIZE;
+		      base_got = htab->igotplt;
+		    }
+
+		  if (h->dynindx == -1
+		      || h->forced_local
+		      || info->symbolic)
+		    {
+		      /* This references the local defitionion.  We must 
+			 initialize this entry in the global offset table.
+			 Since the offset must always be a multiple of 8, 
+			 we use the least significant bit to record
+			 whether we have initialized it already.
+
+			 When doing a dynamic link, we create a .rela.got
+			 relocation entry to initialize the value.  This
+			 is done in the finish_dynamic_symbol routine.	 */
+		      if ((off & 1) != 0)
+			off &= ~1;
+		      else
+			{
+			  bfd_put_64 (output_bfd, relocation,
+				      base_got->contents + off);
+			  /* Note that this is harmless for the GOTPLT64
+			     case, as -1 | 1 still is -1.  */
+			  h->got.offset |= 1;
+			}
 		    }
 		}
 
Index: bfd/elf32-i386.c
===================================================================
--- bfd/elf32-i386.c	(revision 6031)
+++ bfd/elf32-i386.c	(working copy)
@@ -1336,6 +1336,7 @@ elf_i386_check_relocs (bfd *abfd,
 
 		case R_386_GOT32:
 		case R_386_GOTOFF:
+		  h->got.refcount += 1;
 		  if (htab->sgot == NULL
 		      && !elf_i386_create_got_section (htab->elf.dynobj,
 						       info))
@@ -1999,8 +2000,13 @@ elf_i386_allocate_dynrelocs (struct elf_
       if (h->dynindx == -1 || h->forced_local)
 	eh->dyn_relocs = NULL;
 
-      /* STT_GNU_IFUNC symbol uses .got.plt, not .got.  */
-      h->got.refcount = 0;
+      /* 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 
+	  || info->symbolic
+	  || h->forced_local)
+	h->got.refcount = 0;
     }
   else if (htab->elf.dynamic_sections_created
 	   && h->plt.refcount > 0)
@@ -2908,55 +2914,62 @@ elf_i386_relocate_section (bfd *output_b
 	      base_got = htab->sgot;
 	      off = h->got.offset;
 
-	      if (base_got == NULL
-		  || off != (bfd_vma) -1)
+	      if (base_got == NULL)
 		abort ();
 
-	      /* We can't use h->got.offset here to save state, or
-		 even just remember the offset, as finish_dynamic_symbol
-		 would use that as offset into .got.  */
-		  
-	      if (htab->splt != NULL)
+	      if (off == (bfd_vma) -1)
 		{
-		  plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
-		  off = (plt_index + 3) * 4;
-		  base_got = htab->sgotplt;
-		}
-	      else
-		{
-		  plt_index = h->plt.offset / PLT_ENTRY_SIZE;
-		  off = plt_index * 4;
-		  base_got = htab->igotplt;
-		}
-
-	      if (h->dynindx == -1
-		  || h->forced_local
-		  || info->symbolic)
-		{
-		  /* This references the local defitionion.  We must 
-		     initialize this entry in the global offset table.
-		     Since the offset must always be a multiple of 8, we
-		     use the least significant bit to record whether we
-		     have initialized it already.
-
-		     When doing a dynamic link, we create a .rela.got
-		     relocation entry to initialize the value.	This is
-		     done in the finish_dynamic_symbol routine.	 */
-		  if ((off & 1) != 0)
-		    off &= ~1;
+		  /* We can't use h->got.offset here to save state, or
+		     even just remember the offset, as finish_dynamic_symbol
+		     would use that as offset into .got.  */
+		  
+		  if (htab->splt != NULL)
+		    {
+		      plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
+		      off = (plt_index + 3) * 4;
+		      base_got = htab->sgotplt;
+		    }
 		  else
 		    {
-		      bfd_put_32 (output_bfd, relocation,
-				  base_got->contents + off);
-		      h->got.offset |= 1;
+		      plt_index = h->plt.offset / PLT_ENTRY_SIZE;
+		      off = plt_index * 4;
+		      base_got = htab->igotplt;
 		    }
-		}
 
-	      relocation = off;
+		  if (h->dynindx == -1
+		      || h->forced_local
+		      || info->symbolic)
+		    {
+		      /* This references the local defitionion.  We must
+			 initialize this entry in the global offset table.
+			 Since the offset must always be a multiple of 8,
+			 we use the least significant bit to record
+			 whether we have initialized it already.
+
+			 When doing a dynamic link, we create a .rela.got
+			 relocation entry to initialize the value.  This
+			 is done in the finish_dynamic_symbol routine.	 */
+		      if ((off & 1) != 0)
+			off &= ~1;
+		      else
+			{
+			  bfd_put_32 (output_bfd, relocation,
+				      base_got->contents + off);
+			  h->got.offset |= 1;
+			}
+		    }
+
+		  relocation = off;
 
-	      /* Adjust for static executables.  */
-	      if (htab->splt == NULL)
-		relocation += gotplt->output_offset;
+		  /* Adjust for static executables.  */
+		  if (htab->splt == NULL)
+		    relocation += gotplt->output_offset;
+		}
+	      else
+		relocation = (base_got->output_section->vma
+			      + base_got->output_offset + off
+			      - gotplt->output_section->vma
+			      - gotplt->output_offset);
 	     
 	      goto do_relocation;
 


More information about the Binutils mailing list