# DP: Fix PR ld/13302, taken from the trunk

bfd/

2012-03-06  Jakub Jelinek  <jakub@redhat.com>

        * elf64-x86-64.c (elf_x86_64_relocate_section): For R_X86_64_RELATIVE
        set relocate to TRUE.

2011-10-21  H.J. Lu  <hongjiu.lu@intel.com>

	PR ld/13302
	* elf32-i386.c (elf_i386_relocate_section): Replace
	R_386_IRELATIVE with R_386_RELATIVE.

	* elf64-x86-64.c (elf_x86_64_relocate_section): Replace
	R_X86_64_IRELATIVE with R_X86_64_RELATIVE.

2011-10-21  H.J. Lu  <hongjiu.lu@intel.com>.

	* elf32-i386.c (elf_i386_relocate_section): Fix a typo in
	comments.
	* elf64-x86-64.c (elf_x86_64_relocate_section): Likewise.

2011-10-21  H.J. Lu  <hongjiu.lu@intel.com>

	PR ld/13302
	* elf32-i386.c (elf_i386_link_hash_table): Add next_jump_slot_index
	and next_irelative_index.
	(elf_i386_link_hash_table_create): Initialize next_jump_slot_index
	and next_irelative_index.
	(elf_i386_allocate_dynrelocs): Increment reloc_count instead of
	next_tls_desc_index.
	(elf_i386_size_dynamic_sections): Set next_tls_desc_index and
	next_irelative_index from reloc_count.
	(elf_i386_finish_dynamic_symbol): Put R_386_IRELATIVE after
	R_386_JUMP_SLOT.

	* elf64-x86-64.c (elf_x86_64_link_hash_table): Add
	next_jump_slot_index and next_irelative_index.
	(elf_x86_64_link_hash_table_create): Initialize
	next_jump_slot_index and next_irelative_index.
	(elf_x86_64_size_dynamic_sections): Set next_irelative_index
	from reloc_count.
	(elf_x86_64_finish_dynamic_symbol): Put R_X86_64_IRELATIVE after
	R_X86_64_JUMP_SLOT.

ld/testsuite

2011-10-21  H.J. Lu  <hongjiu.lu@intel.com>

	PR ld/13302
	* ld-i386/i386.exp: Run pr13302.

	* ld-i386/pr13302.d: New.
	* ld-i386/pr13302.s: Likewise.

	* ld-x86-64/pr13082-5b.d: Updated.
	* ld-x86-64/pr13082-6a.d: Likewise.
	* ld-x86-64/pr13082-6b.d: Likewise.

2011-10-21  H.J. Lu  <hongjiu.lu@intel.com>

	PR ld/13302
	* ld-ifunc/ifunc-16-i386.d: New.
	* ld-ifunc/ifunc-16-x86-64.d: Likewise.
	* ld-ifunc/ifunc-16-x86.s: Likewise.

diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index 7ef1fc1..d187305 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -806,6 +806,12 @@ struct elf_i386_link_hash_table
 
   /* The index of the next unused R_386_TLS_DESC slot in .rel.plt.  */
   bfd_vma next_tls_desc_index;
+
+  /* The index of the next unused R_386_JUMP_SLOT slot in .rel.plt.  */
+  bfd_vma next_jump_slot_index;
+
+  /* The index of the next unused R_386_IRELATIVE slot in .rel.plt.  */
+  bfd_vma next_irelative_index;
 };
 
 /* Get the i386 ELF linker hash table from a link_info structure.  */
@@ -946,6 +952,8 @@ elf_i386_link_hash_table_create (bfd *abfd)
   ret->sym_cache.abfd = NULL;
   ret->srelplt2 = NULL;
   ret->tls_module_base = NULL;
