PATCH: Make STT_GNU_IFUNC symbol dynamic

H.J. Lu hjl.tools@gmail.com
Mon May 25 02:39:00 GMT 2009


On Sun, May 24, 2009 at 8:50 AM, Ulrich Drepper <drepper@redhat.com> wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> H.J. Lu wrote:
>> If you can check in your glibc patch, I can test my binutis change
>> before I submit it.
>
> Your patch seems fine.  You can do testing with it.  Once I have such a
> binutils version myself and can test it I'll check it in.

Here is the complete binutils patch for i386 and x86-64,  tested wih
the enclosed glibc patch on Linux/ia32 and Linux/Intel64.  I will check
it into binutlls trunk if I don't hear any objections within 12 hours.

BTW, I will post a summary to x86-64 and ia32 psABI mailing list after
my binutils patch is checked in.

Thanks.


-- 
H.J.
---
bfd/

2009-05-24  H.J. Lu  <hongjiu.lu@intel.com>

	* elf32-i386.c (elf_howto_table): Add R_386_IRELATIVE.
	(elf_i386_reloc_type_lookup): Likewise.
	(R_386_tls): Removed.
	(R_386_irelative): New.
	(R_386_vt_offset): Updated.
	(elf_i386_rtype_to_howto): Likewise.
	(elf_i386_finish_dynamic_symbol): Generate R_386_IRELATIVE
	relocation for local STT_GNU_IFUNC symbol.

	* elf64-x86-64.c (x86_64_elf_howto): Add R_X86_64_IRELATIVE.
	(x86_64_reloc_map): Likewise.
	(R_X86_64_standard): Updated.
	(elf64_x86_64_finish_dynamic_symbol): Generate R_X86_64_IRELATIVE
	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.

	* reloc.c (BFD_RELOC_386_IRELATIVE): New.
	(BFD_RELOC_X86_64_IRELATIVE): Likewise.
	* bfd-in2.h: Regenerated.
	* libbfd.h: Likewise.

include/elf/

2009-05-24  H.J. Lu  <hongjiu.lu@intel.com>

	* i386.h (R_386_IRELATIVE): New.
	* x86-64.h (R_X86_64_IRELATIVE): Likewise.

ld/testsuite/

2009-05-24  H.J. Lu  <hongjiu.lu@intel.com>

	* ld-ifunc/ifunc.exp: Run *.d.

	* ld-ifunc/ifunc-1-x86.d: New.
	* ld-ifunc/ifunc-1-x86.s: Likewise.
-------------- next part --------------
bfd/

2009-05-24  H.J. Lu  <hongjiu.lu@intel.com>

	* elf32-i386.c (elf_howto_table): Add R_386_IRELATIVE.
	(elf_i386_reloc_type_lookup): Likewise.
	(R_386_tls): Removed.
	(R_386_irelative): New.
	(R_386_vt_offset): Updated.
	(elf_i386_rtype_to_howto): Likewise.
	(elf_i386_finish_dynamic_symbol): Generate R_386_IRELATIVE
	relocation for local STT_GNU_IFUNC symbol.

	* elf64-x86-64.c (x86_64_elf_howto): Add R_X86_64_IRELATIVE.
	(x86_64_reloc_map): Likewise.
	(R_X86_64_standard): Updated.
	(elf64_x86_64_finish_dynamic_symbol): Generate R_X86_64_IRELATIVE
	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.

	* reloc.c (BFD_RELOC_386_IRELATIVE): New.
	(BFD_RELOC_X86_64_IRELATIVE): Likewise.
	* bfd-in2.h: Regenerated.
	* libbfd.h: Likewise.

include/elf/

2009-05-24  H.J. Lu  <hongjiu.lu@intel.com>

	* i386.h (R_386_IRELATIVE): New.
	* x86-64.h (R_X86_64_IRELATIVE): Likewise.

ld/testsuite/

2009-05-24  H.J. Lu  <hongjiu.lu@intel.com>

	* ld-ifunc/ifunc.exp: Run *.d.

	* ld-ifunc/ifunc-1-x86.d: New.
	* ld-ifunc/ifunc-1-x86.s: Likewise.

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/bfd-in2.h binutils/bfd/bfd-in2.h
--- ../binutils/src/bfd/bfd-in2.h	2009-05-22 11:13:32.000000000 -0700
+++ binutils/bfd/bfd-in2.h	2009-05-24 07:26:08.000000000 -0700
@@ -2837,6 +2837,7 @@ relaxation.  */
   BFD_RELOC_386_TLS_GOTDESC,
   BFD_RELOC_386_TLS_DESC_CALL,
   BFD_RELOC_386_TLS_DESC,
