This is the mail archive of the binutils@sources.redhat.com 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 linking of PIC code on PA


The enclosed patch fixes a problem noted linking PIC code into a static
executable on hppa-linux.  For example, if the following code is compiled
with -fPIC -static, it will segfault:

===
int blah; int main() { return blah; }
===

The problem is that main is called using an indirect call.  The function
pointer points directly to main rather than to a function descriptor
(plabel).  As a result, the pic register (%r19) is not initialized and
we get a segfault.

This problem affects all indirect calls to PIC functions in statically
linked programs.

In looking at possible solutions, we noted that the HP hpux linker
converts instructions with DLTIND relocs to use DPREL relocs when the
code is linked into non-shared binaries.  This allows direct calls
to PIC functions to be done without an import stub and indirect calls
to be done without a plabel in the plt.  This is both simpler than
what the elf32-hppa.c code does now, and documented in the hpux
runtime architecture document.  It also saves about four instructions
in each call.

The enclosed patch implements the above approach.  I have tested it
with binutils and GCC builds with no observed regressions.  I did
one GCC build using -fPIC and -static to test the behavior statically
linked PIC code.

As the power supply in the system that I normally use for cvs updates
is awaiting repair following failure in the blackout, this patch is just
submitted for comment.

Dave

2003-08-29  John David Anglin	<dave.anglin@nrc-cnrc.nrc.ca>
	    Randolph Chung	<randolph@tausq.org>

	* elf32-hppa.c (struct elf32_hppa_link_hash_entry,
	hppa_link_hash_newfunc, hppa_build_one_stub,
	elf32_hppa_adjust_dynamic_symbol, mark_PIC_calls, allocate_plt_static,
	allocate_dynrelocs, elf32_hppa_size_dynamic_sections,
	elf32_hppa_finish_dynamic_symbol): Remove pic_call field and all code
	for generating import stubs for calls to statically linked PIC
	functions.
	(hppa_type_of_stub): Don't generate an import stub for calls to
	statically linked pic functions.  Generate import stubs for calls
	in a shared object, to functions not in a regular file, and to
	defined weak functions.  Add new argument INFO.
	(hppa_build_one_stub): Don't undef ADDIL_DP.
	(elf32_hppa_size_stubs): Pass info to hppa_type_of_stub.
	(final_link_relocate): Change all DLTIND relocs to DPREL relocs in a
	non-shared link.  Convert instructions that use the the linkage table
	pointer, or a facsimile thereof, to use the global data pointer when
	the reloc has been changed.

Index: elf32-hppa.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-hppa.c,v
retrieving revision 1.104
diff -u -3 -p -r1.104 elf32-hppa.c
--- elf32-hppa.c	21 Aug 2003 14:00:05 -0000	1.104
+++ elf32-hppa.c	28 Aug 2003 19:18:22 -0000
@@ -203,10 +203,6 @@ struct elf32_hppa_link_hash_entry {
 #endif
   } *dyn_relocs;
 
-  /* Set if the only reason we need a .plt entry is for a non-PIC to
-     PIC function call.  */
-  unsigned int pic_call:1;
-
   /* Set if this symbol is used by a plabel reloc.  */
   unsigned int plabel:1;
 };
@@ -345,7 +341,6 @@ hppa_link_hash_newfunc (struct bfd_hash_
       eh = (struct elf32_hppa_link_hash_entry *) entry;
       eh->stub_cache = NULL;
       eh->dyn_relocs = NULL;
-      eh->pic_call = 0;
       eh->plabel = 0;
     }
 