+  ret->next_jump_slot_index = 0;
+  ret->next_irelative_index = 0;
 
   ret->loc_hash_table = htab_try_create (1024,
 					 elf_i386_local_htab_hash,
@@ -2275,7 +2283,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 
 	  /* We also need to make an entry in the .rel.plt section.  */
 	  htab->elf.srelplt->size += sizeof (Elf32_External_Rel);
-	  htab->next_tls_desc_index++;
+	  htab->elf.srelplt->reloc_count++;
 
 	  if (get_elf_i386_backend_data (info->output_bfd)->is_vxworks
               && !info->shared)
@@ -2700,9 +2708,19 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
      incremented.  However, when we reserve space for TLS descriptors,
      it's not incremented, so in order to compute the space reserved
      for them, it suffices to multiply the reloc count by the jump
-     slot size.  */
+     slot size.
+     
+     PR ld/13302: We start next_irelative_index at the end of .rela.plt
+     so that R_386_IRELATIVE entries come last.  */
   if (htab->elf.srelplt)
-    htab->sgotplt_jump_table_size = htab->next_tls_desc_index * 4;
+    {
+      htab->next_tls_desc_index = htab->elf.srelplt->reloc_count;
+      htab->sgotplt_jump_table_size = htab->next_tls_desc_index * 4;
+      htab->next_irelative_index = htab->elf.srelplt->reloc_count - 1;
+    }
+  else if (htab->elf.irelplt)
+    htab->next_irelative_index = htab->elf.irelplt->reloc_count - 1;
+
 
   if (htab->elf.sgotplt)
     {
@@ -3232,13 +3250,14 @@ elf_i386_relocate_section (bfd *output_bfd,
 
 	    case R_386_32:
 	      /* Generate dynamic relcoation only when there is a
-		 non-GOF reference in a shared object.  */
+		 non-GOT reference in a shared object.  */
 	      if (info->shared && h->non_got_ref)
 		{
 		  Elf_Internal_Rela outrel;
 		  bfd_byte *loc;
 		  asection *sreloc;
 		  bfd_vma offset;
+		  bfd_boolean relocate;
 
 		  /* Need a dynamic relocation to get the real function
 		     adddress.  */
@@ -3259,15 +3278,14 @@ elf_i386_relocate_section (bfd *output_bfd,
 		      || info->executable)
 		    {
 		      /* This symbol is resolved locally.  */
-		      outrel.r_info = ELF32_R_INFO (0, R_386_IRELATIVE);
-		      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),
-				  contents + offset);
+		      outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
+		      relocate = TRUE;
 		    }
 		  else
-		    outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
+		    {
+		      outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
+		      relocate = FALSE;
+		    }
 
 		  sreloc = htab->elf.irelifunc;
 		  loc = sreloc->contents;
@@ -3280,7 +3298,8 @@ elf_i386_relocate_section (bfd *output_bfd,
 		     we need to include the symbol value so that it
 		     becomes an addend for the dynamic reloc.  For an
 		     internal symbol, we have updated addend.  */
-		  continue;
+		  if (! relocate)
+		    continue;
 		}
 	      /* FALLTHROUGH */
 	    case R_386_PC32:
@@ -4364,13 +4383,13 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
 
       if (plt == htab->elf.splt)
 	{
-	  plt_index = h->plt.offset / plt_entry_size - 1;
-	  got_offset = (plt_index + 3) * 4;
+	  got_offset = h->plt.offset / plt_entry_size - 1;
+	  got_offset = (got_offset + 3) * 4;
 	}
       else
 	{
-	  plt_index = h->plt.offset / plt_entry_size;
-	  got_offset = plt_index * 4;
+	  got_offset = h->plt.offset / plt_entry_size;
+	  got_offset = got_offset * 4;
 	}
 
       /* Fill in the entry in the procedure linkage table.  */
@@ -4431,18 +4450,6 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
                       + abed->plt->plt_got_offset);
 	}
 
-      /* Don't fill PLT entry for static executables.  */
-      if (plt == htab->elf.splt)
-	{
-	  bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rel),
-		      plt->contents + h->plt.offset
-                      + abed->plt->plt_reloc_offset);
-	  bfd_put_32 (output_bfd, - (h->plt.offset
-                                     + abed->plt->plt_plt_offset + 4),
-		      plt->contents + h->plt.offset
-                      + abed->plt->plt_plt_offset);
-	}
-
       /* Fill in the entry in the global offset table.  */
       bfd_put_32 (output_bfd,
 		  (plt->output_section->vma
@@ -4470,12 +4477,29 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
 		       + h->root.u.def.section->output_offset),
 		      gotplt->contents + got_offset);
 	  rel.r_info = ELF32_R_INFO (0, R_386_IRELATIVE);
+	  /* R_386_IRELATIVE comes last.  */
+	  plt_index = htab->next_irelative_index--;
 	}
       else
-	rel.r_info = ELF32_R_INFO (h->dynindx, R_386_JUMP_SLOT);
+	{
+	  rel.r_info = ELF32_R_INFO (h->dynindx, R_386_JUMP_SLOT);
+	  plt_index = htab->next_jump_slot_index++;
+	}
       loc = relplt->contents + plt_index * sizeof (Elf32_External_Rel);
       bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
 