+  BFD_RELOC_386_IRELATIVE,
 
 /* x86-64/elf relocations  */
   BFD_RELOC_X86_64_GOT32,
@@ -2865,6 +2866,7 @@ relaxation.  */
   BFD_RELOC_X86_64_GOTPC32_TLSDESC,
   BFD_RELOC_X86_64_TLSDESC_CALL,
   BFD_RELOC_X86_64_TLSDESC,
+  BFD_RELOC_X86_64_IRELATIVE,
 
 /* ns32k relocations  */
   BFD_RELOC_NS32K_IMM_8,
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-05-05 13:59:47.000000000 -0700
+++ binutils/bfd/elf32-i386.c	2009-05-24 19:00:11.000000000 -0700
@@ -138,10 +138,13 @@ static reloc_howto_type elf_howto_table[
   HOWTO(R_386_TLS_DESC, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
 	bfd_elf_generic_reloc, "R_386_TLS_DESC",
 	TRUE, 0xffffffff, 0xffffffff, FALSE),
+  HOWTO(R_386_IRELATIVE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
+	bfd_elf_generic_reloc, "R_386_IRELATIVE",
+	TRUE, 0xffffffff, 0xffffffff, FALSE),
 
   /* Another gap.  */
-#define R_386_tls (R_386_TLS_DESC + 1 - R_386_tls_offset)
-#define R_386_vt_offset (R_386_GNU_VTINHERIT - R_386_tls)
+#define R_386_irelative (R_386_IRELATIVE + 1 - R_386_tls_offset)
+#define R_386_vt_offset (R_386_GNU_VTINHERIT - R_386_irelative)
 
 /* GNU extension to record C++ vtable hierarchy.  */
   HOWTO (R_386_GNU_VTINHERIT,	/* type */
@@ -316,6 +319,10 @@ elf_i386_reloc_type_lookup (bfd *abfd AT
       TRACE ("BFD_RELOC_386_TLS_DESC");
       return &elf_howto_table[R_386_TLS_DESC - R_386_tls_offset];
 
+    case BFD_RELOC_386_IRELATIVE:
+      TRACE ("BFD_RELOC_386_IRELATIVE");
+      return &elf_howto_table[R_386_IRELATIVE];
+
     case BFD_RELOC_VTABLE_INHERIT:
       TRACE ("BFD_RELOC_VTABLE_INHERIT");
       return &elf_howto_table[R_386_GNU_VTINHERIT - R_386_vt_offset];
@@ -355,9 +362,9 @@ elf_i386_rtype_to_howto (bfd *abfd, unsi
       && ((indx = r_type - R_386_ext_offset) - R_386_standard
 	  >= R_386_ext - R_386_standard)
       && ((indx = r_type - R_386_tls_offset) - R_386_ext
-	  >= R_386_tls - R_386_ext)
-      && ((indx = r_type - R_386_vt_offset) - R_386_tls
-	  >= R_386_vt - R_386_tls))
+	  >= R_386_irelative - R_386_ext)
+      && ((indx = r_type - R_386_vt_offset) - R_386_irelative
+	  >= R_386_vt - R_386_irelative))
     {
       (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
 			     abfd, (int) r_type);
@@ -2606,7 +2613,7 @@ elf_i386_relocate_section (bfd *output_b
 	  && ((indx = r_type - R_386_ext_offset) - R_386_standard
 	      >= R_386_ext - R_386_standard)
 	  && ((indx = r_type - R_386_tls_offset) - R_386_ext
-	      >= R_386_tls - R_386_ext))
+	      >= R_386_irelative - R_386_ext))
 	{
 	  (*_bfd_error_handler)
 	    (_("%B: unrecognized relocation (0x%x) in section `%A'"),
@@ -3684,7 +3691,10 @@ elf_i386_finish_dynamic_symbol (bfd *out
       /* 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)
@@ -3773,7 +3783,18 @@ elf_i386_finish_dynamic_symbol (bfd *out
       rel.r_offset = (htab->sgotplt->output_section->vma
 		      + htab->sgotplt->output_offset
 		      + got_offset);
-      rel.r_info = ELF32_R_INFO (h->dynindx, R_386_JUMP_SLOT);
+      if (h->dynindx != -1)
+	rel.r_info = ELF32_R_INFO (h->dynindx, R_386_JUMP_SLOT);
+      else
+	{
+	  /* Store addend in the .got.plt section.  */
+	  bfd_put_32 (output_bfd,
+		      (h->root.u.def.value 
+		       + h->root.u.def.section->output_section->vma
+		       + h->root.u.def.section->output_offset),
+		      htab->sgotplt->contents + got_offset);
+	  rel.r_info = ELF32_R_INFO (0, R_386_IRELATIVE);
+	}
       loc = htab->srelplt->contents + plt_index * sizeof (Elf32_External_Rel);
       bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
 
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-05-22 12:49:50.000000000 -0700
+++ binutils/bfd/elf64-x86-64.c	2009-05-24 07:21:45.000000000 -0700
@@ -143,12 +143,15 @@ static reloc_howto_type x86_64_elf_howto
 	complain_overflow_bitfield, bfd_elf_generic_reloc,
 	"R_X86_64_TLSDESC",
 	FALSE, MINUS_ONE, MINUS_ONE, FALSE),
+  HOWTO(R_X86_64_IRELATIVE, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
+	bfd_elf_generic_reloc, "R_X86_64_IRELATIVE", FALSE, MINUS_ONE,
+	MINUS_ONE, FALSE),
 
   /* We have a gap in the reloc numbers here.
      R_X86_64_standard counts the number up to this point, and
      R_X86_64_vt_offset is the value to subtract from a reloc type of
      R_X86_64_GNU_VT* to form an index into this table.  */
-#define R_X86_64_standard (R_X86_64_TLSDESC + 1)
+#define R_X86_64_standard (R_X86_64_IRELATIVE + 1)
 #define R_X86_64_vt_offset (R_X86_64_GNU_VTINHERIT - R_X86_64_standard)
 
 /* GNU extension to record C++ vtable hierarchy.  */
@@ -211,6 +214,7 @@ static const struct elf_reloc_map x86_64
   { BFD_RELOC_X86_64_GOTPC32_TLSDESC, R_X86_64_GOTPC32_TLSDESC, },
   { BFD_RELOC_X86_64_TLSDESC_CALL, R_X86_64_TLSDESC_CALL, },
   { BFD_RELOC_X86_64_TLSDESC,	R_X86_64_TLSDESC, },
+  { BFD_RELOC_X86_64_IRELATIVE,	R_X86_64_IRELATIVE, },
   { BFD_RELOC_VTABLE_INHERIT,	R_X86_64_GNU_VTINHERIT, },
   { BFD_RELOC_VTABLE_ENTRY,	R_X86_64_GNU_VTENTRY, },
 };
