GNU ld ifunc dynamic relocation order

Alan Modra amodra@gmail.com
Wed Mar 27 13:24:00 GMT 2013


This patch series is aimed at fixing STT_GNU_IFUNC dynamic relocation
order within a single powerpc binary.  Ideally, you'd like ld.so to
apply ifunc relocations last, so that ifunc resolver functions in the
binary can access variables via the GOT.  The first part here takes
care to lay out relocations in the proper order in the backend.

	* elf32-ppc.c (ppc_elf_check_relocs): Set PLT_IFUNC in local got
	masks for all local ifunc syms.
	(allocate_dynrelocs): Don't use htab->relgot for ifunc.
	(ppc_elf_size_dynamic_sections): Likewise.
	(ppc_elf_relocate_section): Likewise.

Index: bfd/elf32-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-ppc.c,v
retrieving revision 1.327
diff -u -p -r1.327 elf32-ppc.c
--- bfd/elf32-ppc.c	4 Mar 2013 12:12:11 -0000	1.327
+++ bfd/elf32-ppc.c	27 Mar 2013 10:50:56 -0000
@@ -3921,13 +3921,11 @@ ppc_elf_check_relocs (bfd *abfd,
 	  if (isym == NULL)
 	    return FALSE;
 
-	  if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC
-	      && (!info->shared
-		  || is_branch_reloc (r_type)))
+	  if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
 	    {
 	      struct plt_entry **ifunc;
-	      bfd_vma addend;
 
+	      /* Set PLT_IFUNC flag for this sym, no GOT entry yet.  */
 	      ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
 					     PLT_IFUNC);
 	      if (ifunc == NULL)
@@ -3936,15 +3934,19 @@ ppc_elf_check_relocs (bfd *abfd,
 	      /* STT_GNU_IFUNC symbols must have a PLT entry;
 		 In a non-pie executable even when there are
 		 no plt calls.  */
-	      addend = 0;
-	      if (r_type == R_PPC_PLTREL24)
+	      if (!info->shared
+		  || is_branch_reloc (r_type))
 		{
-		  ppc_elf_tdata (abfd)->makes_plt_call = 1;
-		  if (info->shared)
-		    addend = rel->r_addend;
+		  bfd_vma addend = 0;
+		  if (r_type == R_PPC_PLTREL24)
+		    {
+		      ppc_elf_tdata (abfd)->makes_plt_call = 1;
+		      if (info->shared)
+			addend = rel->r_addend;
+		    }
+		  if (!update_plt_info (abfd, ifunc, got2, addend))
+		    return FALSE;
 		}
-	      if (!update_plt_info (abfd, ifunc, got2, addend))
-		return FALSE;
 	    }
 	}
 
@@ -5901,6 +5903,9 @@ allocate_dynrelocs (struct elf_link_hash
 		  || eh->elf.root.type != bfd_link_hash_undefweak))
 	    {
 	      asection *rsec = htab->relgot;
+
+	      if (eh->elf.type == STT_GNU_IFUNC)
+		rsec = htab->reliplt;
 	      /* All the entries we allocated need relocs.
 		 Except LD only needs one.  */
 	      if ((eh->tls_mask & TLS_LD) != 0
@@ -6181,8 +6186,12 @@ ppc_elf_size_dynamic_sections (bfd *outp
 	      {
 		*local_got = allocate_got (htab, need);
 		if (info->shared)
-		  htab->relgot->size += (need
-					 * (sizeof (Elf32_External_Rela) / 4));
+		  {
+		    asection *srel = htab->relgot;
+		    if ((*lgot_masks & PLT_IFUNC) != 0)
+		      srel = htab->reliplt;
+		    srel->size += need * (sizeof (Elf32_External_Rela) / 4);
+		  }
 	      }
 	  }
 	else
@@ -7987,6 +7996,8 @@ ppc_elf_relocate_section (bfd *output_bf
 			asection *rsec = htab->relgot;
 			bfd_byte * loc;
 
+			if (ifunc != NULL)
+			  rsec = htab->reliplt;
 			outrel.r_offset = (htab->got->output_section->vma
 					   + htab->got->output_offset
 					   + off);

-- 
Alan Modra
Australia Development Lab, IBM



More information about the Binutils mailing list