summary refs log tree commit diff
path: root/sysdeps
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2004-04-17 22:57:01 +0000
committerUlrich Drepper <drepper@redhat.com>2004-04-17 22:57:01 +0000
commit69ac9d0793dd675cf49fa3ce6796a0dce227c076 (patch)
tree6e57d02cf5268af95afdef4012fa0379332285c0 /sysdeps
parent5339290658a4c9e8c8d9e6d95ae27705fdd59c10 (diff)
downloadglibc-69ac9d0793dd675cf49fa3ce6796a0dce227c076.tar.gz
glibc-69ac9d0793dd675cf49fa3ce6796a0dce227c076.tar.xz
glibc-69ac9d0793dd675cf49fa3ce6796a0dce227c076.zip
Update.
2004-04-04  Carlos O'Donell  <carlos@baldric.uwo.ca>

	* sysdeps/hppa/Dist: Add bits/link.h elf/entry.h.

	* sysdeps/hppa/bits/link.h: New file.

	* sysdeps/hppa/dl-machine.h (__hppa_init_bootstrap_fdesc_table):
	Initialze the fdesc table for the generic code.
	(elf_machine_dynamic): Use asm version.
	(elf_machine_load_addresss): Simplify asm by calling
	elf_machine_dynamic.
	(elf_machine_fixup_plt): Correct comment.
	(elf_machine_profile_fixup_plt): New.
	(elf_machine_runtime_setup): Check PLT exists, if lazy=1  process
	normally, else relocate all the absolute entries.
	(RTLD_START): Fix comments.
	(TRAMPOLINE_TEMPLATE): Reformat assembly, add return pointer for
	calls to profile_fixup.
	(ELF_MACHINE_SIZEOF_JMP_SLOT, DL_STATIC_FUNCTION_ADDRESS,
	DL_PLATFORM_INIT): Define.
	(DL_FUNCTION_ADDRESS): Remove.
	(dl_platform_init): New.
	(elf_machine_rela): Use generic fdesc code, and process all COPY
	relocations. Use __attribute__((always_inline)).
	(elf_machine_rela_relative): Add sanity checks, remove IPLT
	processing, print error message in default case. Use
	__attribute__((always_inline)).
	(elf_machine_lazy_rel): Use __attribute__((always_inline)).

2004-04-05  Carlos O'Donell  <carlos@baldric.uwo.ca>

	* sysdeps/hppa/fpu/feupdateenv.c (feupdateenv): Use only sw[0]
	and call feraiseexcept.

2003-11-15  Randolph Chung  <tausq@debian.org>

	* gmon/gmon.c (__monstartup): Round kcountsize to multiples of
	the froms[] array so the array is properly aligned.

2004-04-05  H.J. Lu  <hongjiu.lu@intel.com>

	* Makeconfig (libgcc_eh): Add -Wl,.

	* configure.in: Add -lgcc_s for --as-needed check.

2004-04-16  Kaz Kojima  <kkojima@rr.iij4u.or.jp>

	* sysdeps/sh/elf/configure.in: New file.

	* iconvdata/gconv-modules: Add PT154 and RK1048 entries.
	* iconvdata/tst-tables.sh: Add PT154 and RK1048.
	* iconvdata/Makefile (modules): Add PT154 anhd RK1048.
	(distribute): Add pt154.c and rk1048.c.
	(gen-8bit-gap-modules): Add pt154 and rk1048.
	* icondata/pt154.c: New file.
	* iconvdata/rk1048.c: New file.
Diffstat (limited to 'sysdeps')
-rw-r--r--sysdeps/hppa/Dist2
-rw-r--r--sysdeps/hppa/bits/link.h6
-rw-r--r--sysdeps/hppa/dl-machine.h575
-rw-r--r--sysdeps/hppa/fpu/feupdateenv.c5
4 files changed, 330 insertions, 258 deletions
diff --git a/sysdeps/hppa/Dist b/sysdeps/hppa/Dist
index e26e411bc5..5a0df47c68 100644
--- a/sysdeps/hppa/Dist
+++ b/sysdeps/hppa/Dist
@@ -1,3 +1,5 @@
 libgcc-compat.c
 dl-symaddr.c
 dl-fptr.c