@@ -3328,7 +3332,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 +3388,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_IRELATIVE);
+	  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);
 
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/elflink.c binutils/bfd/elflink.c
--- ../binutils/src/bfd/elflink.c	2009-05-23 14:39:29.000000000 -0700
+++ binutils/bfd/elflink.c	2009-05-24 06:48:05.000000000 -0700
@@ -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;
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/libbfd.h binutils/bfd/libbfd.h
--- ../binutils/src/bfd/libbfd.h	2009-05-05 10:56:24.000000000 -0700
+++ binutils/bfd/libbfd.h	2009-05-24 07:26:08.000000000 -0700
@@ -1104,6 +1104,7 @@ static const char *const bfd_reloc_code_
   "BFD_RELOC_386_TLS_GOTDESC",
   "BFD_RELOC_386_TLS_DESC_CALL",
   "BFD_RELOC_386_TLS_DESC",
+  "BFD_RELOC_386_IRELATIVE",
   "BFD_RELOC_X86_64_GOT32",
   "BFD_RELOC_X86_64_PLT32",
   "BFD_RELOC_X86_64_COPY",
@@ -1130,6 +1131,7 @@ static const char *const bfd_reloc_code_
   "BFD_RELOC_X86_64_GOTPC32_TLSDESC",
   "BFD_RELOC_X86_64_TLSDESC_CALL",
   "BFD_RELOC_X86_64_TLSDESC",
+  "BFD_RELOC_X86_64_IRELATIVE",
   "BFD_RELOC_NS32K_IMM_8",
   "BFD_RELOC_NS32K_IMM_16",
   "BFD_RELOC_NS32K_IMM_32",
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/reloc.c binutils/bfd/reloc.c
--- ../binutils/src/bfd/reloc.c	2009-05-05 10:56:24.000000000 -0700
+++ binutils/bfd/reloc.c	2009-05-24 07:26:01.000000000 -0700
@@ -2492,6 +2492,8 @@ ENUMX
   BFD_RELOC_386_TLS_DESC_CALL
 ENUMX
   BFD_RELOC_386_TLS_DESC
+ENUMX
+  BFD_RELOC_386_IRELATIVE
 ENUMDOC
   i386/elf relocations
 
@@ -2547,6 +2549,8 @@ ENUMX
   BFD_RELOC_X86_64_TLSDESC_CALL
 ENUMX
   BFD_RELOC_X86_64_TLSDESC