+      /* Don't fill PLT entry for static executables.  */
+      if (plt == htab->elf.splt)
+	{
+	  bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rel),
+		      plt->contents + h->plt.offset
+                      + abed->plt->plt_reloc_offset);
+	  bfd_put_32 (output_bfd, - (h->plt.offset
+                                     + abed->plt->plt_plt_offset + 4),
+		      plt->contents + h->plt.offset
+                      + abed->plt->plt_plt_offset);
+	}
+
       if (!h->def_regular)
 	{
 	  /* Mark the symbol as undefined, rather than as defined in
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index e4c3946..2206dd4 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -698,6 +698,11 @@ struct elf_x86_64_link_hash_table
   /* The offset into sgot of the GOT entry used by the PLT entry
      above.  */
   bfd_vma tlsdesc_got;
+
+  /* The index of the next R_X86_64_JUMP_SLOT entry in .rela.plt.  */
+  bfd_vma next_jump_slot_index;
+  /* The index of the next R_X86_64_IRELATIVE entry in .rela.plt.  */
+  bfd_vma next_irelative_index;
 };
 
 /* Get the x86-64 ELF linker hash table from a link_info structure.  */
@@ -839,6 +844,8 @@ elf_x86_64_link_hash_table_create (bfd *abfd)
   ret->tls_ld_got.refcount = 0;
   ret->sgotplt_jump_table_size = 0;
   ret->tls_module_base = NULL;
+  ret->next_jump_slot_index = 0; 
+  ret->next_irelative_index = 0;
 
   if (ABI_64_P (abfd))
     {
@@ -2667,10 +2674,18 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
      incremented.  However, when we reserve space for TLS descriptors,
      it's not incremented, so in order to compute the space reserved
      for them, it suffices to multiply the reloc count by the jump
-     slot size.  */
+     slot size.
+
+     PR ld/13302: We start next_irelative_index at the end of .rela.plt
+     so that R_X86_64_IRELATIVE entries come last.  */
   if (htab->elf.srelplt)
-    htab->sgotplt_jump_table_size
-      = elf_x86_64_compute_jump_table_size (htab);
+    {
+      htab->sgotplt_jump_table_size
+	= elf_x86_64_compute_jump_table_size (htab);
+      htab->next_irelative_index = htab->elf.srelplt->reloc_count - 1;
+    }
+  else if (htab->elf.irelplt)
+    htab->next_irelative_index = htab->elf.irelplt->reloc_count - 1;
 
   if (htab->tlsdesc_plt)
     {
@@ -3141,11 +3156,12 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 		}
 
 	      /* Generate dynamic relcoation only when there is a
-		 non-GOF reference in a shared object.  */
+		 non-GOT reference in a shared object.  */
 	      if (info->shared && h->non_got_ref)
 		{
 		  Elf_Internal_Rela outrel;
 		  asection *sreloc;
+		  bfd_boolean relocate;
 
 		  /* Need a dynamic relocation to get the real function
 		     address.  */
@@ -3165,15 +3181,15 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 		      || info->executable)
 		    {
 		      /* This symbol is resolved locally.  */
-		      outrel.r_info = htab->r_info (0, R_X86_64_IRELATIVE);
-		      outrel.r_addend = (h->root.u.def.value
-					 + h->root.u.def.section->output_section->vma
-					 + h->root.u.def.section->output_offset);
+		      outrel.r_info = htab->r_info (0, R_X86_64_RELATIVE);
+		      outrel.r_addend = relocation;
+		      relocate = TRUE;
 		    }
 		  else
 		    {
 		      outrel.r_info = htab->r_info (h->dynindx, r_type);
 		      outrel.r_addend = 0;
+		      relocate = FALSE;
 		    }
 
 		  sreloc = htab->elf.irelifunc;
@@ -3184,7 +3200,8 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 		     we need to include the symbol value so that it
 		     becomes an addend for the dynamic reloc.  For an
 		     internal symbol, we have updated addend.  */
-		  continue;
+		  if (! relocate)
+		    continue;
 		}
 	      /* FALLTHROUGH */
 	    case R_X86_64_PC32:
@@ -4205,13 +4222,13 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
 
       if (plt == htab->elf.splt)
 	{
-	  plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
-	  got_offset = (plt_index + 3) * GOT_ENTRY_SIZE;
+	  got_offset = h->plt.offset / PLT_ENTRY_SIZE - 1;
+	  got_offset = (got_offset + 3) * GOT_ENTRY_SIZE;
 	}
       else
 	{
-	  plt_index = h->plt.offset / PLT_ENTRY_SIZE;
-	  got_offset = plt_index * GOT_ENTRY_SIZE;
+	  got_offset = h->plt.offset / PLT_ENTRY_SIZE;
+	  got_offset = got_offset * GOT_ENTRY_SIZE;
 	}
 
       /* Fill in the entry in the procedure linkage table.  */
