summary refs log tree commit diff
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>1995-05-08 09:11:25 +0000
committerRoland McGrath <roland@gnu.org>1995-05-08 09:11:25 +0000
commit421f82e5cc8f81ab003247d771bcecbad799be85 (patch)
tree6d2e888aa32ba05854b1bd793b903cd0eb755bc4
parent0fb807c1dbb08de4408c440c2db490b52bd16f57 (diff)
downloadglibc-421f82e5cc8f81ab003247d771bcecbad799be85.tar.gz
glibc-421f82e5cc8f81ab003247d771bcecbad799be85.tar.xz
glibc-421f82e5cc8f81ab003247d771bcecbad799be85.zip
Sat May 6 11:06:47 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
	* Makeconfig (+gccwarn): Add -Winline.

	* hurd/hurdsig.c (_hurd_internal_post_signal): If SS->context is
 	set, avoid abort_rpcs, and use reply and intr ports saved in
 	SS->context.
	* sysdeps/mach/hurd/i386/trampoline.c: Don't set SS->intr_port
 	from SS->context.  Don't clear SS->context.
	* sysdeps/mach/hurd/i386/sigreturn.c: Don't set SS->intr_port when
 	setting SS->context.  If msg_sig_post returns, re-lock and clear
 	SS->context.

Fri May  5 10:37:09 1995  Roland McGrath  <roland@churchy.gnu.ai.mit.edu>

	* mach/Makefile (errsystems.c): Comment out generation rule.

	* sysdeps/mach/_strerror.c: Consider a system unknown if its
 	bad_sub member is null.

	* mach/mig-alloc.c: Add weak alias to non-__ name.
-rw-r--r--ChangeLog22
-rw-r--r--Makeconfig2
-rw-r--r--elf/dl-error.c13
-rw-r--r--elf/dl-load.c38
-rw-r--r--elf/dl-lookup.c5
-rw-r--r--elf/dl-object.c3
-rw-r--r--elf/dl-reloc.c9
-rw-r--r--elf/dlclose.c2
-rw-r--r--elf/dlerror.c57
-rw-r--r--elf/dlsym.c2
-rw-r--r--elf/do-rel.h68
-rw-r--r--elf/dynamic-link.h105
-rw-r--r--elf/link.h26
-rw-r--r--elf/rtld.c268
-rw-r--r--hurd/hurdsig.c113
-rw-r--r--mach/Makefile4
-rw-r--r--sysdeps/i386/dl-machine.h37
-rw-r--r--sysdeps/i386/dl-runtime.c9
-rw-r--r--sysdeps/mach/_strerror.c6
-rw-r--r--sysdeps/mach/hurd/getdtsz.c7
-rw-r--r--sysdeps/mach/hurd/i386/sigreturn.c10
-rw-r--r--sysdeps/mach/hurd/i386/trampoline.c18
22 files changed, 470 insertions, 354 deletions
diff --git a/ChangeLog b/ChangeLog
index 2bf9c5aa2d..609e65c4b6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+Sat May  6 11:06:47 1995  Roland McGrath  <roland@churchy.gnu.ai.mit.edu>
+
+	* Makeconfig (+gccwarn): Add -Winline.
+
+	* hurd/hurdsig.c (_hurd_internal_post_signal): If SS->context is
+ 	set, avoid abort_rpcs, and use reply and intr ports saved in
+ 	SS->context.
+	* sysdeps/mach/hurd/i386/trampoline.c: Don't set SS->intr_port
+ 	from SS->context.  Don't clear SS->context.
+	* sysdeps/mach/hurd/i386/sigreturn.c: Don't set SS->intr_port when
+ 	setting SS->context.  If msg_sig_post returns, re-lock and clear
+ 	SS->context.
+
+Fri May  5 10:37:09 1995  Roland McGrath  <roland@churchy.gnu.ai.mit.edu>
+
+	* mach/Makefile (errsystems.c): Comment out generation rule.
+
+	* sysdeps/mach/_strerror.c: Consider a system unknown if its
+ 	bad_sub member is null.
+
+	* mach/mig-alloc.c: Add weak alias to non-__ name.
+
 Wed May  3 11:56:35 1995  Roland McGrath  <roland@churchy.gnu.ai.mit.edu>
 
 	* sysdeps/mach/hurd/dup2.c: Fixed broken test in last change.
diff --git a/Makeconfig b/Makeconfig
index 823b7f44f1..cb3c065ddc 100644
--- a/Makeconfig
+++ b/Makeconfig
@@ -272,7 +272,7 @@ RANLIB = ranlib
 endif
 
 # Extra flags to pass to GCC.
-+gccwarn := -Wall -Wwrite-strings -Wno-parentheses
++gccwarn := -Wall -Wwrite-strings -Wno-parentheses -Winline
 
 # This is the program that generates makefile
 # dependencies from C source files.
diff --git a/elf/dl-error.c b/elf/dl-error.c
index b9ee3516b5..5f8e4e4088 100644
--- a/elf/dl-error.c
+++ b/elf/dl-error.c
@@ -22,23 +22,28 @@ Cambridge, MA 02139, USA.  */
 #include <setjmp.h>
 
 static jmp_buf catch_env;
-static const char *signalled_errstring;
+static const char *signalled_errstring, *signalled_objname;
 
 void
-_dl_signal_error (int errcode, const char *errstring)
+_dl_signal_error (int errcode,
+		  const char *objname,
+		  const char *errstring)
 {
   signalled_errstring = errstring ?: "DYNAMIC LINKER BUG!!!";
   longjmp (catch_env, errcode ?: -1);
 }
 
 int