+bits/link.h
+elf/entry.h
diff --git a/sysdeps/hppa/bits/link.h b/sysdeps/hppa/bits/link.h
new file mode 100644
index 0000000000..54842b2299
--- /dev/null
+++ b/sysdeps/hppa/bits/link.h
@@ -0,0 +1,6 @@
+/* Used to store the function descriptor table */
+struct link_map_machine
+  {
+    size_t fptr_table_len;
+    ElfW(Addr) *fptr_table;
+  };
diff --git a/sysdeps/hppa/dl-machine.h b/sysdeps/hppa/dl-machine.h
index cd180e7f76..bc9ed107b8 100644
--- a/sysdeps/hppa/dl-machine.h
+++ b/sysdeps/hppa/dl-machine.h
@@ -1,5 +1,5 @@
 /* Machine-dependent ELF dynamic relocation inline functions.  PA-RISC version.
-   Copyright (C) 1995-1997,1999,2000,2001,2002, 2003
+   Copyright (C) 1995-1997,1999-2003
 	Free Software Foundation, Inc.
    Contributed by David Huggins-Daines <dhd@debian.org>
    This file is part of the GNU C Library.
@@ -25,40 +25,52 @@
 #define ELF_MACHINE_NAME "hppa"
 
 #include <sys/param.h>
+#include <assert.h>
 #include <string.h>
 #include <link.h>
-#include <assert.h>
-
-/* These must match the definition of the stub in bfd/elf32-hppa.c. */
-#define SIZEOF_PLT_STUB (4*4)
+#include <errno.h>
+#include <dl-fptr.h>
+#include <abort-instr.h>
+
+# define VALID_ELF_OSABI(osabi)		((osabi == ELFOSABI_SYSV) || (osabi == ELFOSABI_LINUX))
+# define VALID_ELF_ABIVERSION(ver)	(ver == 0)
+# define VALID_ELF_HEADER(hdr,exp,size) \
+  memcmp (hdr,exp,size-2) == 0 \
+  && VALID_ELF_OSABI (hdr[EI_OSABI]) \
+  && VALID_ELF_ABIVERSION (hdr[EI_ABIVERSION])
+
+/* These two definitions must match the definition of the stub in 
+   bfd/elf32-hppa.c (see plt_stub[]).
+   
+   a. Define the size of the *entire* stub we place at the end of the PLT
+   table (right up against the GOT).
+   
+   b. Define the number of bytes back from the GOT to the entry point of
+   the PLT stub. You see the PLT stub must be entered in the middle
+   so it can depwi to find it's own address (long jump stub) 
+   
+   c. Define the size of a single PLT entry so we can jump over the
+   last entry to get the stub address */
+	
+#define SIZEOF_PLT_STUB (7*4)
 #define GOT_FROM_PLT_STUB (4*4)
+#define PLT_ENTRY_SIZE (2*4)
 
-/* A PLABEL is a function descriptor.  Properly they consist of just
-   FUNC and GP.  But we want to traverse a binary tree too.  See
-   dl-fptr.c for the code (it may be made common between HPPA and
-   IA-64 in the future).
-
-   We call these 'fptr' to make it easier to steal code from IA-64. */
-
-/* ld.so currently has 12 PLABEL32 relocs.  We'll keep this constant
-   large for now in case we require more, as the rest of these will be
-   used by the dynamic program itself (libc.so has quite a few
-   PLABEL32 relocs in it). */
-#define HPPA_BOOT_FPTR_SIZE	256
-
-struct hppa_fptr
+/* Initialize the function descriptor table before relocations */
+static inline void
+__hppa_init_bootstrap_fdesc_table (struct link_map *map)
 {
-  Elf32_Addr func;
-  Elf32_Addr gp;
-  struct hppa_fptr *next;
-};
+  ElfW(Addr) *boot_table;
+
+  /* Careful: this will be called before got has been relocated... */
+  ELF_MACHINE_LOAD_ADDRESS(boot_table,_dl_boot_fptr_table);
 
-extern struct hppa_fptr __boot_ldso_fptr[];
-extern struct hppa_fptr *__fptr_root;
-extern int __fptr_count;
+  map->l_mach.fptr_table_len = ELF_MACHINE_BOOT_FPTR_TABLE_LEN;
+  map->l_mach.fptr_table = boot_table;
+}
 
-extern Elf32_Addr __hppa_make_fptr (const struct link_map *, Elf32_Addr,
-				    struct hppa_fptr **, struct hppa_fptr *);
+#define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info)		\
+	__hppa_init_bootstrap_fdesc_table (&bootstrap_map);
 
 /* Return nonzero iff ELF header is compatible with the running host.  */
 static inline int
@@ -67,55 +79,52 @@ elf_machine_matches_host (const Elf32_Ehdr *ehdr)
   return ehdr->e_machine == EM_PARISC;
 }
 
-
 /* Return the link-time address of _DYNAMIC.  */
 static inline Elf32_Addr
+elf_machine_dynamic (void) __attribute__ ((const));
+
+static inline Elf32_Addr
 elf_machine_dynamic (void)
 {
   Elf32_Addr dynamic;
 
-#if 0
-  /* Use this method if GOT address not yet set up.  */
-  asm (
-"	b,l	1f,%0\n"
+  asm ("b,l	1f,%0\n"
 "	depi	0,31,2,%0\n"
 "1:	addil	L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 8),%0\n"
 "	ldw	R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 12)(%%r1),%0\n"
-      : "=r" (dynamic) : : "r1");
-#else
-  /* This works because we already have our GOT address available.  */
-  dynamic = (Elf32_Addr) &_DYNAMIC;
-#endif
+       : "=r" (dynamic) : : "r1");
 
   return dynamic;
 }
 
 /* Return the run-time load address of the shared object.  */
 static inline Elf32_Addr
+elf_machine_load_address (void) __attribute__ ((const));
+
+static inline Elf32_Addr
 elf_machine_load_address (void)
 {
-  Elf32_Addr dynamic, dynamic_linkaddress;
+  Elf32_Addr dynamic;
 
   asm (
 "	b,l	1f,%0\n"
 "	depi	0,31,2,%0\n"
 "1:	addil	L'_DYNAMIC - ($PIC_pcrel$0 - 8),%0\n"
-"	ldo	R'_DYNAMIC - ($PIC_pcrel$0 - 12)(%%r1),%1\n"
-"	addil	L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 16),%0\n"
-"	ldw	R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 20)(%%r1),%0\n"
-   : "=r" (dynamic_linkaddress), "=r" (dynamic) : : "r1");
+"	ldo	R'_DYNAMIC - ($PIC_pcrel$0 - 12)(%%r1),%0\n"
+   : "=r" (dynamic) : : "r1");
 