@@ -4233,17 +4250,6 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
 		       - 6),
 		  plt->contents + h->plt.offset + 2);
 
-      /* Don't fill PLT entry for static executables.  */
-      if (plt == htab->elf.splt)
-	{
-	  /* Put relocation index.  */
-	  bfd_put_32 (output_bfd, plt_index,
-		      plt->contents + h->plt.offset + 7);
-	  /* Put offset for jmp .PLT0.  */
-	  bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
-		      plt->contents + h->plt.offset + 12);
-	}
-
       /* Fill in the entry in the global offset table, initially this
 	 points to the pushq instruction in the PLT which is at offset 6.  */
       bfd_put_64 (output_bfd, (plt->output_section->vma
@@ -4267,11 +4273,25 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
 	  rela.r_addend = (h->root.u.def.value
 			   + h->root.u.def.section->output_section->vma
 			   + h->root.u.def.section->output_offset);
+	  /* R_X86_64_IRELATIVE comes last.  */
+	  plt_index = htab->next_irelative_index--;
 	}
       else
 	{
 	  rela.r_info = htab->r_info (h->dynindx, R_X86_64_JUMP_SLOT);
 	  rela.r_addend = 0;
+	  plt_index = htab->next_jump_slot_index++;
+	}
+
+      /* Don't fill PLT entry for static executables.  */
+      if (plt == htab->elf.splt)
+	{
+	  /* Put relocation index.  */
+	  bfd_put_32 (output_bfd, plt_index,
+		      plt->contents + h->plt.offset + 7);
+	  /* Put offset for jmp .PLT0.  */
+	  bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
+		      plt->contents + h->plt.offset + 12);
 	}
 
       bed = get_elf_backend_data (output_bfd);