@@ -556,7 +551,8 @@ static enum elf32_hppa_stub_type
 hppa_type_of_stub (asection *input_sec,
 		   const Elf_Internal_Rela *rel,
 		   struct elf32_hppa_link_hash_entry *hash,
-		   bfd_vma destination)
+		   bfd_vma destination,
+		   struct bfd_link_info *info)
 {
   bfd_vma location;
   bfd_vma branch_offset;
@@ -565,8 +561,11 @@ hppa_type_of_stub (asection *input_sec,
 
   if (hash != NULL
       && hash->elf.plt.offset != (bfd_vma) -1
-      && (hash->elf.dynindx != -1 || hash->pic_call)
-      && !hash->plabel)
+      && hash->elf.dynindx != -1
+      && !hash->plabel
+      && (info->shared
+	  || !(hash->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)
+	  || hash->elf.root.type == bfd_link_hash_defweak))
     {
       /* We need an import stub.  Decide between hppa_stub_import
 	 and hppa_stub_import_shared later.  */
@@ -769,39 +768,6 @@ hppa_build_one_stub (struct bfd_hash_ent
 	  size = 16;
 	}
 
-      if (!info->shared
-	  && stub_entry->h != NULL
-	  && stub_entry->h->pic_call)
-	{
-	  /* Build the .plt entry needed to call a PIC function from
-	     statically linked code.  We don't need any relocs.  */
-	  bfd *dynobj;
-	  struct elf32_hppa_link_hash_entry *eh;
-	  bfd_vma value;
-
-	  dynobj = htab->elf.dynobj;
-	  eh = (struct elf32_hppa_link_hash_entry *) stub_entry->h;
-
-	  if (eh->elf.root.type != bfd_link_hash_defined
-	      && eh->elf.root.type != bfd_link_hash_defweak)
-	    abort ();
-
-	  value = (eh->elf.root.u.def.value
-		   + eh->elf.root.u.def.section->output_offset
-		   + eh->elf.root.u.def.section->output_section->vma);
-
-	  /* Fill in the entry in the procedure linkage table.
-
-	     The format of a plt entry is
-	     <funcaddr>
-	     <__gp>.  */
-
-	  bfd_put_32 (htab->splt->owner, value,
-		      htab->splt->contents + off);
-	  value = elf_gp (htab->splt->output_section->owner);
-	  bfd_put_32 (htab->splt->owner, value,
-		      htab->splt->contents + off + 4);
-	}
       break;
 
     case hppa_stub_export:
@@ -863,7 +829,6 @@ hppa_build_one_stub (struct bfd_hash_ent
 #undef BL_R1
 #undef ADDIL_R1
 #undef DEPI_R1
-#undef ADDIL_DP
 #undef LDW_R1_R21
 #undef LDW_R1_DLT
 #undef LDW_R1_R19
@@ -1685,18 +1650,8 @@ elf32_hppa_adjust_dynamic_symbol (struct
 	     used by a plabel relocation.  Either this object is the
 	     application or we are doing a shared symbolic link.  */
 
-	  /* As a special sop to the hppa ABI, we keep a .plt entry
-	     for functions in sections containing PIC code.  */
-	  if (!info->shared
-	      && h->plt.refcount > 0
-	      && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0
-	      && (h->root.u.def.section->flags & SEC_HAS_GOT_REF) != 0)
-	    ((struct elf32_hppa_link_hash_entry *) h)->pic_call = 1;
-	  else
-	    {
-	      h->plt.offset = (bfd_vma) -1;
-	      h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
-	    }
+	  h->plt.offset = (bfd_vma) -1;
+	  h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
 	}
 
       return TRUE;
@@ -1796,34 +1751,8 @@ elf32_hppa_adjust_dynamic_symbol (struct
   return TRUE;
 }
 
-/* Called via elf_link_hash_traverse to create .plt entries for an
-   application that uses statically linked PIC functions.  Similar to
-   the first part of elf32_hppa_adjust_dynamic_symbol.  */
-
-static bfd_boolean
-mark_PIC_calls (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
-{
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
-  if (! (h->plt.refcount > 0
-	 && (h->root.type == bfd_link_hash_defined
-	     || h->root.type == bfd_link_hash_defweak)
-	 && (h->root.u.def.section->flags & SEC_HAS_GOT_REF) != 0))
-    {
-      h->plt.offset = (bfd_vma) -1;
-      h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
-      return TRUE;
-    }
-
-  h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
-  ((struct elf32_hppa_link_hash_entry *) h)->pic_call = 1;
-
-  return TRUE;
-}
-
 /* Allocate space in the .plt for entries that won't have relocations.
-   ie. pic_call and plabel entries.  */
+   ie. plabel entries.  */
 
 static bfd_boolean
 allocate_plt_static (struct elf_link_hash_entry *h, void *inf)
@@ -1840,16 +1769,7 @@ allocate_plt_static (struct elf_link_has
 
   info = inf;
   htab = hppa_link_hash_table (info);
-  if (((struct elf32_hppa_link_hash_entry *) h)->pic_call)
-    {
-      /* Make an entry in the .plt section for non-pic code that is
-	 calling pic code.  */
-      ((struct elf32_hppa_link_hash_entry *) h)->plabel = 0;
-      s = htab->splt;
-      h->plt.offset = s->_raw_size;
-      s->_raw_size += PLT_ENTRY_SIZE;
-    }
-  else if (htab->elf.dynamic_sections_created
+  if (htab->elf.dynamic_sections_created
 	   && h->plt.refcount > 0)
     {
       /* Make sure this symbol is output as a dynamic symbol.
@@ -1916,7 +1836,6 @@ allocate_dynrelocs (struct elf_link_hash
   htab = hppa_link_hash_table (info);
   if (htab->elf.dynamic_sections_created
       && h->plt.offset != (bfd_vma) -1
-      && !((struct elf32_hppa_link_hash_entry *) h)->pic_call
       && !((struct elf32_hppa_link_hash_entry *) h)->plabel)
     {
       /* Make an entry in the .plt section.  */
@@ -2114,14 +2033,6 @@ elf32_hppa_size_dynamic_sections (bfd *o
 			      clobber_millicode_symbols,
 			      info);
     }
-  else
-    {
-      /* Run through the function symbols, looking for any that are
-	 PIC, and mark them as needing .plt entries so that %r19 will
-	 be set up.  */
-      if (! info->shared)
-	elf_link_hash_traverse (&htab->elf, mark_PIC_calls, info);
-    }
 
   /* Set up .got and .plt offsets for local syms, and space for local
      dynamic relocs.  */
@@ -2871,7 +2782,7 @@ elf32_hppa_size_stubs
 
 		  /* Determine what (if any) linker stub is needed.  */
 		  stub_type = hppa_type_of_stub (section, irela, hash,
-						 destination);
+						 destination, info);
 		  if (stub_type == hppa_stub_none)
 		    continue;
 
@@ -3126,10 +3037,12 @@ final_link_relocate (asection *input_sec
 		     bfd_vma value,
 		     struct elf32_hppa_link_hash_table *htab,
 		     asection *sym_sec,
-		     struct elf32_hppa_link_hash_entry *h)
+		     struct elf32_hppa_link_hash_entry *h,
+		     struct bfd_link_info *info)
 {
   int insn;
   unsigned int r_type = ELF32_R_TYPE (rel->r_info);
+  unsigned int orig_r_type = r_type;
   reloc_howto_type *howto = elf_hppa_howto_table + r_type;
   int r_format = howto->bitsize;
   enum hppa_reloc_field_selector_type_alt r_field;
@@ -3152,6 +3065,26 @@ final_link_relocate (asection *input_sec
 	      input_section->output_offset +
 	      input_section->output_section->vma);
 
+  /* If we are not building a shared library, convert DLTIND relocs to
+     DPREL relocs.  */
+  if (!info->shared)
+    {
+      switch (r_type)
+        {
+          case R_PARISC_DLTIND21L:
+            r_type = R_PARISC_DPREL21L;
+	    break;
+
+          case R_PARISC_DLTIND14R:
+            r_type = R_PARISC_DPREL14R;
+	    break;
+
+          case R_PARISC_DLTIND14F:
+            r_type = R_PARISC_DPREL14F;
+	    break;
+	}
+    }
+
   switch (r_type)
     {
     case R_PARISC_PCREL12F:
@@ -3163,8 +3096,11 @@ final_link_relocate (asection *input_sec
 	  || sym_sec->output_section == NULL
 	  || (h != NULL
 	      && h->elf.plt.offset != (bfd_vma) -1
-	      && (h->elf.dynindx != -1 || h->pic_call)
-	      && !h->plabel))
+	      && h->elf.dynindx != -1
+	      && !h->plabel
+	      && (info->shared
+		  || !(h->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)
+		  || h->elf.root.type == bfd_link_hash_defweak)))
 	{
 	  stub_entry = hppa_get_stub_entry (input_section, sym_sec,
 					    h, rel, htab);
@@ -3204,6 +3140,38 @@ final_link_relocate (asection *input_sec
     case R_PARISC_DPREL21L:
     case R_PARISC_DPREL14R:
     case R_PARISC_DPREL14F:
+      /* Convert instructions that use the linkage table pointer (r19) to
+	 instructions that use the global data pointer (dp).  This is the
+	 most efficient way of using PIC code in an incomplete executable,
+	 but the user must follow the standard runtime conventions for
+	 accessing data for this to work.  */
+      if (orig_r_type == R_PARISC_DLTIND21L)
+	{
+	  /* Convert addil instructions if the original reloc was a
+	     DLTIND21L.  GCC sometimes uses a register other than r19 for
+	     the operation, so we must convert any addil instruction
+	     that uses this relocation.  */
+	  if ((insn & 0xfc000000) == ((int) OP_ADDIL << 26))
+	    insn = ADDIL_DP;
+	  else
+	    /* We must have a ldil instruction.  It's too hard to find
+	       and convert the associated add instruction, so issue an
+	       error.  */
+	    (*_bfd_error_handler)
+              (_("%s(%s+0x%lx): %s fixup for insn 0x%x is not supported in a non-shared link"),
+	       bfd_archive_filename (input_bfd),
+	       input_section->name,
+	       (long) rel->r_offset,
+	       howto->name,
+	       insn);
+	}
+      else if (orig_r_type == R_PARISC_DLTIND14F)
+	{
+	  /* This must be a format 1 load/store.  Change the base
+	     register to dp.  */
+	  insn = (insn & 0xfc1ffff) | (27 << 21);
+	}
+
     /* For all the DP relative relocations, we need to examine the symbol's
        section.  If it has no section or if it's a code section, then
        "data pointer relative" makes no sense.  In that case we don't
@@ -3806,7 +3774,7 @@ elf32_hppa_relocate_section (bfd *output
 	}
 
       r = final_link_relocate (input_section, contents, rel, relocation,
-			       htab, sym_sec, h);
+			       htab, sym_sec, h, info);
 
       if (r == bfd_reloc_ok)
 	continue;
@@ -3863,6 +3831,8 @@ elf32_hppa_finish_dynamic_symbol (bfd *o
 				  Elf_Internal_Sym *sym)
 {
   struct elf32_hppa_link_hash_table *htab;
+  Elf_Internal_Rela rel;
+  bfd_byte *loc;
 
   htab = hppa_link_hash_table (info);
 
@@ -3890,43 +3860,27 @@ elf32_hppa_finish_dynamic_symbol (bfd *o
 		      + h->root.u.def.section->output_section->vma);
 	}
 
-      if (! ((struct elf32_hppa_link_hash_entry *) h)->pic_call)
+      /* Create a dynamic IPLT relocation for this entry.  */
+      rel.r_offset = (h->plt.offset
+		      + htab->splt->output_offset
+		      + htab->splt->output_section->vma);
+      if (h->dynindx != -1)
 	{
-	  Elf_Internal_Rela rel;
-	  bfd_byte *loc;
-
-	  /* Create a dynamic IPLT relocation for this entry.  */
-	  rel.r_offset = (h->plt.offset
-			  + htab->splt->output_offset
-			  + htab->splt->output_section->vma);
-	  if (h->dynindx != -1)
-	    {
-	      rel.r_info = ELF32_R_INFO (h->dynindx, R_PARISC_IPLT);
-	      rel.r_addend = 0;
-	    }
-	  else
-	    {
-	      /* This symbol has been marked to become local, and is
-		 used by a plabel so must be kept in the .plt.  */
-	      rel.r_info = ELF32_R_INFO (0, R_PARISC_IPLT);
-	      rel.r_addend = value;
-	    }
-
-	  loc = htab->srelplt->contents;
-	  loc += htab->srelplt->reloc_count++ * sizeof (Elf32_External_Rela);
-	  bfd_elf32_swap_reloca_out (htab->splt->output_section->owner,
-				     &rel, loc);
+	  rel.r_info = ELF32_R_INFO (h->dynindx, R_PARISC_IPLT);
+	  rel.r_addend = 0;
 	}
       else
 	{
-	  bfd_put_32 (htab->splt->owner,
-		      value,
-		      htab->splt->contents + h->plt.offset);
-	  bfd_put_32 (htab->splt->owner,
-		      elf_gp (htab->splt->output_section->owner),
-		      htab->splt->contents + h->plt.offset + 4);
+	  /* This symbol has been marked to become local, and is
+	     used by a plabel so must be kept in the .plt.  */
+	  rel.r_info = ELF32_R_INFO (0, R_PARISC_IPLT);
+	  rel.r_addend = value;
 	}
 
+      loc = htab->srelplt->contents;
+      loc += htab->srelplt->reloc_count++ * sizeof (Elf32_External_Rela);
+      bfd_elf32_swap_reloca_out (htab->splt->output_section->owner, &rel, loc);
+
       if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
 	{
 	  /* Mark the symbol as undefined, rather than as defined in
@@ -3937,9 +3891,6 @@ elf32_hppa_finish_dynamic_symbol (bfd *o
 
   if (h->got.offset != (bfd_vma) -1)
     {
-      Elf_Internal_Rela rel;
-      bfd_byte *loc;
-
       /* This symbol has an entry in the global offset table.  Set it
 	 up.  */
 
@@ -3978,8 +3929,6 @@ elf32_hppa_finish_dynamic_symbol (bfd *o
   if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0)
     {
       asection *s;
-      Elf_Internal_Rela rel;
-      bfd_byte *loc;
 
       /* This symbol needs a copy reloc.  Set it up.  */
 


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