-  return dynamic - dynamic_linkaddress;
+  return dynamic - elf_machine_dynamic ();
 }
 
-/* Fixup a PLT entry to bounce directly to the function at VALUE.  */
+/* Fixup a PLT entry to bounce directly to the function at VALUE.  
+   Optimized non-profile version. */
 static inline Elf32_Addr
 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
 		       const Elf32_Rela *reloc,
 		       Elf32_Addr *reloc_addr, Elf32_Addr value)
 {
-  /* l is the link_map for the caller, t is the link_map for the object
-   * being called */
+  /* map is the link_map for the caller, t is the link_map for the object
+     being called */
   reloc_addr[1] = D_PTR (t, l_info[DT_PLTGOT]);
   reloc_addr[0] = value;
   /* Return the PLT slot rather than the function value so that the
@@ -123,6 +132,20 @@ elf_machine_fixup_plt (struct link_map *map, lookup_t t,
   return (Elf32_Addr) reloc_addr;
 }
 
+/* Fixup a PLT entry to bounce directly to the function at VALUE.  */
+#define ELF_MACHINE_PROFILE_FIXUP_PLT elf_machine_profile_fixup_plt
+static inline Elf32_Addr
+elf_machine_profile_fixup_plt (struct link_map *map, lookup_t t,
+		       const Elf32_Rela *reloc,
+		       Elf32_Addr *reloc_addr, Elf32_Addr value)
+{
+  if(__builtin_expect (t == NULL, 1)) 
+    return (Elf32_Addr) reloc_addr;
+  /* Return the PLT slot rather than the function value so that the
+     trampoline can load the new LTP. */
+  return (Elf32_Addr) elf_machine_fixup_plt(map, t, reloc, reloc_addr, value);
+}
+
 /* Return the final value of a plt relocation.  */
 static inline Elf32_Addr
 elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
@@ -138,110 +161,158 @@ elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
 static inline int
 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
 {
+  Elf32_Addr *got = NULL;
+  Elf32_Addr l_addr, iplt, jmprel, end_jmprel, r_type, r_sym;
+  const Elf32_Rela *reloc;
+  struct fdesc *fptr;
+  static union {
+    unsigned char c[8];
+    Elf32_Addr i[2];
+  } sig = {{0x00,0xc0,0xff,0xee, 0xde,0xad,0xbe,0xef}};
+		
+  /* If we don't have a PLT we can just skip all this... */
+  if (__builtin_expect (l->l_info[DT_JMPREL] == NULL,0))
+    return lazy;
+  
+  /* All paths use these values */ 
+  l_addr = l->l_addr;
+  jmprel = D_PTR(l, l_info[DT_JMPREL]);
+  end_jmprel = jmprel + l->l_info[DT_PLTRELSZ]->d_un.d_val;
+  
   extern void _dl_runtime_resolve (void);
   extern void _dl_runtime_profile (void);
-  Elf32_Addr jmprel = D_PTR(l, l_info[DT_JMPREL]);
-
-  if (lazy && jmprel)
+  
+  /* Linking lazily */
+  if (lazy)
     {
-      Elf32_Addr *got = NULL;
-      Elf32_Addr l_addr;
-      Elf32_Addr end_jmprel;
-      Elf32_Addr iplt;
-
-      /* Relocate all the PLT slots.  */
-      l_addr = l->l_addr;
-      end_jmprel = jmprel + l->l_info[DT_PLTRELSZ]->d_un.d_val;
+      /* FIXME: Search for the got, but backwards through the relocs, technically we should
+         find it on the first try. However, assuming the relocs got out of order the 
+         routine is made a bit more robust by searching them all in case of failure. */
+      for (iplt = (end_jmprel - sizeof(Elf32_Rela)); iplt >= jmprel; iplt -= sizeof (Elf32_Rela))
+        {
+	      
+	  reloc = (const Elf32_Rela *) iplt;
+          r_type = ELF32_R_TYPE (reloc->r_info);
+          r_sym = ELF32_R_SYM (reloc->r_info);
+
+          got = (Elf32_Addr *) (reloc->r_offset + l_addr + PLT_ENTRY_SIZE + SIZEOF_PLT_STUB);
+
+          /* If we aren't an IPLT, and we aren't NONE then it's a bad reloc */
+          if (__builtin_expect (r_type != R_PARISC_IPLT, 0))
+	    {
+	      if (__builtin_expect (r_type != R_PARISC_NONE, 0))
+	        _dl_reloc_bad_type (l, r_type, 1);
+	      continue;
+	    }
+	
+          /* Check for the plt_stub that binutils placed here for us 
+             to use with _dl_runtime_resolve  */
+          if (got[-2] != sig.i[0] || got[-1] != sig.i[1])
+            {
+              got = NULL; /* Not the stub... keep looking */
+            } 
+          else 
+	    {
+              /* Found the GOT! */       	
+              register Elf32_Addr ltp __asm__ ("%r19");
+              /* Identify this shared object. */
+              got[1] = (Elf32_Addr) l;
+
+              /* This function will be called to perform the relocation. */
+              if (__builtin_expect (!profile, 1))
+                {
+                  /* If a static application called us, then _dl_runtime_resolve is not
+		     a function descriptor, but the *real* address of the function... */
+		  if((unsigned long) &_dl_runtime_resolve & 3)
+		    {
+                      got[-2] = (Elf32_Addr) ((struct fdesc *) 
+                                  ((unsigned long) &_dl_runtime_resolve & ~3))->ip;
+		    }
+		  else
+		    {
+		      /* Static executable! */
+                      got[-2] = (Elf32_Addr) &_dl_runtime_resolve;
+		    }
+                }
+              else
+	        {
+	          if (_dl_name_match_p (GLRO(dl_profile), l))
+	            {
+		      /* This is the object we are looking for.  Say that
+		         we really want profiling and the timers are
+		         started.  */
+                      GL(dl_profile_map) = l;
+                    }
+
+		  if((unsigned long) &_dl_runtime_resolve & 3)
+		    {
+                      got[-2] = (Elf32_Addr) ((struct fdesc *)
+                                  ((unsigned long) &_dl_runtime_profile & ~3))->ip;
+		    }
+		  else
+		    {
+		      /* Static executable */
+                      got[-2] = (Elf32_Addr) &_dl_runtime_profile;
+		    }
+                }
+              /* Plunk in the gp of this function descriptor so we 
+	         can make the call to _dl_runtime_xxxxxx */
+              got[-1] = ltp;
+              break;
+              /* Done looking for the GOT, and stub is setup */
+            } /* else we found the GOT */
+        } /* for, walk the relocs backwards */
+
+      if(!got) 
+        return 0; /* No lazy linking for you! */
+  
+      /* Process all the relocs, now that we know the GOT... */    
       for (iplt = jmprel; iplt < end_jmprel; iplt += sizeof (Elf32_Rela))
 	{
-	  const Elf32_Rela *reloc;
-	  Elf32_Word r_type;
-	  Elf32_Word r_sym;
-	  struct hppa_fptr *fptr;
-
 	  reloc = (const Elf32_Rela *) iplt;
 	  r_type = ELF32_R_TYPE (reloc->r_info);
 	  r_sym = ELF32_R_SYM (reloc->r_info);
 
 	  if (__builtin_expect (r_type == R_PARISC_IPLT, 1))
 	    {
-	      fptr = (struct hppa_fptr *) (reloc->r_offset + l_addr);
+	      fptr = (struct fdesc *) (reloc->r_offset + l_addr);
 	      if (r_sym != 0)
 		{
 		  /* Relocate the pointer to the stub.  */
-		  fptr->func += l_addr;
+		  fptr->ip = (Elf32_Addr) got - GOT_FROM_PLT_STUB;
+
 		  /* Instead of the LTP value, we put the reloc offset
 		     here.  The trampoline code will load the proper
 		     LTP and pass the reloc offset to the fixup
 		     function.  */
 		  fptr->gp = iplt - jmprel;
-		  if (!got)
-		    {
-		      static union {
-			unsigned char c[8];
-			Elf32_Addr i[2];
-		      } sig = {{0x00,0xc0,0xff,0xee, 0xde,0xad,0xbe,0xef}};
-
-		      /* Find our .got section.  It's right after the
-			 stub.  */
-		      got = (Elf32_Addr *) (fptr->func + GOT_FROM_PLT_STUB);
-
-		      /* Sanity check to see if the address we are
-                         going to check below is within a reasonable
-                         approximation of the bounds of the PLT (or,
-                         at least, is at an address that won't fault
-                         on read).  Then check for the magic signature
-                         above. */
-		      if (fptr->func < (Elf32_Addr) fptr + sizeof(*fptr))
-			  return 0;
-		      if (fptr->func >
-			  ((Elf32_Addr) fptr
-			   + SIZEOF_PLT_STUB
-			   + ((l->l_info[DT_PLTRELSZ]->d_un.d_val / sizeof (Elf32_Rela))
-			      * 8)))
-			return 0;
-		      if (got[-2] != sig.i[0] || got[-1] != sig.i[1])
-			return 0; /* No lazy linking for you! */
-		    }
-		}
+		} /* r_sym != 0 */
 	      else
 		{
 		  /* Relocate this *ABS* entry.  */
-		  fptr->func = reloc->r_addend + l_addr;
+		  fptr->ip = reloc->r_addend + l_addr;
 		  fptr->gp = D_PTR (l, l_info[DT_PLTGOT]);
 		}
-	    }
-	  else if (__builtin_expect (r_type != R_PARISC_NONE, 0))
-	    _dl_reloc_bad_type (l, r_type, 1);
-	}
-
-      if (got)
-	{
-	  register Elf32_Addr ltp __asm__ ("%r19");
-	  /* Identify this shared object. */
-	  got[1] = (Elf32_Addr) l;
-
-	  /* This function will be called to perform the relocation. */
-	  if (__builtin_expect (!profile, 1))
-	    got[-2] =
-	      (Elf32_Addr) ((struct hppa_fptr *)
-			    ((unsigned long) &_dl_runtime_resolve & ~3))->func;
-	  else
-	    {
-	      if (_dl_name_match_p (GL(dl_profile), l))
-		{
-		  /* This is the object we are looking for.  Say that
-		     we really want profiling and the timers are
-		     started.  */
-		  GL(dl_profile_map) = l;
-		}
-	      got[-2] =
-		(Elf32_Addr) ((struct hppa_fptr *)
-			      ((unsigned long) &_dl_runtime_profile & ~3))->func;
-	    }
-	  got[-1] = ltp;
-	}
-    }
+	    } /* r_type == R_PARISC_IPLT */
+	} /* for all the relocations */ 
+    } /* if lazy */
+  else
+    {
+      for (iplt = jmprel; iplt < end_jmprel; iplt += sizeof (Elf32_Rela))
+        {
+          reloc = (const Elf32_Rela *) iplt;
+          r_type = ELF32_R_TYPE (reloc->r_info);
+          r_sym = ELF32_R_SYM (reloc->r_info);
+
+          if (__builtin_expect ((r_type == R_PARISC_IPLT) && (r_sym == 0), 1))
+            {
+              fptr = (struct fdesc *) (reloc->r_offset + l_addr);
+              /* Relocate this *ABS* entry, set only the gp, the rest is set later
+                 when elf_machine_rela_relative is called (WITHOUT the linkmap)  */
+              fptr->gp = D_PTR (l, l_info[DT_PLTGOT]);
+            } /* r_type == R_PARISC_IPLT */
+        } /* for all the relocations */ 
+    }	  
   return lazy;
 }
 