diff --git a/ld/testsuite/ld-i386/i386.exp b/ld/testsuite/ld-i386/i386.exp
index 68b71fb..1727922 100644
--- a/ld/testsuite/ld-i386/i386.exp
+++ b/ld/testsuite/ld-i386/i386.exp
@@ -210,3 +210,4 @@ if { !([istarget "i?86-*-linux*"]
 
 run_dump_test "compressed1"
 run_dump_test "pr12627"
+run_dump_test "pr13302"
diff --git a/ld/testsuite/ld-i386/pr13302.d b/ld/testsuite/ld-i386/pr13302.d
new file mode 100644
index 0000000..3d85d08
--- /dev/null
+++ b/ld/testsuite/ld-i386/pr13302.d
@@ -0,0 +1,12 @@
+#name: PR ld/13302
+#as: --32
+#ld: -pie -melf_i386
+#readelf: -r --wide
+
+Relocation section '.rel.dyn' at offset 0x[0-9a-f]+ contains 1 entries:
+ Offset     Info    Type                Sym. Value  Symbol's Name
+[0-9a-f]+ +[0-9a-f]+ +R_386_RELATIVE +
+
+Relocation section '.rel.plt' at offset 0x[0-9a-f]+ contains 1 entries:
+ Offset     Info    Type                Sym. Value  Symbol's Name
+[0-9a-f]+ +[0-9a-f]+ +R_386_IRELATIVE +
diff --git a/ld/testsuite/ld-i386/pr13302.s b/ld/testsuite/ld-i386/pr13302.s
new file mode 100644
index 0000000..cfd2717
--- /dev/null
+++ b/ld/testsuite/ld-i386/pr13302.s
@@ -0,0 +1,11 @@
+	.text
+	.globl _start
+	.type ifunc, @gnu_indirect_function
+_start:
+	lea	.Ljmp@GOTOFF(%ebx), %eax
+ifunc:
+	jmp	*(%eax)
+	.section	.data.rel.ro.local,"aw",@progbits
+	.align	4
+.Ljmp:
+	.long ifunc
diff --git a/ld/testsuite/ld-ifunc/ifunc-16-i386.d b/ld/testsuite/ld-ifunc/ifunc-16-i386.d
new file mode 100644
index 0000000..8ae3d0a
--- /dev/null
+++ b/ld/testsuite/ld-ifunc/ifunc-16-i386.d
@@ -0,0 +1,10 @@
+#source: ifunc-16-x86.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_JUMP_SLOT[ ]+0+[ ]+ifunc
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_386_IRELATIVE[ ]*
diff --git a/ld/testsuite/ld-ifunc/ifunc-16-x86-64.d b/ld/testsuite/ld-ifunc/ifunc-16-x86-64.d
new file mode 100644
index 0000000..d69626d
--- /dev/null
+++ b/ld/testsuite/ld-ifunc/ifunc-16-x86-64.d
@@ -0,0 +1,10 @@
+#source: ifunc-16-x86.s
+#as: --64
+#ld: -shared -melf_x86_64
+#readelf: -r --wide
+#target: x86_64-*-*
+
+Relocation section '.rela.plt' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_X86_64_JUMP_SLOT[ ]+0+[ ]+ifunc \+ 0
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_X86_64_IRELATIVE[ ]+[0-9a-f]*
diff --git a/ld/testsuite/ld-ifunc/ifunc-16-x86.s b/ld/testsuite/ld-ifunc/ifunc-16-x86.s
new file mode 100644
index 0000000..fb38253
--- /dev/null
+++ b/ld/testsuite/ld-ifunc/ifunc-16-x86.s
@@ -0,0 +1,17 @@
+	.text
+	.globl	fct
+	.type	fct, @gnu_indirect_function
+	.set	fct,resolve
+	.hidden int_fct
+	.globl	int_fct
+	.set	int_fct,fct
+	.p2align 4,,15
+	.type	resolve, @function
+resolve:
+	call	ifunc@PLT
+	.size	resolve, .-resolve
+	.globl	g
+	.type	g, @function
+g:
+	jmp	int_fct@PLT
+	.size	g, .-g
diff --git a/ld/testsuite/ld-x86-64/pr13082-5b.d b/ld/testsuite/ld-x86-64/pr13082-5b.d
index 1c5a5e7..48e37c3 100644
--- a/ld/testsuite/ld-x86-64/pr13082-5b.d
+++ b/ld/testsuite/ld-x86-64/pr13082-5b.d
@@ -6,7 +6,7 @@
 
 Relocation section '.rela.dyn' at offset 0x[0-9a-f]+ contains 1 entries:
  Offset     Info    Type                Sym. Value  Symbol's Name \+ Addend
-[0-9a-f]+ +[0-9a-f]+ +R_X86_64_IRELATIVE +[0-9a-f]+
+[0-9a-f]+ +[0-9a-f]+ +R_X86_64_RELATIVE +[0-9a-f]+
 
 Relocation section '.rela.plt' at offset 0x[0-9a-f]+ contains 1 entries:
  Offset     Info    Type                Sym. Value  Symbol's Name \+ Addend
diff --git a/ld/testsuite/ld-x86-64/pr13082-6a.d b/ld/testsuite/ld-x86-64/pr13082-6a.d
index 9a1a655..de90bb8 100644
--- a/ld/testsuite/ld-x86-64/pr13082-6a.d
+++ b/ld/testsuite/ld-x86-64/pr13082-6a.d
@@ -6,7 +6,7 @@
 
 Relocation section '.rela.dyn' at offset 0x[0-9a-f]+ contains 1 entries:
  Offset     Info    Type                Sym. Value  Symbol's Name \+ Addend
-[0-9a-f]+ +[0-9a-f]+ +R_X86_64_IRELATIVE +[0-9a-f]+
+[0-9a-f]+ +[0-9a-f]+ +R_X86_64_RELATIVE +[0-9a-f]+
 
 Relocation section '.rela.plt' at offset 0x[0-9a-f]+ contains 1 entries:
  Offset     Info    Type                Sym. Value  Symbol's Name \+ Addend
diff --git a/ld/testsuite/ld-x86-64/pr13082-6b.d b/ld/testsuite/ld-x86-64/pr13082-6b.d
index 792c348..66ff59b 100644
--- a/ld/testsuite/ld-x86-64/pr13082-6b.d
+++ b/ld/testsuite/ld-x86-64/pr13082-6b.d
@@ -6,7 +6,7 @@
 
 Relocation section '.rela.dyn' at offset 0x[0-9a-f]+ contains 1 entries:
  Offset     Info    Type                Sym. Value  Symbol's Name \+ Addend
-[0-9a-f]+ +[0-9a-f]+ +R_X86_64_IRELATIVE +[0-9a-f]+
+[0-9a-f]+ +[0-9a-f]+ +R_X86_64_RELATIVE +[0-9a-f]+
 
 Relocation section '.rela.plt' at offset 0x[0-9a-f]+ contains 1 entries:
  Offset     Info    Type                Sym. Value  Symbol's Name \+ Addend