-_dl_catch_error (const char **errstring, void (*operate) (void))
+_dl_catch_error (const char **errstring,
+		 const char **objname,
+		 void (*operate) (void))
 {
   int errcode;
 
-  signalled_errstring = NULL;
+  signalled_errstring = signalled_objname = NULL;
   errcode = setjmp (catch_env);
   (*operate) ();
   *errstring = signalled_errstring;
+  *objname = signalled_objname;
   return *errstring ? errcode : 0;
 }
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 0de7404a80..f8b37ba346 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -107,10 +107,20 @@ _dl_map_object (struct link_map *loader, const char *name,
 		Elf32_Addr *entry_point)
 {
   int fd;
+  struct link_map *l = NULL;
   char *realname;
   const size_t pagesize = getpagesize ();
   void *file_mapping = NULL;
   size_t mapping_size = 0;
+
+  void lose (int code, const char *msg)
+    {
+      (void) close (fd);
+      if (file_mapping)
+	munmap (file_mapping, mapping_size);
+      _dl_signal_error (code, l ? l->l_name : name, msg);
+    }
+
   /* Make sure LOCATION is mapped in.  */
   void *map (off_t location, size_t size)
     {
@@ -124,14 +134,13 @@ _dl_map_object (struct link_map *loader, const char *name,
 	  result = mmap (file_mapping, mapping_size, PROT_READ,
 			 MAP_COPY|MAP_FILE, fd, 0);
 	  if (result == (void *) -1)
-	    return NULL;
+	    lose (errno, "cannot map file data");
 	  file_mapping = result;
 	}
       return file_mapping + location;
     }
 
   const Elf32_Ehdr *header;
-  struct link_map *l;
 
   /* Look for this name among those already loaded.  */
   for (l = _dl_loaded; l; l = l->l_next)
@@ -170,7 +179,7 @@ _dl_map_object (struct link_map *loader, const char *name,
     }
 
   if (fd == -1)
-    return NULL;
+    lose (errno, "cannot open shared object file");
 
   /* Look again to see if the real name matched another already loaded.  */
   for (l = _dl_loaded; l; l = l->l_next)
@@ -186,17 +195,9 @@ _dl_map_object (struct link_map *loader, const char *name,
 
   /* Map in the first page to read the header.  */
   header = map (0, sizeof *header);
-  if (! header)
-    {
-    lose:
-      (void) close (fd);
-      if (file_mapping)
-	munmap (file_mapping, mapping_size);
-      return NULL;
-    }
 
 #undef LOSE
-#define LOSE(s) _dl_signal_error (0, s)
+#define LOSE(s) lose (0, (s))
   /* Check the header for basic validity.  */
   if (*(Elf32_Word *) &header->e_ident != ((ELFMAG0 << (EI_MAG0 * 8)) |
 					   (ELFMAG1 << (EI_MAG1 * 8)) |
@@ -224,7 +225,7 @@ _dl_map_object (struct link_map *loader, const char *name,
     {
       _dl_zerofd = _dl_sysdep_open_zero_fill ();
       if (_dl_zerofd == -1)
-	_dl_signal_error (errno, "cannot open zero fill device");
+	_dl_signal_error (errno, NULL, "cannot open zero fill device");
     }
 
   {
@@ -235,8 +236,6 @@ _dl_map_object (struct link_map *loader, const char *name,
     int anywhere;
 
     ph = map (header->e_phoff, header->e_phnum * sizeof (Elf32_Phdr));
-    if (! ph)
-      goto lose;
     memcpy (phdr, ph, sizeof phdr);
     l->l_phnum = header->e_phnum;
 
@@ -288,7 +287,8 @@ _dl_map_object (struct link_map *loader, const char *name,
 	      {
 		/* XXX this loses if the first segment mmap call puts
 		   it someplace where the later segments cannot fit.  */
-		mapat = mmap ((caddr_t) l->l_addr + mapstart, mapend - mapstart,
+		mapat = mmap ((caddr_t) (l->l_addr + mapstart),
+			      mapend - mapstart,
 			      prot, MAP_COPY|MAP_FILE|MAP_INHERIT |
 			      /* Let the system choose any convenient
 				 location if this is the first segment.
@@ -312,8 +312,7 @@ _dl_map_object (struct link_map *loader, const char *name,
 		l->l_addr = 0;
 	      }
 	    if (mapat == (caddr_t) -1)
-	      _dl_signal_error (errno,
-				"failed to map region from shared object");
+	      lose (errno, "failed to map segment from shared object");
 
 	    if (ph->p_memsz > ph->p_filesz)
 	      {
@@ -341,8 +340,7 @@ _dl_map_object (struct link_map *loader, const char *name,
 						 & ~(pagesize - 1)),
 				      pagesize,
 				      prot|PROT_WRITE) < 0)
-			  _dl_signal_error (errno,
-					    "cannot change protections");
+			  lose (errno, "cannot change memory protections");
 		      }
 		    memset (zero, 0, zeroend - zero);
 		    if ((prot & PROT_WRITE) == 0)
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index b4600b1970..a7afcc79bb 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -27,7 +27,8 @@ Cambridge, MA 02139, USA.  */
 
 Elf32_Addr
 _dl_lookup_symbol (const char *undef_name, const Elf32_Sym **ref,
-		   struct link_map *symbol_scope)
+		   struct link_map *symbol_scope,
+		   const char *reference_name)
 {
   unsigned long int hash = elf_hash (undef_name);
   struct link_map *map;
@@ -106,7 +107,7 @@ _dl_lookup_symbol (const char *undef_name, const Elf32_Sym **ref,
       char buf[sizeof msg + strlen (undef_name)];
       memcpy (buf, msg, sizeof msg - 1);
       memcpy (&buf[sizeof msg - 1], undef_name, sizeof buf - sizeof msg);
-      _dl_signal_error (0, msg);
+      _dl_signal_error (0, reference_name, msg);
     }
 
   *ref = weak_value.s;
diff --git a/elf/dl-object.c b/elf/dl-object.c
index e7b1ce3f45..ca4e785be3 100644
--- a/elf/dl-object.c
+++ b/elf/dl-object.c
@@ -37,7 +37,8 @@ _dl_new_object (char *realname, const char *libname, int type)
 {
   struct link_map *new = malloc (sizeof *new);
   if (! new)
-    _dl_signal_error (ENOMEM, "can't open new object");
+    _dl_signal_error (ENOMEM, libname,
+		      "cannot allocate shared object descriptor");
 
   memset (new, 0, sizeof *new);
   new->l_name = realname;
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index 8efb3f04a6..94ffb71759 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -48,7 +48,7 @@ _dl_relocate_object (struct link_map *l, int lazy)
 			       & ~(pagesize - 1)));
 	    if (mprotect (mapstart, mapend - mapstart,
 			  PROT_READ|PROT_WRITE) < 0)
-	      _dl_signal_error (errno,
+	      _dl_signal_error (errno, l->l_name,
 				"cannot make segment writable for relocation");
 	  }
     }
@@ -62,7 +62,8 @@ _dl_relocate_object (struct link_map *l, int lazy)
 
     Elf32_Addr resolve (const Elf32_Sym **ref)
       {
-	return _dl_lookup_symbol (strtab + (*ref)->st_name, ref, scope);
+	return _dl_lookup_symbol (strtab + (*ref)->st_name, ref, scope,
+				  l->l_name);
       }
 
     real_next = l->l_next;
@@ -75,7 +76,7 @@ _dl_relocate_object (struct link_map *l, int lazy)
     else
       scope = _dl_loaded;
 
-    elf_dynamic_relocate (l->l_info, l->l_addr, lazy, resolve);
+    ELF_DYNAMIC_RELOCATE (l, lazy, resolve);
 
     /* Restore list frobnication done above for DT_SYMBOLIC.  */
     l->l_next = real_next;
@@ -107,7 +108,7 @@ _dl_relocate_object (struct link_map *l, int lazy)
 	    if (ph->p_flags & PF_X)
 	      prot |= PROT_EXEC;
 	    if (mprotect (mapstart, mapend - mapstart, prot) < 0)
-	      _dl_signal_error (errno,
+	      _dl_signal_error (errno, l->l_name,
 				"can't restore segment prot after reloc");
 	  }
     }
diff --git a/elf/dlclose.c b/elf/dlclose.c
index 4aa4085f66..06b2d1bdcd 100644
--- a/elf/dlclose.c
+++ b/elf/dlclose.c
@@ -24,7 +24,7 @@ Cambridge, MA 02139, USA.  */
 #include <sys/mman.h>
 
 
-#define LOSE(s) _dl_signal_error (0, s)
+#define LOSE(s) _dl_signal_error (0, map->l_name, s)
 
 int
 dlclose (void *handle)
diff --git a/elf/dlerror.c b/elf/dlerror.c
index 0eed60a45d..4ec5037de4 100644
--- a/elf/dlerror.c
+++ b/elf/dlerror.c
@@ -23,42 +23,49 @@ Cambridge, MA 02139, USA.  */
 #include <string.h>
 #include <stdlib.h>
 
-static int _dl_last_errcode;
-static const char *_dl_last_errstring;
+static int last_errcode;
+static const char *last_errstring;
+static const char *last_object_name;
 
 char *
 dlerror (void)
 {
- char *ret;
+  static char *buf;
+  char *ret;
 
-  if (! _dl_last_errstring)
-    return NULL;
-
-  if (_dl_last_errcode)
+  if (buf)
     {
-      static char *buf;
-      if (buf)
-	{
-	  free (buf);
-	  buf = NULL;
-	}
-      if (asprintf (&buf, "%s: %s",
-		    _dl_last_errstring, strerror (_dl_last_errcode)) == -1)
-	return NULL;
-      else
-	ret = buf;
+      free (buf);
+      buf = NULL;
     }
- else
-   ret = (char *) _dl_last_errstring;
 
- /* Reset the error indicator.  */
- _dl_last_errstring = NULL;
- return ret;
+  if (! last_errstring)
+    return NULL;
+
+  if (last_errcode == 0 && ! last_object_name)
+    ret = (char *) last_errstring;
+  else if (last_errcode == 0)
+    ret = (asprintf (&buf, "%s: %s", last_object_name, last_errstring) == -1
+	   ? NULL : buf);
+  else if (! last_object_name)
+    ret = (asprintf (&buf, "%s: %s",
+		     last_errstring, strerror (last_errcode)) == -1
+	   ? NULL : buf);
+  else
+    ret = (asprintf (&buf, "%s: %s: %s",
+		     last_object_name, last_errstring,
+		     strerror (last_errcode)) == -1
+	   ? NULL : buf);
+
+  /* Reset the error indicator.  */
+  last_errstring = NULL;
+  return ret;
 }
 
 int
 _dlerror_run (void (*operate) (void))
 {
-  _dl_last_errcode = _dl_catch_error (&_dl_last_errstring, operate);
-  return _dl_last_errstring != NULL;
+  last_errcode = _dl_catch_error (&last_errstring, &last_object_name,
+				  operate);
+  return last_errstring != NULL;
 }
diff --git a/elf/dlsym.c b/elf/dlsym.c
index 6d8781053b..3e10812da8 100644
--- a/elf/dlsym.c
+++ b/elf/dlsym.c
@@ -33,7 +33,7 @@ dlsym (void *handle, const char *name)
   void doit (void)
     {
       const Elf32_Sym *ref = NULL;
-      value = _dl_lookup_symbol (name, &ref, map);
+      value = _dl_lookup_symbol (name, map->l_name, &ref, map);
     }
 
   /* Confine the symbol scope to just this map.  */
diff --git a/elf/do-rel.h b/elf/do-rel.h
new file mode 100644
index 0000000000..04643e8fac
--- /dev/null
+++ b/elf/do-rel.h
@@ -0,0 +1,68 @@
+/* Do relocations for ELF dynamic linking.
+Copyright (C) 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+/* This file may be included twice, to define both
+   `elf_dynamic_do_rel' and `elf_dynamic_do_rela'.  */
+
+#ifdef DO_RELA
+#define elf_dynamic_do_rel	elf_dynamic_do_rela
+#define	Elf32_Rel		Elf32_Rela
+#define elf_machine_rel		elf_machine_rela
+#endif
+
+
+/* Perform the relocations in MAP on the running program image as specified
+   by RELTAG, SZTAG.  *RESOLVE is called to resolve symbol values; it
+   modifies its argument pointer to point to the defining symbol, and
+   returns the base load address of the defining object.  */
+
+static inline void
+elf_dynamic_do_rel (struct link_map *map,
+		    int reltag, int sztag, 
+		    Elf32_Addr (*resolve) (const Elf32_Sym **))
+{
+  const Elf32_Sym *const symtab
+    = (const Elf32_Sym *) map->l_info[DT_SYMTAB]->d_un.d_ptr;
+  const Elf32_Rel *r = (const Elf32_Rel *) map->l_info[reltag]->d_un.d_ptr;
+  const Elf32_Rel *end = &r[map->l_info[sztag]->d_un.d_val / sizeof *r];
+
+  for (; r < end; ++r)
+    {
+      const Elf32_Sym *definer = &symtab[ELF32_R_SYM (r->r_info)];
+      Elf32_Addr loadbase;
+
+      if (ELF32_R_SYM (r->r_info) == STN_UNDEF)
+	loadbase = 0;		/* This value will not be consulted.  */
+      else
+	{
+	  if (resolve)
+	    loadbase = (*resolve) (&definer);
+	  else
+	    {
+	      assert (definer->st_shndx != SHN_UNDEF);
+	      loadbase = map->l_addr;
+	    }
+	}
+      elf_machine_rel (map, r, loadbase, definer);
+    }
+}
+
+#undef elf_dynamic_do_rel
+#undef Elf32_Rel
+#undef elf_machine_rel
diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h
index 1c3af29d6a..fc5c585356 100644
--- a/elf/dynamic-link.h
+++ b/elf/dynamic-link.h
@@ -18,23 +18,10 @@ not, write to the Free Software Foundation, Inc., 675 Mass Ave,
 Cambridge, MA 02139, USA.  */
 
 #include <elf.h>
-
-/* This machine-dependent file defines these inline functions.  */
-
-static void elf_machine_rel (Elf32_Addr loadaddr, Elf32_Dyn *info[DT_NUM],
-			     const Elf32_Rel *reloc, 
-			     Elf32_Addr sym_loadaddr, const Elf32_Sym *sym);
-static void elf_machine_rela (Elf32_Addr loadaddr, Elf32_Dyn *info[DT_NUM],
-			      const Elf32_Rela *reloc, 
-			      Elf32_Addr sym_loadaddr, const Elf32_Sym *sym);
-static Elf32_Addr *elf_machine_got (void);
-static Elf32_Addr elf_machine_load_address (void);
-
 #include <dl-machine.h>
-
-
 #include <assert.h>
 
+
 /* Read the dynamic section at DYN and fill in INFO with indices DT_*.  */
 
 static inline void
@@ -60,60 +47,36 @@ elf_get_dynamic_info (Elf32_Dyn *dyn, Elf32_Dyn *info[DT_NUM])
 	    info[DT_PLTREL]->d_un.d_val == DT_RELA);
 }
 
-/* Perform the relocations specified by DYNAMIC on the running program
-   image.  If LAZY is nonzero, don't relocate PLT entries.  *RESOLVE is
-   called to resolve symbol values; it modifies its argument pointer to
-   point to the defining symbol, and returns the base load address of the
-   defining object.  */
-
-static inline void
-elf_dynamic_relocate (Elf32_Dyn *dynamic[DT_NUM], Elf32_Addr loadaddr,
-		      int lazy, Elf32_Addr (*resolve) (const Elf32_Sym **))
-{
-  const Elf32_Sym *const symtab
-    = (const Elf32_Sym *) dynamic[DT_SYMTAB]->d_un.d_ptr;
-
-  inline Elf32_Addr symvalue (Elf32_Word info, const Elf32_Sym **definer)
-    {
-      if (ELF32_R_SYM (info) == STN_UNDEF)
-	return 0;		/* This value will not be consulted.  */
-      *definer = &symtab[ELF32_R_SYM (info)];
-      return (*resolve) (definer);
-    }
-
-  /* Perform Elf32_Rel relocations in the section found by RELTAG, SZTAG.  */
-  inline void do_rel (Elf32_Word reltag, Elf32_Word sztag)
-    {
-      const Elf32_Rel *r = (const Elf32_Rel *) dynamic[reltag]->d_un.d_ptr;
-      const Elf32_Rel *end = &r[dynamic[sztag]->d_un.d_val / sizeof *r];
-      while (r < end)
-	{
-	  const Elf32_Sym *definer;
-	  Elf32_Addr loadbase = symvalue (r->r_info, &definer);
-	  elf_machine_rel (loadaddr, dynamic, r, loadbase, definer);
-	  ++r;
-	}
-    }
-  /* Perform Elf32_Rela relocations in the section found by RELTAG, SZTAG.  */
-  inline void do_rela (Elf32_Word reltag, Elf32_Word sztag)
-    {
-      const Elf32_Rela *r = (const Elf32_Rela *) dynamic[reltag]->d_un.d_ptr;
-      const Elf32_Rela *end = &r[dynamic[sztag]->d_un.d_val / sizeof *r];
-      while (r < end)
-	{
-	  const Elf32_Sym *definer;
-	  Elf32_Addr loadbase = symvalue (r->r_info, &definer);
-	  elf_machine_rela (loadaddr, dynamic, r, loadbase, definer);
-	  ++r;
-	}
-    }
-
-  if (dynamic[DT_RELA])
-    do_rela (DT_RELA, DT_RELASZ);
-  if (dynamic[DT_REL])
-    do_rel (DT_REL, DT_RELSZ);
-  if (dynamic[DT_JMPREL] && ! lazy)
-    /* Relocate the PLT right now.  */
-    (dynamic[DT_PLTREL]->d_un.d_val == DT_REL ? do_rel : do_rela)
-      (DT_JMPREL, DT_PLTRELSZ);
-}
+/* Get the definitions of `elf_dynamic_do_rel' and `elf_dynamic_do_rela'.
+   These functions are almost identical, so we use cpp magic to avoid
+   duplicating their code.  It cannot be done in a more general function
+   because we must be able to completely inline.  */
+
+#if ! ELF_MACHINE_NO_REL
+#include "do-rel.h"
+#define ELF_DYNAMIC_DO_REL(map, lazy, resolve)				      \
+  if ((map)->l_info[DT_REL])						      \
+    elf_dynamic_do_rel ((map), DT_REL, DT_RELSZ, (resolve));		      \
+  if (!(lazy) && (map)->l_info[DT_PLTREL]->d_un.d_val == DT_REL)	      \
+    elf_dynamic_do_rel ((map), DT_JMPREL, DT_PLTRELSZ, (resolve));
+#else
+#define ELF_DYNAMIC_DO_RELA(map, lazy, resolve) /* Nothing to do.  */
+#endif
+
+#if ! ELF_MACHINE_NO_RELA
+#define DO_RELA
+#include "do-rel.h"
+#define ELF_DYNAMIC_DO_RELA(map, lazy, resolve)				      \
+  if ((map)->l_info[DT_RELA])						      \
+    elf_dynamic_do_rela ((map), DT_RELA, DT_RELASZ, (resolve));		      \
+  if (!(lazy) && (map)->l_info[DT_PLTREL]->d_un.d_val == DT_RELA)	      \
+    elf_dynamic_do_rela ((map), DT_JMPREL, DT_PLTRELSZ, (resolve);
+#else
+#define ELF_DYNAMIC_DO_RELA(map, lazy, resolve) /* Nothing to do.  */
+#endif
+
+/* This can't just be an inline function because GCC is too dumb
+   to inline functions containing inlines themselves.  */
+#define ELF_DYNAMIC_RELOCATE(map, lazy, resolve) \
+  do { ELF_DYNAMIC_DO_REL ((map), (lazy), (resolve)); \
+       ELF_DYNAMIC_DO_RELA ((map), (lazy), (resolve)); } while (0)
diff --git a/elf/link.h b/elf/link.h
index 7b999dc532..66de6d97d7 100644
--- a/elf/link.h
+++ b/elf/link.h
@@ -131,17 +131,23 @@ extern void _dl_sysdep_fatal (const char *string, ...)
 extern int _dl_secure;
 
 /* This function is called by all the internal dynamic linker functions
-   when they encounter an error.  ERRCODE is either an `errno' code
-   or zero; ERRSTRING is a string describing the specific problem.  */
+   when they encounter an error.  ERRCODE is either an `errno' code or
+   zero; OBJECT is the name of the problematical shared object, or null if
+   it is a general problem; ERRSTRING is a string describing the specific
+   problem.  */
    
-extern void _dl_signal_error (int errcode, const char *errstring)
+extern void _dl_signal_error (int errcode,
+			      const char *object,
+			      const char *errstring)
      __attribute__ ((__noreturn__));
 
 /* Call OPERATE, catching errors from `dl_signal_error'.  If there is no
-   error, *ERRSTRING is set to null.  If there is an error, *ERRSTRING is
-   set to the string passed to _dl_signal_error, and the error code passed
-   is the return value.  */
-extern int _dl_catch_error (const char **errstring, void (*operate) (void));
+   error, *ERRSTRING is set to null.  If there is an error, *ERRSTRING and
+   *OBJECT are set to the strings passed to _dl_signal_error, and the error
+   code passed is the return value.  */
+extern int _dl_catch_error (const char **errstring,
+			    const char **object,
+			    void (*operate) (void));
 
 
 /* Helper function for <dlfcn.h> functions.  Runs the OPERATE function via
@@ -166,10 +172,12 @@ extern void _dl_setup_hash (struct link_map *map);
    referred to by UNDEF.  *SYM is the symbol table entry containing the
    reference; it is replaced with the defining symbol, and the base load
    address of the defining object is returned.  SYMBOL_SCOPE is the head of
-   the chain used for searching.  */
+   the chain used for searching.  REFERENCE_NAME should name the object
+   containing the reference; it is used in error messages.  */
 extern Elf32_Addr _dl_lookup_symbol (const char *undef,
 				     const Elf32_Sym **sym,
-				     struct link_map *symbol_scope);
+				     struct link_map *symbol_scope,
+				     const char *reference_name);
 
 
 /* List of objects currently loaded.  */
diff --git a/elf/rtld.c b/elf/rtld.c
index fd75779a01..0605336603 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -52,40 +52,33 @@ static void dl_main (const Elf32_Phdr *phdr,
 Elf32_Addr
 _dl_start (void *arg)
 {
-  Elf32_Addr rtld_loadaddr;
-  Elf32_Dyn *dynamic_section;
-  Elf32_Dyn *dynamic_info[DT_NUM];
+  struct link_map rtld_map;
 
   /* Figure out the run-time load address of the dynamic linker itself.  */
-  rtld_loadaddr = elf_machine_load_address ();
+  rtld_map.l_addr = elf_machine_load_address ();
 
   /* Read our own dynamic section and fill in the info array.
      Conveniently, the first element of the GOT contains the
      offset of _DYNAMIC relative to the run-time load address.  */
-  dynamic_section = (void *) rtld_loadaddr + *elf_machine_got ();
-  elf_get_dynamic_info (dynamic_section, dynamic_info);
+  rtld_map.l_ld = (void *) rtld_map.l_addr + *elf_machine_got ();
+  elf_get_dynamic_info (rtld_map.l_ld, rtld_map.l_info);
 
 #ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
-  ELF_MACHINE_BEFORE_RTLD_RELOC (dynamic_info);
+  ELF_MACHINE_BEFORE_RTLD_RELOC (rtld_map.l_info);
 #endif
 
   /* Relocate ourselves so we can do normal function calls and
      data access using the global offset table.  */
-  {
-    Elf32_Addr resolve (const Elf32_Sym **ref)
-      {
-	assert ((*ref)->st_shndx != SHN_UNDEF);
-	return rtld_loadaddr;
-      }
-    elf_dynamic_relocate (dynamic_info, rtld_loadaddr, 0, resolve);
-  }
+
+  ELF_DYNAMIC_RELOCATE (&rtld_map, 0, NULL);
+
 
   /* Now life is sane; we can call functions and access global data.
      Set up to use the operating system facilities, and find out from
      the operating system's program loader where to find the program
      header table in core.  */
 
-  dl_r_debug.r_ldbase = rtld_loadaddr; /* Record our load address.  */
+  dl_r_debug.r_ldbase = rtld_map.l_addr; /* Record our load address.  */
 
   /* Call the OS-dependent function to set up life so we can do things like
      file access.  It will call `dl_main' (below) to do all the real work
@@ -107,29 +100,30 @@ dl_main (const Elf32_Phdr *phdr,
 {
   void doit (void)
     {
-  const Elf32_Phdr *ph;
-  struct link_map *l;
-  const char *interpreter_name;
-  int lazy;
+      const Elf32_Phdr *ph;
+      struct link_map *l;
+      const char *interpreter_name;
+      int lazy;
 
-  if (*user_entry == (Elf32_Addr) &_start)
-    {
-      /* Ho ho.  We are not the program interpreter!  We are the program
-	 itself!  This means someone ran ld.so as a command.  Well, that
-	 might be convenient to do sometimes.  We support it by
-	 interpreting the args like this:
-
-	 ld.so PROGRAM ARGS...
-	 
-	 The first argument is the name of a file containing an ELF
-	 executable we will load and run with the following arguments.  To
-	 simplify life here, PROGRAM is searched for using the normal rules
-	 for shared objects, rather than $PATH or anything like that.  We
-	 just load it and use its entry point; we don't pay attention to
-	 its PT_INTERP command (we are the interpreter ourselves).  This is
-	 an easy way to test a new ld.so before installing it.  */
-      if (_dl_argc < 2)
-	_dl_sysdep_fatal ("\
+      if (*user_entry == (Elf32_Addr) &_start)
+	{
+	  /* Ho ho.  We are not the program interpreter!  We are the program
+	     itself!  This means someone ran ld.so as a command.  Well, that
+	     might be convenient to do sometimes.  We support it by
+	     interpreting the args like this:
+	     
+	     ld.so PROGRAM ARGS...
+	     
+	     The first argument is the name of a file containing an ELF
+	     executable we will load and run with the following arguments.
+	     To simplify life here, PROGRAM is searched for using the
+	     normal rules for shared objects, rather than $PATH or anything
+	     like that.  We just load it and use its entry point; we don't
+	     pay attention to its PT_INTERP command (we are the interpreter
+	     ourselves).  This is an easy way to test a new ld.so before
+	     installing it.  */
+	  if (_dl_argc < 2)
+	    _dl_sysdep_fatal ("\
 Usage: ld.so EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]\n\
 You have invoked `ld.so', the helper program for shared library executables.\n\
 This program usually lives in the file `/lib/ld.so', and special directives\n\
@@ -142,116 +136,118 @@ that file itself, but always uses this helper program from the file you\n\
 specified, instead of the helper program file specified in the executable\n\
 file you run.  This is mostly of use for maintainers to test new versions\n\
 of this helper program; chances are you did not intend to run this program.\n"
-			  );
-
-      interpreter_name = _dl_argv[0];
-      --_dl_argc;
-      ++_dl_argv;
-      l = _dl_map_object (NULL, _dl_argv[0], user_entry);
-      phdr = l->l_phdr;
-      phent = l->l_phnum;
-      l->l_type = lt_executable;
-      l->l_libname = (char *) "";
-    }
-  else
-    {
-      /* Create a link_map for the executable itself.
-	 This will be what dlopen on "" returns.  */
-      l = _dl_new_object ((char *) "", "", lt_executable);
-      l->l_phdr = phdr;
-      l->l_phnum = phent;
-      interpreter_name = 0;
-    }
+			      );
+
+	  interpreter_name = _dl_argv[0];
+	  --_dl_argc;
+	  ++_dl_argv;
+	  l = _dl_map_object (NULL, _dl_argv[0], user_entry);
+	  phdr = l->l_phdr;
+	  phent = l->l_phnum;
+	  l->l_type = lt_executable;
+	  l->l_libname = (char *) "";
+	}
+      else
+	{
+	  /* Create a link_map for the executable itself.
+	     This will be what dlopen on "" returns.  */
+	  l = _dl_new_object ((char *) "", "", lt_executable);
+	  l->l_phdr = phdr;
+	  l->l_phnum = phent;
+	  interpreter_name = 0;
+	}
 
-  /* Scan the program header table for the dynamic section.  */
-  for (ph = phdr; ph < &phdr[phent]; ++ph)
-    switch (ph->p_type)
-      {
-      case PT_DYNAMIC:
-	/* This tells us where to find the dynamic section,
-	   which tells us everything we need to do.  */
-	l->l_ld = (void *) ph->p_vaddr;
-	break;
-      case PT_INTERP:
-	/* This "interpreter segment" was used by the program loader to
-	   find the program interpreter, which is this program itself, the
-	   dynamic linker.  We note what name finds us, so that a future
-	   dlopen call or DT_NEEDED entry, for something that wants to link
-	   against the dynamic linker as a shared library, will know that
-	   the shared object is already loaded.  */
-	interpreter_name = (void *) ph->p_vaddr;
-	break;
-      }
-  assert (interpreter_name);	/* How else did we get here?  */
-
-  /* Extract the contents of the dynamic section for easy access.  */
-  elf_get_dynamic_info (l->l_ld, l->l_info);
-  /* Set up our cache of pointers into the hash table.  */
-  _dl_setup_hash (l);
-
-  if (l->l_info[DT_DEBUG])
-    /* There is a DT_DEBUG entry in the dynamic section.  Fill it in
-       with the run-time address of the r_debug structure, which we
-       will set up later to communicate with the debugger.  */
-    l->l_info[DT_DEBUG]->d_un.d_ptr = (Elf32_Addr) &dl_r_debug;
-
-  l = _dl_new_object ((char *) interpreter_name, interpreter_name,
-		      lt_interpreter);
-
-  /* Now process all the DT_NEEDED entries and map in the objects.
-     Each new link_map will go on the end of the chain, so we will
-     come across it later in the loop to map in its dependencies.  */
-  for (l = _dl_loaded; l; l = l->l_next)
-    {
-      if (l->l_info[DT_NEEDED])
+      /* Scan the program header table for the dynamic section.  */
+      for (ph = phdr; ph < &phdr[phent]; ++ph)
+	switch (ph->p_type)
+	  {
+	  case PT_DYNAMIC:
+	    /* This tells us where to find the dynamic section,
+	       which tells us everything we need to do.  */
+	    l->l_ld = (void *) ph->p_vaddr;
+	    break;
+	  case PT_INTERP:
+	    /* This "interpreter segment" was used by the program loader to
+	       find the program interpreter, which is this program itself, the
+	       dynamic linker.  We note what name finds us, so that a future
+	       dlopen call or DT_NEEDED entry, for something that wants to link
+	       against the dynamic linker as a shared library, will know that
+	       the shared object is already loaded.  */
+	    interpreter_name = (void *) ph->p_vaddr;
+	    break;
+	  }
+      assert (interpreter_name); /* How else did we get here?  */
+
+      /* Extract the contents of the dynamic section for easy access.  */
+      elf_get_dynamic_info (l->l_ld, l->l_info);
+      /* Set up our cache of pointers into the hash table.  */
+      _dl_setup_hash (l);
+
+      if (l->l_info[DT_DEBUG])
+	/* There is a DT_DEBUG entry in the dynamic section.  Fill it in
+	   with the run-time address of the r_debug structure, which we
+	   will set up later to communicate with the debugger.  */
+	l->l_info[DT_DEBUG]->d_un.d_ptr = (Elf32_Addr) &dl_r_debug;
+
+      l = _dl_new_object ((char *) interpreter_name, interpreter_name,
+			  lt_interpreter);
+
+      /* Now process all the DT_NEEDED entries and map in the objects.
+	 Each new link_map will go on the end of the chain, so we will
+	 come across it later in the loop to map in its dependencies.  */
+      for (l = _dl_loaded; l; l = l->l_next)
 	{
-	  const char *strtab
-	    = (void *) l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr;
-	  const Elf32_Dyn *d;
-	  for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
-	    if (d->d_tag == DT_NEEDED)
-	      _dl_map_object (l, strtab + d->d_un.d_val, NULL);
+	  if (l->l_info[DT_NEEDED])
+	    {
+	      const char *strtab
+		= (void *) l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr;
+	      const Elf32_Dyn *d;
+	      for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
+		if (d->d_tag == DT_NEEDED)
+		  _dl_map_object (l, strtab + d->d_un.d_val, NULL);
+	    }
+	  l->l_deps_loaded = 1;
 	}
-      l->l_deps_loaded = 1;
-    }
 
-  l = _dl_loaded->l_next;
-  assert (l->l_type == lt_interpreter);
-  if (l->l_opencount == 0)
-    {
-      /* No DT_NEEDED entry referred to the interpreter object itself.
-	 Remove it from the maps we will use for symbol resolution.  */
-      l->l_prev->l_next = l->l_next;
-      if (l->l_next)
-	l->l_next->l_prev = l->l_prev;
-    }
+      l = _dl_loaded->l_next;
+      assert (l->l_type == lt_interpreter);
+      if (l->l_opencount == 0)
+	{
+	  /* No DT_NEEDED entry referred to the interpreter object itself.
+	     Remove it from the maps we will use for symbol resolution.  */
+	  l->l_prev->l_next = l->l_next;
+	  if (l->l_next)
+	    l->l_next->l_prev = l->l_prev;
+	}
 
-  lazy = _dl_secure || *(getenv ("LD_BIND_NOW") ?: "");
+      lazy = _dl_secure || *(getenv ("LD_BIND_NOW") ?: "");
 
-  /* Now we have all the objects loaded.  Relocate them all.
-     We do this in reverse order so that copy relocs of earlier
-     objects overwrite the data written by later objects.  */
-  l = _dl_loaded;
-  while (l->l_next)
-    l = l->l_next;
-  do
-    {
-      _dl_relocate_object (l, lazy);
-      l = l->l_prev;
-    } while (l);
-
-  /* Tell the debugger where to find the map of loaded objects.  */
-  dl_r_debug.r_version = 1 /* R_DEBUG_VERSION XXX */;
-  dl_r_debug.r_map = _dl_loaded;
-  dl_r_debug.r_brk = (Elf32_Addr) &_dl_r_debug_state;
-}
+      /* Now we have all the objects loaded.  Relocate them all.
+	 We do this in reverse order so that copy relocs of earlier
+	 objects overwrite the data written by later objects.  */
+      l = _dl_loaded;
+      while (l->l_next)
+	l = l->l_next;
+      do
+	{
+	  _dl_relocate_object (l, lazy);
+	  l = l->l_prev;
+	} while (l);
+
+      /* Tell the debugger where to find the map of loaded objects.  */
+      dl_r_debug.r_version = 1	/* R_DEBUG_VERSION XXX */;
+      dl_r_debug.r_map = _dl_loaded;
+      dl_r_debug.r_brk = (Elf32_Addr) &_dl_r_debug_state;
+    }
   const char *errstring;
+  const char *errobj;
   int err;
 
-  err = _dl_catch_error (&errstring, &doit);
+  err = _dl_catch_error (&errstring, &errobj, &doit);
   if (errstring)
     _dl_sysdep_fatal (_dl_argv[0] ?: "<program name unknown>",
 		      ": error in loading shared libraries\n",
+		      errobj ?: "", errobj ? ": " : "",
 		      errstring, err ? ": " : NULL,
 		      err ? strerror (err) : NULL, NULL);
 
diff --git a/hurd/hurdsig.c b/hurd/hurdsig.c
index 9620a00ca4..c5ce050c7a 100644
--- a/hurd/hurdsig.c
+++ b/hurd/hurdsig.c
@@ -667,9 +667,16 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
       /* Nobody cares about this signal.  */
       break;
 
+    sigbomb:
+      /* We got a fault setting up the stack frame for the handler.
+	 Nothing to do but die; BSD gets SIGILL in this case.  */
+      sigcode = signo;	/* XXX ? */
+      signo = SIGILL;
+      act = core;
+      /* FALLTHROUGH */
+
     case term:			/* Time to die.  */
     case core:			/* And leave a rotting corpse.  */
-    nirvana:
       /* Have the proc server stop all other threads in our task.  */
       err = __USEPORT (PROC, __proc_dostop (port, _hurd_msgport_thread));
       assert_perror (err);
@@ -693,7 +700,7 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
     case handle:
       /* Call a handler for this signal.  */
       {
-	struct sigcontext *scp;
+	struct sigcontext *scp, ocontext;
 	int wait_for_reply, state_changed;
 
 	/* Stop the thread and abort its pending RPC operations.  */
@@ -710,19 +717,64 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
 	   thread_get_state is never kosher before thread_abort.  */
 	abort_thread (ss, &thread_state, NULL, 0, 0);
 
-	wait_for_reply = (abort_rpcs (ss, signo, &thread_state, &state_changed,
-				      &reply_port, reply_port_type, untraced)
-			  != MACH_PORT_NULL);
+	if (ss->context)
+	  {
+	    /* We have a previous sigcontext that sigreturn was about
+	       to restore when another signal arrived.  */
+
+	    mach_port_t *loc;
 
-	if (ss->critical_section)
+	    if (_hurdsig_catch_fault (SIGSEGV))
+	      {
+		assert (_hurdsig_fault_sigcode >= (long int) ss->context &&
+			_hurdsig_fault_sigcode < (long int) (ss->context + 1));
+		/* We faulted reading the thread's stack.  Forget that
+		   context and pretend it wasn't there.  It almost
+		   certainly crash if this handler returns, but that's it's
+		   problem.  */
+		ss->context = NULL;
+	      }
+	    else
+	      {
+		/* Copy the context from the thread's stack before
+		   we start diddling the stack to set up the handler.  */
+		ocontext = *ss->context;
+		ss->context = &ocontext;
+	      }
+	    _hurdsig_end_catch_fault ();
+	    
+	    if (! machine_get_basic_state (ss->thread, &thread_state))
+	      goto sigbomb;
+	    loc = interrupted_reply_port_location (&thread_state);
+	    if (loc && *loc != MACH_PORT_NULL)
+	      /* This is the reply port for the context which called
+		 sigreturn.  Since we are abandoning that context entirely
+		 and restoring SS->context instead, destroy this port.  */
+	      __mach_port_destroy (__mach_task_self (), *loc);
+
+	    /* The thread was in sigreturn, not in any interruptible RPC.  */
+	    wait_for_reply = 0;
+
+	    assert (! ss->critical_section);
+	  }
+	else
 	  {
-	    /* The thread is in a critical section.  Mark the signal as
-	       pending.  When it finishes the critical section, it will
-	       check for pending signals.  */
-	    mark_pending ();
-	    assert (! state_changed);
-	    __thread_resume (ss->thread);
-	    break;
+	    wait_for_reply = (abort_rpcs (ss, signo,
+					  &thread_state, &state_changed,
+					  &reply_port, reply_port_type,
+					  untraced)
+			      != MACH_PORT_NULL);
+
+	    if (ss->critical_section)
+	      {
+		/* The thread is in a critical section.  Mark the signal as
+		   pending.  When it finishes the critical section, it will
+		   check for pending signals.  */
+		mark_pending ();
+		assert (! state_changed);
+		__thread_resume (ss->thread);
+		break;
+	      }
 	  }
 
 	/* Call the machine-dependent function to set the thread up
@@ -731,18 +783,10 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
 				      signo, sigcode,
 				      wait_for_reply, &thread_state);
 	if (scp == NULL)
-	  {
-	    /* We got a fault setting up the stack frame for the handler.
-	       Nothing to do but die; BSD gets SIGILL in this case.  */
-	    sigcode = signo;	/* XXX ? */
-	    signo = SIGILL;
-	    act = core;
-	    goto nirvana;
-	  }
+	  goto sigbomb;
 
 	/* Set the machine-independent parts of the signal context.  */
 
-	scp->sc_error = sigerror;
 	{
 	  /* Fetch the thread variable for the MiG reply port,
 	     and set it to MACH_PORT_NULL.  */
@@ -754,17 +798,32 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
 	    }
 	  else
 	    scp->sc_reply_port = MACH_PORT_NULL;
+
+	  /* Save the intr_port in use by the interrupted code,
+	     and clear the cell before running the trampoline.  */
+	  scp->sc_intr_port = ss->intr_port;
+	  ss->intr_port = MACH_PORT_NULL;
+
+	  if (ss->context)
+	    {
+	      /* After the handler runs we will restore to the state in
+		 SS->context, not the state of the thread now.  So restore
+		 that context's reply port and intr port.  */
+
+	      scp->sc_reply_port = ss->context->sc_reply_port;
+	      scp->sc_intr_port = ss->context->sc_intr_port;
+
+	      ss->context = NULL;
+	    }
 	}
 
+	/* Backdoor extra argument to signal handler.  */
+	scp->sc_error = sigerror;
+
 	/* Block SIGNO and requested signals while running the handler.  */
 	scp->sc_mask = ss->blocked;
 	ss->blocked |= __sigmask (signo) | ss->actions[signo].sa_mask;
 
-	/* Save the intr_port in use by the interrupted code,
-	   and clear the cell before running the trampoline.  */
-	scp->sc_intr_port = ss->intr_port;
-	ss->intr_port = MACH_PORT_NULL;
-
 	/* Start the thread running the handler (or possibly waiting for an
 	   RPC reply before running the handler).  */
 	err = __thread_set_state (ss->thread, MACHINE_THREAD_STATE_FLAVOR,
diff --git a/mach/Makefile b/mach/Makefile
index 509785cb60..dbb5da5b90 100644
--- a/mach/Makefile
+++ b/mach/Makefile
@@ -183,8 +183,12 @@ endif
 # Be sure not to make these with implicit rules from foo.defs.
 mach.h mach/memory_object.h: ;
 
+ifneq (,)
+# A gcc bug prevents the generated file from working properly,
+# so we have one in the distribution for the time being.
 generated += errsystems.c
 $(objpfx)errsystems.c: errsystems.awk err_*.sub \
 		       $(wildcard $(addsuffix /err_*.sub,$(+sysdep_dirs)))
 	gawk -v subsys='$(filter-out $<,$^)' -f $^ > $@.n
 	mv $@.n $@
+endif
diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h
index 5e1ee2a413..1797ae5b87 100644
--- a/sysdeps/i386/dl-machine.h
+++ b/sysdeps/i386/dl-machine.h
@@ -68,11 +68,10 @@ elf_machine_load_address (void)
   ++(const Elf32_Rel *) (dynamic_info)[DT_REL]->d_un.d_ptr;
 
 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
-   LOADADDR is the load address of the object; INFO is an array indexed
-   by DT_* of the .dynamic section info.  */
+   MAP is the object containing the reloc.  */
 
 static inline void
-elf_machine_rel (Elf32_Addr loadaddr, Elf32_Dyn *info[DT_NUM],
+elf_machine_rel (struct link_map *map,
 		 const Elf32_Rel *reloc,
 		 Elf32_Addr sym_loadaddr, const Elf32_Sym *sym)
 {
@@ -92,7 +91,7 @@ elf_machine_rel (Elf32_Addr loadaddr, Elf32_Dyn *info[DT_NUM],
       *reloc_addr += sym_value;
       break;
     case R_386_RELATIVE:
-      *reloc_addr += loadaddr;
+      *reloc_addr += map->l_addr;
       break;
     case R_386_PC32:
       *reloc_addr = sym_value - (Elf32_Addr) reloc_addr;
@@ -105,13 +104,7 @@ elf_machine_rel (Elf32_Addr loadaddr, Elf32_Dyn *info[DT_NUM],
 
 
 /* The i386 never uses Elf32_Rela relocations.  */
-static inline void
-elf_machine_rela (Elf32_Addr loadaddr, Elf32_Dyn *info[DT_NUM],
-		  const Elf32_Rela *reloc, 
-		  Elf32_Addr sym_loadaddr, const Elf32_Sym *sym)
-{
-  _dl_signal_error (0, "Elf32_Rela relocation requested -- unused on i386");
-}
+#define ELF_MACHINE_NO_RELA 1
 
 
 /* Set up the loaded object described by L so its unrelocated PLT
@@ -140,9 +133,16 @@ elf_machine_runtime_setup (struct link_map *l)
 #define RTLD_START asm ("\
 .text\n\
 .globl _start\n\
-_start:	call _dl_start\n\
-	# Save the user entry point address in %ebx.\n\
-	movl %eax, %ebx\n\
+.globl _dl_start_user\n\
+_start:\n\
+	call _dl_start\n\
+_dl_start_user:\n\
+	# Save the user entry point address in %edi.\n\
+	movl %eax, %edi\n\
+	# Point %ebx at the GOT.
+1:	call 2f\n\
+2:	popl %ebx\n\
+	addl $_GLOBAL_OFFSET_TABLE_+[.-2b], %ebx\n\
 	# Call _dl_init_next to return the address of an initializer\n\
 	# function to run.\n\
 0:	call _dl_init_next@PLT\n\
@@ -160,10 +160,7 @@ _start:	call _dl_start\n\
 	# Loop to call _dl_init_next for the next initializer.\n\
 	jmp 0b\n\
 	# Pass our finalizer function to the user in %edx, as per ELF ABI.\n\
-1:	call 2f\n\
-2:	popl %eax\n\
-	addl $_GLOBAL_OFFSET_TABLE_+[.-2b], %eax\n\
-	leal _dl_fini@GOT(%eax), %edx\n\
-	# Jump to the user entry point.\n\
-	jmp *%ebx\n\
+	leal _dl_fini@GOT(%ebx), %edx\n\
+	# Jump to the user's entry point.\n\
+	jmp *%edi\n\
 ");
diff --git a/sysdeps/i386/dl-runtime.c b/sysdeps/i386/dl-runtime.c
index 897524fdd3..1bc569760c 100644
--- a/sysdeps/i386/dl-runtime.c
+++ b/sysdeps/i386/dl-runtime.c
@@ -17,8 +17,6 @@ License along with the GNU C Library; see the file COPYING.LIB.  If
 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
 Cambridge, MA 02139, USA.  */
 
-register void *sp asm ("%esp");
-
 #include <link.h>
 #include "dynamic-link.h"
 
@@ -30,7 +28,7 @@ register void *sp asm ("%esp");
    0(%esp)	identifier for this shared object (struct link_map *)
 
    The user expects the real function the PLT refers to to be entered
-   8(%esp) as the top of stack.  */
+   with 8(%esp) as the top of stack.  */
 
 void
 _dl_runtime_resolve (Elf32_Word reloc_offset)
@@ -63,14 +61,15 @@ _dl_runtime_resolve (Elf32_Word reloc_offset)
     scope = _dl_loaded;
   
   definer = &symtab[ELF32_R_SYM (reloc->r_info)];
-  loadbase = _dl_lookup_symbol (strtab + definer->st_name, &definer, scope);
+  loadbase = _dl_lookup_symbol (strtab + definer->st_name, &definer,
+				scope, l->l_name);
   
   /* Restore list frobnication done above for DT_SYMBOLIC.  */
   l->l_next = real_next;
   l->l_prev->l_next = l;
 
   /* Apply the relocation with that value.  */
-  elf_machine_rel (l->l_addr, l->l_info, reloc, loadbase, definer);
+  elf_machine_rel (l, reloc, loadbase, definer);
 
   /* The top of the stack is the word we set L from; but this location
      holds the address we will return to.  Store there the address of a
diff --git a/sysdeps/mach/_strerror.c b/sysdeps/mach/_strerror.c
index 4740902a10..398c77fbdf 100644
--- a/sysdeps/mach/_strerror.c
+++ b/sysdeps/mach/_strerror.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1995 Free Software Foundation, Inc.
 This file is part of the GNU C Library.
 
 The GNU C Library is free software; you can redistribute it and/or
@@ -20,7 +20,7 @@ Cambridge, MA 02139, USA.  */
 #include <stdio.h>
 #include <string.h>
 #include <mach/error.h>
-#include <mach/errorlib.h>
+#include <errorlib.h>
 
 /* Return a string describing the errno code in ERRNUM.  */
 char *
@@ -38,7 +38,7 @@ DEFUN(_strerror_internal, (errnum, buf), int errnum AND char buf[1024])
   sub = err_get_sub (errnum);
   code = err_get_code (errnum);
 
-  if (system > err_max_system)
+  if (system > err_max_system || ! __mach_error_systems[system].bad_sub)
     {
       sprintf (buf, "Unknown error system %d", system);
       return buf;
diff --git a/sysdeps/mach/hurd/getdtsz.c b/sysdeps/mach/hurd/getdtsz.c
index 3e6385f64e..1befd48a70 100644
--- a/sysdeps/mach/hurd/getdtsz.c
+++ b/sysdeps/mach/hurd/getdtsz.c
@@ -21,6 +21,7 @@ Cambridge, MA 02139, USA.  */
 #include <unistd.h>
 #include <hurd.h>
 #include <hurd/fd.h>
+#include <hurd/resource.h>
 
 /* Return the maximum number of file descriptors the current process
    could possibly have (until it raises the resource limit).  */
@@ -29,9 +30,9 @@ DEFUN_VOID(__getdtablesize)
 {
   int size;
   HURD_CRITICAL_BEGIN;
-  __mutex_lock (&_hurd_rlimits_lock);
-  size = _hurd_rlimits[RLIM_NOFILE].rlim_cur; /* XXX RLIM_INFINITY?? */
-  __mutex_unlock (&_hurd_rlimits_lock);
+  __mutex_lock (&_hurd_rlimit_lock);
+  size = _hurd_rlimits[RLIMIT_NOFILE].rlim_cur;
+  __mutex_unlock (&_hurd_rlimit_lock);
   HURD_CRITICAL_END;
   return size;
 }
diff --git a/sysdeps/mach/hurd/i386/sigreturn.c b/sysdeps/mach/hurd/i386/sigreturn.c
index d00fa7755f..0e5ccfc9f5 100644
--- a/sysdeps/mach/hurd/i386/sigreturn.c
+++ b/sysdeps/mach/hurd/i386/sigreturn.c
@@ -57,15 +57,13 @@ __sigreturn (struct sigcontext *scp)
 	 the signal thread will notice it if it runs another handler, and
 	 arrange to have us called over again in the new reality.  */
       ss->context = scp;
-      /* Clear the intr_port slot, since we are not in fact doing
-	 an interruptible RPC right now.  If SS->intr_port is not null,
-	 the SCP context is doing an interruptible RPC, but the signal
-	 thread will examine us while we are blocked in the sig_post RPC.  */
-      ss->intr_port = MACH_PORT_NULL;
       __spin_unlock (&ss->lock);
       __msg_sig_post (_hurd_msgport, 0, __mach_task_self ());
-      /* If a pending signal was handled, sig_post never returned.  */
+      /* If a pending signal was handled, sig_post never returned.
+	 If it did return, the pending signal didn't run a handler;
+	 proceed as usual.  */
       __spin_lock (&ss->lock);
+      ss->context = NULL;
     }
 
   if (scp->sc_onstack)
diff --git a/sysdeps/mach/hurd/i386/trampoline.c b/sysdeps/mach/hurd/i386/trampoline.c
index 3402181481..2a31588e21 100644
--- a/sysdeps/mach/hurd/i386/trampoline.c
+++ b/sysdeps/mach/hurd/i386/trampoline.c
@@ -73,23 +73,11 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
 		  sizeof (state->basic));
 	  memcpy (&state->fpu, &ss->context->sc_i386_float_state,
 		  sizeof (state->fpu));
-	  state->set = (1 << i386_THREAD_STATE) | (1 << i386_FLOAT_STATE);
-	  assert (! rpc_wait);
-	  /* The intr_port slot was cleared before sigreturn sent us the
-	     sig_post that made us notice this pending signal, so
-	     _hurd_internal_post_signal wouldn't do interrupt_operation.
-	     After we return, our caller will set SCP->sc_intr_port (in the
-	     new context) from SS->intr_port and clear SS->intr_port.  Now
-	     that we are restoring this old context recorded by sigreturn,
-	     we want to restore its intr_port too; so store it in
-	     SS->intr_port now, so it will end up in SCP->sc_intr_port
-	     later.  */
-	  ss->intr_port = ss->context->sc_intr_port;
+	  state->set |= (1 << i386_THREAD_STATE) | (1 << i386_FLOAT_STATE);
 	}
-      /* If the sigreturn context was bogus, just ignore it.  */
-      ss->context = NULL;
     }
-  else if (! machine_get_basic_state (ss->thread, state))
+
+  if (! machine_get_basic_state (ss->thread, state))
     return NULL;
 
   if ((ss->actions[signo].sa_flags & SA_ONSTACK) &&