@@ -251,7 +322,7 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
 
 #define RTLD_START \
 /* Set up dp for any non-PIC lib constructors that may be called.  */	\
-static struct link_map *						\
+static struct link_map * __attribute__((used))				\
 set_dp (struct link_map *map)						\
 {									\
   register Elf32_Addr dp asm ("%r27");					\
@@ -272,22 +343,24 @@ asm (									\
 "	stw	%r25,-40(%sp)\n" /* argc */				\
 "	stw	%r24,-44(%sp)\n" /* argv */				\
 									\
-	/* We need the LTP, and we need it now. */			\
-	/* $PIC_pcrel$0 points 8 bytes past the current instruction,	\
-	   just like a branch reloc.  This sequence gets us the runtime	\
-	   address of _DYNAMIC. */					\
+	/* We need the LTP, and we need it now.				\
+	   $PIC_pcrel$0 points 8 bytes past the current instruction,	\
+	   just like a branch reloc.  This sequence gets us the		\
+	   runtime address of _DYNAMIC. */				\
 "	bl	0f,%r19\n"						\
 "	depi	0,31,2,%r19\n"	/* clear priviledge bits */		\
 "0:	addil	L'_DYNAMIC - ($PIC_pcrel$0 - 8),%r19\n"			\
 "	ldo	R'_DYNAMIC - ($PIC_pcrel$0 - 12)(%r1),%r26\n"		\
 									\
-	/* Also get the link time address from the first entry of the GOT.  */ \
+	/* The link time address is stored in the first entry of the	\
+	   GOT.  */							\
 "	addil	L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 16),%r19\n"	\
 "	ldw	R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 20)(%r1),%r20\n" \
 									\
 "	sub	%r26,%r20,%r20\n"	/* Calculate load offset */	\
 									\
-	/* Rummage through the dynamic entries, looking for DT_PLTGOT.  */ \
+	/* Rummage through the dynamic entries, looking for		\
+	   DT_PLTGOT.  */						\
 "	ldw,ma	8(%r26),%r19\n"						\
 "1:	cmpib,=,n 3,%r19,2f\n"	/* tag == DT_PLTGOT? */			\
 "	cmpib,<>,n 0,%r19,1b\n"						\
@@ -307,8 +380,8 @@ asm (									\
 	   |         32 bytes of magic       |				\
 	   |---------------------------------|				\
 	   | 32 bytes argument/sp save area  |				\
-	   |---------------------------------|  ((current->mm->env_end) + 63 & ~63) \
-	   |         N bytes of slack        |				\
+	   |---------------------------------|  ((current->mm->env_end)	\
+	   |         N bytes of slack        |	 + 63 & ~63)		\
 	   |---------------------------------|				\
 	   |      envvar and arg strings     |				\
 	   |---------------------------------|				\
@@ -354,7 +427,7 @@ asm (									\
 "	ldw	0(%r20),%r20\n"						\
 									\
 "	ldw	-40(%sp),%r25\n"	/* argc */			\
-"	comib,=	0,%r20,.Lnofix\n"	/* FIXME: will be mispredicted */ \
+"	comib,=	0,%r20,.Lnofix\n"	/* FIXME: Mispredicted branch */\
 "	ldw	-44(%sp),%r24\n"	/* argv (delay slot) */		\
 									\
 "	sub	%r25,%r20,%r25\n"					\
@@ -376,7 +449,7 @@ asm (									\
 "	bl	_dl_init_internal,%r2\n"				\
 "	ldo	4(%r23),%r23\n"	/* delay slot */			\
 									\
-	/* Reload argc, argv  to the registers start.S expects them in (feh) */ \
+	/* Reload argc, argv to the registers start.S expects.  */	\
 "	ldw	-40(%sp),%r25\n"					\
 "	ldw	-44(%sp),%r24\n"					\
 									\
@@ -388,8 +461,8 @@ asm (									\
 "	.word	0xdeadbeef\n"						\
 "	.previous\n"							\
 									\
-	/* %r3 contains a function pointer, we need to mask out the lower \
-	 * bits and load the gp and jump address. */			\
+	/* %r3 contains a function pointer, we need to mask out the	\
+	   lower bits and load the gp and jump address. */		\
 "	depi	0,31,2,%r3\n"						\
 "	ldw	0(%r3),%r2\n"						\
 "	addil	LT'__dl_fini_plabel,%r19\n"				\
@@ -404,46 +477,57 @@ asm (									\
 /* This code gets called via the .plt stub, and is used in
    dl-runtime.c to call the `fixup' function and then redirect to the
    address it returns.
+   
+   WARNING: This template is also used by gcc's __cffc, and expects
+   that the "bl" for fixup() exist at a particular offset.
+   Do not change this template without changing gcc, while the prefix
+   "bl" should fix everything so gcc finds the right spot, it will
+   slow down __cffc when it attempts to call fixup to resolve function
+   descriptor references. Please refer to gcc/gcc/config/pa/fptr.c
+   
    Enter with r19 = reloc offset, r20 = got-8, r21 = fixup ltp.  */
-#define TRAMPOLINE_TEMPLATE(tramp_name, fixup_name) \
-  extern void tramp_name (void);		    \
-  asm ( "\
-	/* Trampoline for " #tramp_name " */				    \n\
-	.globl " #tramp_name "						    \n\
-	.type " #tramp_name ",@function					    \n\
-" #tramp_name ":							    \n\
-	/* Save return pointer */					    \n\
-	stw	%r2,-20(%sp)						    \n\
-	/* Save argument registers in the call stack frame. */		    \n\
-	stw	%r26,-36(%sp)						    \n\
-	stw	%r25,-40(%sp)						    \n\
-	stw	%r24,-44(%sp)						    \n\
-	stw	%r23,-48(%sp)						    \n\
-	/* Build a call frame. */					    \n\
-	stwm	%sp,64(%sp)						    \n\
-									    \n\
-	/* Set up args to fixup func.  */				    \n\
-	ldw	8+4(%r20),%r26	/* got[1] == struct link_map *  */	    \n\
-	copy	%r19,%r25	/* reloc offset  */			    \n\
-									    \n\
-	/* Call the real address resolver. */				    \n\
-	bl	" #fixup_name ",%r2					    \n\
-	copy	%r21,%r19	/* delay slot, set fixup func ltp */	    \n\
-									    \n\
-	ldwm	-64(%sp),%sp						    \n\
-	/* Arguments. */						    \n\
-	ldw	-36(%sp),%r26						    \n\
-	ldw	-40(%sp),%r25						    \n\
-	ldw	-44(%sp),%r24						    \n\
-	ldw	-48(%sp),%r23						    \n\
-	/* Return pointer. */						    \n\
-	ldw	-20(%sp),%r2						    \n\
-	/* Call the real function. */					    \n\
-	ldw	0(%r28),%r22						    \n\
-	bv	%r0(%r22)						    \n\
-	ldw	4(%r28),%r19						    \n\
-");
-
+#define TRAMPOLINE_TEMPLATE(tramp_name, fixup_name) 			\
+  extern void tramp_name (void);		    			\
+  asm (									\
+ "	.text\n"							\
+ 	/* FAKE bl to provide gcc's __cffc with fixup's address */	\
+ "	bl	" #fixup_name ",%r2\n" /* Runtime address of fixup */	\
+ "	.globl " #tramp_name "\n"					\
+ "	.type " #tramp_name ",@function\n"				\
+  #tramp_name ":\n"							\
+ 	/* Save return pointer */					\
+ "	stw	%r2,-20(%sp)\n"						\
+ 	/* Save argument registers in the call stack frame. */		\
+ "	stw	%r26,-36(%sp)\n"					\
+ "	stw	%r25,-40(%sp)\n"					\
+ "	stw	%r24,-44(%sp)\n"					\
+ "	stw	%r23,-48(%sp)\n"					\
+ 	/* Build a call frame, and save structure pointer. */		\
+ "	stwm	%r28,64(%sp)\n"						\
+ 									\
+ 	/* Set up args to fixup func.  */				\
+ "	ldw	8+4(%r20),%r26\n" /* (1) got[1] == struct link_map */	\
+ "	copy	%r19,%r25\n"	  /* (2) reloc offset  */		\
+ "	copy    %r2,%r24\n"	  /* (3) profile_fixup needs rp */	\
+ 									\
+ 	/* Call the real address resolver. */				\
+ "	bl	" #fixup_name ",%r2\n"					\
+ "	copy	%r21,%r19\n"	  /* set fixup func ltp (DELAY SLOT)*/	\
+ 									\
+ "	ldw	0(%r28),%r22\n"	  /* load up the returned func ptr */	\
+ "	ldw	4(%r28),%r19\n"						\
+ "	ldwm	-64(%sp),%r28\n"					\
+ 	/* Arguments. */						\
+ "	ldw	-36(%sp),%r26\n"					\
+ "	ldw	-40(%sp),%r25\n"					\
+ "	ldw	-44(%sp),%r24\n"					\
+ "	ldw	-48(%sp),%r23\n"					\
+ 	/* Call the real function. */					\
+ "	bv	%r0(%r22)\n"						\
+ 	/* Return pointer. */						\
+ "	ldw	-20(%sp),%r2\n"						\
+        );
+  
 #ifndef PROF
 #define ELF_MACHINE_RUNTIME_TRAMPOLINE			\
   TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup);	\
@@ -454,7 +538,6 @@ asm (									\
   strong_alias (_dl_runtime_resolve, _dl_runtime_profile);
 #endif
 
-
 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
    PLT entries should not be allowed to define the value.
    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
@@ -464,22 +547,35 @@ asm (									\
     * ELF_RTYPE_CLASS_PLT)					\
    | (((type) == R_PARISC_COPY) * ELF_RTYPE_CLASS_COPY))
 
-/* Used by ld.so for ... something ... */
+/* Used by the runtime in fixup to figure out if reloc is *really* PLT */
 #define ELF_MACHINE_JMP_SLOT R_PARISC_IPLT
+#define ELF_MACHINE_SIZEOF_JMP_SLOT PLT_ENTRY_SIZE
 
 /* We only use RELA. */
 #define ELF_MACHINE_NO_REL 1
 
 /* Return the address of the entry point. */
 #define ELF_MACHINE_START_ADDRESS(map, start) \
-  DL_FUNCTION_ADDRESS (map, start)
+  DL_STATIC_FUNCTION_ADDRESS (map, start)
+
+/* We define an initialization functions.  This is called very early in
+ *    _dl_sysdep_start.  */
+#define DL_PLATFORM_INIT dl_platform_init ()
 
+static inline void __attribute__ ((unused))
+dl_platform_init (void)
+{
+	if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
+	/* Avoid an empty string which would disturb us.  */
+		GLRO(dl_platform) = NULL;
+}
+	
 #endif /* !dl_machine_h */
 
 /* These are only actually used where RESOLVE_MAP is defined, anyway. */
 #ifdef RESOLVE_MAP
 
-static inline void
+auto void __attribute__((always_inline))
 elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
 		  const Elf32_Sym *sym, const struct r_found_version *version,
 		  void *const reloc_addr_arg)
@@ -490,14 +586,14 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
   struct link_map *sym_map;
   Elf32_Addr value;
 
-#if !defined RTLD_BOOTSTRAP && !defined SHARED
+# if !defined RTLD_BOOTSTRAP && !defined SHARED
   /* This is defined in rtld.c, but nowhere in the static libc.a; make the
      reference weak so static programs can still link.  This declaration
      cannot be done when compiling rtld.c (i.e.  #ifdef RTLD_BOOTSTRAP)
      because rtld.c contains the common defn for _dl_rtld_map, which is
      incompatible with a weak decl in the same file.  */
   weak_extern (GL(dl_rtld_map));
-#endif
+# endif
 
   /* RESOLVE_MAP will return a null value for undefined syms, and
      non-null for all other syms.  In particular, relocs with no
@@ -505,13 +601,13 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
      resolved to MAP.  (The first entry in a symbol table is all
      zeros, and an all zero Elf32_Sym has a binding of STB_LOCAL.)
      See RESOLVE_MAP definition in elf/dl-reloc.c  */
-#ifdef RTLD_BOOTSTRAP
+# ifdef RTLD_BOOTSTRAP
   /* RESOLVE_MAP in rtld.c doesn't have the local sym test.  */
   sym_map = (ELF32_ST_BIND (sym->st_info) != STB_LOCAL
 	     ? RESOLVE_MAP (&sym, version, r_type) : map);
-#else
+# else
   sym_map = RESOLVE_MAP (&sym, version, r_type);
-#endif
+# endif
   if (sym_map)
     {
       value = sym ? sym_map->l_addr + sym->st_value : 0;
@@ -523,15 +619,6 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
   switch (r_type)
     {
     case R_PARISC_DIR32:
-#ifndef RTLD_BOOTSTRAP
-      /* All hell breaks loose if we try to relocate these twice,
-         because any initialized variables in ld.so that refer to
-         other ones will have their values reset.  In particular,
-         __fptr_next will be reset, sometimes causing endless loops in
-         __hppa_make_fptr().  So don't do that. */
-      if (map == &GL(dl_rtld_map))
-	return;
-#endif
       /* .eh_frame can have unaligned relocs.  */
       if ((unsigned long) reloc_addr_arg & 3)
 	{
@@ -552,51 +639,26 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
       if (sym == NULL
 	  || sym_map == NULL
 	  || ELF32_ST_BIND (sym->st_info) == STB_LOCAL)
-	break;
-
-      /* Okay, we need to make ourselves a PLABEL then.  See the IA64
-         code for an explanation of how this works.  */
-#ifndef RTLD_BOOTSTRAP
-      value = __hppa_make_fptr (sym_map, value, &__fptr_root, NULL);
-#else
-      {
-	struct hppa_fptr *p_boot_ldso_fptr;
-	struct hppa_fptr **p_fptr_root;
-	int *p_fptr_count;
-	unsigned long dot;
-
-	/* Go from the top of __boot_ldso_fptr.  As on IA64, we
-	   probably haven't relocated the necessary values by this
-	   point so we have to find them ourselves. */
-
-	asm ("bl	0f,%0						    \n\
-	      depi	0,31,2,%0					    \n\
-0:	      addil	L'__boot_ldso_fptr - ($PIC_pcrel$0 - 8),%0	    \n\
-	      ldo	R'__boot_ldso_fptr - ($PIC_pcrel$0 - 12)(%%r1),%1   \n\
-	      addil	L'__fptr_root - ($PIC_pcrel$0 - 16),%0		    \n\
-	      ldo	R'__fptr_root - ($PIC_pcrel$0 - 20)(%%r1),%2	    \n\
-	      addil	L'__fptr_count - ($PIC_pcrel$0 - 24),%0		    \n\
-	      ldo	R'__fptr_count - ($PIC_pcrel$0 - 28)(%%r1),%3"
-	     :
-	     "=r" (dot),
-	     "=r" (p_boot_ldso_fptr),
-	     "=r" (p_fptr_root),
-	     "=r" (p_fptr_count));
-
-	value = __hppa_make_fptr (sym_map, value, p_fptr_root,
-				  &p_boot_ldso_fptr[--*p_fptr_count]);
-      }
-#endif
+        {
+	  break;
+        }
+      /* Set bit 30 to indicate to $$dyncall that this is a PLABEL.
+         We have to do this outside of the generic function descriptor
+	 code, since it doesn't know about our requirement for setting
+	 protection bits */
+      value = (Elf32_Addr)((unsigned int)_dl_make_fptr (sym_map, sym, value) | 2);
       break;
 
     case R_PARISC_IPLT:
       if (__builtin_expect (sym_map != NULL, 1))
-	elf_machine_fixup_plt (NULL, sym_map, reloc, reloc_addr, value);
-      else
-	{
+        {
+	  elf_machine_fixup_plt (NULL, sym_map, reloc, reloc_addr, value);
+        } 
+      else 
+        {
 	  /* If we get here, it's a (weak) undefined sym.  */
 	  elf_machine_fixup_plt (NULL, map, reloc, reloc_addr, value);
-	}
+        }
       return;
 
     case R_PARISC_COPY:
@@ -606,20 +668,20 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
 	break;
       if (__builtin_expect (sym->st_size > refsym->st_size, 0)
 	  || (__builtin_expect (sym->st_size < refsym->st_size, 0)
-	      && __builtin_expect (GL(dl_verbose), 0)))
+	      && __builtin_expect (GLRO(dl_verbose), 0)))
 	{
 	  const char *strtab;
 
 	  strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
-	  _dl_error_printf ("\
-%s: Symbol `%s' has different size in shared object, consider re-linking\n",
+	  _dl_error_printf ("%s: Symbol `%s' has different size in shared object, "
+			    "consider re-linking\n",
 			    rtld_progname ?: "<program name unknown>",
 			    strtab + refsym->st_name);
 	}
       memcpy (reloc_addr_arg, (void *) value,
 	      MIN (sym->st_size, refsym->st_size));
       return;
-
+      
     case R_PARISC_NONE:	/* Alright, Wilbur. */
       return;
 
@@ -630,25 +692,27 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
   *reloc_addr = value;
 }
 
-#define DO_ELF_MACHINE_REL_RELATIVE(map, l_addr, relative) \
-  elf_machine_rel_relative (map, l_addr, relative,			      \
-			    (void *) (l_addr + relative->r_offset))
-
 /* hppa doesn't have an R_PARISC_RELATIVE reloc, but uses relocs with
    ELF32_R_SYM (info) == 0 for a similar purpose.  */
-static inline void
-elf_machine_rela_relative (struct link_map *map, Elf32_Addr l_addr,
+auto void __attribute__((always_inline))
+elf_machine_rela_relative (Elf32_Addr l_addr,
 			   const Elf32_Rela *reloc,
 			   void *const reloc_addr_arg)
 {
-  Elf32_Addr *const reloc_addr = reloc_addr_arg;
   unsigned long const r_type = ELF32_R_TYPE (reloc->r_info);
+  Elf32_Addr *const reloc_addr = reloc_addr_arg;
+  static char msgbuf[] = { "Unknown" }; 
+  struct link_map map;
   Elf32_Addr value;
 
   value = l_addr + reloc->r_addend;
 
-  if (ELF32_R_SYM (reloc->r_info) != 0)
-    asm volatile ("iitlbp	%r0,(%r0)");  /* Crash. */
+  if (ELF32_R_SYM (reloc->r_info) != 0){ 
+    _dl_error_printf ("%s: In elf_machine_rela_relative "
+		      "ELF32_R_SYM (reloc->r_info) != 0. Aborting.",
+		      rtld_progname ?: "<program name unknown>");
+    ABORT_INSTRUCTION;  /* Crash. */
+  }
 
   switch (r_type)
     {
@@ -668,21 +732,22 @@ elf_machine_rela_relative (struct link_map *map, Elf32_Addr l_addr,
     case R_PARISC_PLABEL32:
       break;
 
-    case R_PARISC_IPLT:
-      elf_machine_fixup_plt (NULL, map, reloc, reloc_addr, value);
-      return;
+    case R_PARISC_IPLT: /* elf_machine_runtime_setup already set gp */
+      break;
 
     case R_PARISC_NONE:
       return;
 
-    default:
-      _dl_reloc_bad_type (map, r_type, 0);
+    default: /* Bad reloc, map unknown (really it's the current map) */
+      map.l_name = msgbuf;
+      _dl_reloc_bad_type (&map, r_type, 0);
+      return;
     }
 
   *reloc_addr = value;
 }
 
-static inline void
+auto void __attribute__((always_inline))
 elf_machine_lazy_rel (struct link_map *map,
 		      Elf32_Addr l_addr, const Elf32_Rela *reloc)
 {
diff --git a/sysdeps/hppa/fpu/feupdateenv.c b/sysdeps/hppa/fpu/feupdateenv.c
index 8980dfd69c..7d50282e05 100644
--- a/sysdeps/hppa/fpu/feupdateenv.c
+++ b/sysdeps/hppa/fpu/feupdateenv.c
@@ -27,11 +27,10 @@ feupdateenv (const fenv_t *envp)
 
   /* Get the current exception status. */
   __asm__ ("fstd %%fr0,0(%1)" : "=m" (*sw) : "r" (sw));
-  sw[0] &= FE_ALL_EXCEPT;
-  envp->__status_word = envp->__status_word | sw[0];
-  
   /* Install new environment.  */
   fesetenv (envp);
+  /* Raise the saved exceptions */
+  feraiseexcept(sw[0] & FE_ALL_EXCEPT);
 
   /* Success.  */
   return 0;