+ENUMX
+  BFD_RELOC_X86_64_IRELATIVE
 ENUMDOC
   x86-64/elf relocations
 
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/include/elf/i386.h binutils/include/elf/i386.h
--- ../binutils/src/include/elf/i386.h	2009-05-05 10:56:16.000000000 -0700
+++ binutils/include/elf/i386.h	2009-05-23 18:06:03.000000000 -0700
@@ -66,6 +66,7 @@ START_RELOC_NUMBERS (elf_i386_reloc_type
      RELOC_NUMBER (R_386_TLS_GOTDESC,  39)
      RELOC_NUMBER (R_386_TLS_DESC_CALL,40)
      RELOC_NUMBER (R_386_TLS_DESC,     41)
+     RELOC_NUMBER (R_386_IRELATIVE,    42) /* Adjust indirectly by program base */
 
      /* Used by Intel.  */
      RELOC_NUMBER (R_386_USED_BY_INTEL_200, 200)
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/include/elf/x86-64.h binutils/include/elf/x86-64.h
--- ../binutils/src/include/elf/x86-64.h	2009-05-05 10:56:16.000000000 -0700
+++ binutils/include/elf/x86-64.h	2009-05-23 18:05:08.000000000 -0700
@@ -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_IRELATIVE, 37)    /* Adjust indirectly by program base */
      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)
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/ld/testsuite/ld-ifunc/ifunc-1-x86.d binutils/ld/testsuite/ld-ifunc/ifunc-1-x86.d
--- ../binutils/src/ld/testsuite/ld-ifunc/ifunc-1-x86.d	1969-12-31 16:00:00.000000000 -0800
+++ binutils/ld/testsuite/ld-ifunc/ifunc-1-x86.d	2009-05-24 19:12:28.000000000 -0700
@@ -0,0 +1,7 @@
+#ld: -shared
+#objdump: -dw
+#target: x86_64-*-* i?86-*-*
+
+#...
+[ \t0-9a-f]+:[ \t0-9a-f]+call[ \t0-9a-fq]+<\*ABS\*@plt>
+#pass
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/ld/testsuite/ld-ifunc/ifunc-1-x86.s binutils/ld/testsuite/ld-ifunc/ifunc-1-x86.s
--- ../binutils/src/ld/testsuite/ld-ifunc/ifunc-1-x86.s	1969-12-31 16:00:00.000000000 -0800
+++ binutils/ld/testsuite/ld-ifunc/ifunc-1-x86.s	2009-05-24 19:11:29.000000000 -0700
@@ -0,0 +1,16 @@
+	.type foo, %gnu_indirect_function
+	.global __GI_foo
+	.hidden __GI_foo
+	.set __GI_foo, foo
+	.text
+.globl foo
+	.type	foo, @function
+foo:
+	ret
+	.size	foo, .-foo
+.globl bar
+	.type	bar, @function
+bar:
+	call	__GI_foo@PLT
+	ret
+	.size	bar, .-bar
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/ld/testsuite/ld-ifunc/ifunc.exp binutils/ld/testsuite/ld-ifunc/ifunc.exp
--- ../binutils/src/ld/testsuite/ld-ifunc/ifunc.exp	2009-05-23 14:39:29.000000000 -0700
+++ binutils/ld/testsuite/ld-ifunc/ifunc.exp	2009-05-24 19:11:29.000000000 -0700
@@ -252,3 +252,10 @@ if { $verbose < 1 } {
     remote_file host delete "tmpdir/static_prog"
     remote_file host delete "tmpdir/static_nonifunc_prog"
 }
+
+set test_list [lsort [glob -nocomplain $srcdir/$subdir/*.d]]
+foreach t $test_list {
+    # We need to strip the ".d", but can leave the dirname.
+    verbose [file rootname $t]
+    run_dump_test [file rootname $t]
+}
-------------- next part --------------
2009-05-24  H.J. Lu  <hongjiu.lu@intel.com>

	* elf/elf.h (R_386_IRELATIVE): New.
	(R_X86_64_IRELATIVE): Likewise.
	(R_386_NUM): Updated.
	(R_X86_64_NUM): Likewise.

	* sysdeps/i386/dl-machine.h (elf_machine_rel): Check SHN_UNDEF
	for STT_GNU_IFUNC symbol.  Handle R_386_IRELATIVE.
	(elf_machine_rela): Likewise.
	(elf_machine_lazy_rel): Handle R_386_IRELATIVE.
	(elf_machine_lazy_rela): Likewise.

	* sysdeps/x86_64/dl-machine.h (elf_machine_rela): Check SHN_UNDEF
	for STT_GNU_IFUNC symbol.  Handle R_X86_64_IRELATIVE.
	(elf_machine_lazy_rel): Handle R_X86_64_IRELATIVE.

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/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-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);
 }


More information about the Binutils mailing list