about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog96
-rwxr-xr-xconfigure6
-rw-r--r--elf/dl-open.c3
-rw-r--r--elf/dl-profile.c6
-rw-r--r--elf/dl-reloc.c7
-rw-r--r--elf/dl-support.c3
-rw-r--r--elf/dynamic-link.h8
-rw-r--r--elf/elf.h6
-rw-r--r--elf/ldsodefs.h6
-rw-r--r--elf/rtld.c15
-rw-r--r--elf/sprof.c220
-rw-r--r--libc.map5
-rw-r--r--libio/fgetc.c5
-rw-r--r--libio/fileops.c3
-rw-r--r--libio/fputc.c5
-rw-r--r--libio/freopen.c3
-rw-r--r--libio/freopen64.c5
-rw-r--r--libio/fseek.c5
-rw-r--r--libio/fseeko.c5
-rw-r--r--libio/fseeko64.c5
-rw-r--r--libio/ftello.c5
-rw-r--r--libio/ftello64.c5
-rw-r--r--libio/getc.c5
-rw-r--r--libio/getchar.c7
-rw-r--r--libio/iofclose.c3
-rw-r--r--libio/iofflush.c5
-rw-r--r--libio/iofgetpos.c5
-rw-r--r--libio/iofgetpos64.c5
-rw-r--r--libio/iofgets.c5
-rw-r--r--libio/iofputs.c5
-rw-r--r--libio/iofread.c5
-rw-r--r--libio/iofsetpos.c5
-rw-r--r--libio/iofsetpos64.c5
-rw-r--r--libio/ioftell.c5
-rw-r--r--libio/iofwrite.c5
-rw-r--r--libio/iogetdelim.c5
-rw-r--r--libio/iogets.c5
-rw-r--r--libio/ioputs.c5
-rw-r--r--libio/ioseekoff.c5
-rw-r--r--libio/ioseekpos.c5
-rw-r--r--libio/iosetbuffer.c5
-rw-r--r--libio/iosetvbuf.c5
-rw-r--r--libio/ioungetc.c5
-rw-r--r--libio/iovsprintf.c5
-rw-r--r--libio/iovsscanf.c3
-rw-r--r--libio/oldfileops.c3
-rw-r--r--libio/oldiofclose.c5
-rw-r--r--libio/peekc.c5
-rw-r--r--libio/putc.c5
-rw-r--r--libio/putchar.c5
-rw-r--r--libio/rewind.c5
-rw-r--r--linuxthreads/ChangeLog4
-rw-r--r--linuxthreads/sysdeps/pthread/bits/libc-lock.h7
-rw-r--r--malloc/mtrace.c9
-rw-r--r--misc/mntent.h10
-rw-r--r--nis/nis_print.c19
-rw-r--r--signal/Makefile2
-rw-r--r--stdio-common/vfprintf.c7
-rw-r--r--stdio-common/vfscanf.c12
-rw-r--r--sysdeps/generic/libc-start.c6
-rw-r--r--sysdeps/generic/sigset-cvt-mask.h24
-rw-r--r--sysdeps/i386/dl-machine.h9
-rw-r--r--sysdeps/i386/elf/start.S5
-rw-r--r--sysdeps/posix/mkstemp.c2
-rw-r--r--sysdeps/posix/sigvec.c164
-rw-r--r--sysdeps/unix/sysv/linux/i386/clone.S6
-rw-r--r--sysdeps/unix/sysv/linux/i386/i686/sysdep.h19
-rw-r--r--sysdeps/unix/sysv/linux/i386/mmap.S2
-rw-r--r--sysdeps/unix/sysv/linux/i386/s_pread64.S8
-rw-r--r--sysdeps/unix/sysv/linux/i386/s_pwrite64.S8
-rw-r--r--sysdeps/unix/sysv/linux/i386/socket.S2
-rw-r--r--sysdeps/unix/sysv/linux/i386/syscall.S2
-rw-r--r--sysdeps/unix/sysv/linux/i386/sysdep.h35
-rw-r--r--sysdeps/unix/sysv/linux/sigset-cvt-mask.h35
-rw-r--r--sysdeps/unix/sysv/sysv4/sigset-cvt-mask.h33
75 files changed, 703 insertions, 295 deletions
diff --git a/ChangeLog b/ChangeLog
index de5eec17d0..cc8ba2f5f8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,99 @@
+1998-06-07 13:32  Ulrich Drepper  <drepper@cygnus.com>
+
+	* libc.map: Add _dl_profile.
+	* elf/dl-reloc.c (_dl_relocate_object): Take extra argument, pass
+	this to ELF_DYNAMIC_RELOCATE.
+	Always allocate array for relocation result if LD_PROFILE is defined.
+	* elf/ldsodefs.h: Adjust prototypes.
+	* elf/dl-open.c (_dl_open): Call relocation function with extra
+	argument.
+	* elf/rtld.c: Likewise.
+	* elf/dl-profile.c (_dl_mcount): Don't mark as internal function.
+	Correct loop condition.
+	* elf/dynamic-link.h: Don't examine _dl_profile variable, pass
+	consider_profile to runtime setup function.
+	* sysdeps/i386/dl-machine.h (elf_machine_runtime_setup): Use
+	_dl_runtime_profile for all shared objects if LD_PROFILE is defined.
+
+	* elf/dl-support.c: Define __libc_stack_end.
+	* elf/rtld.c: Likewise.
+	* sysdeps/generic/libc-start.c: Store last stack address in
+	__libc_stack_end.
+	* sysdeps/i386/dl-machine.h (_dl_start_user): Store stack address.
+	* sysdeps/i386/elf/start.s: Call __libc_start_main with extra argument.
+
+	* elf/elf.h: Include <features.h>, not <sys/cdefs.h>.
+	Include <stdint.h>, not <inttypes.h>.
+
+	* elf/sprof.c: Implement flat profiling.
+
+	* libio/fgetc.c: Call _IO_cleanup_region_end with 0 and call
+	_IO_funlockfile explicitly.
+	* libio/fileops.c: Likewise.
+	* libio/fputc.c: Likewise.
+	* libio/freopen.c: Likewise.
+	* libio/freopen64.c: Likewise.
+	* libio/fseek.c: Likewise.
+	* libio/fseeko.c: Likewise.
+	* libio/fseeko64.c: Likewise.
+	* libio/ftello.c: Likewise.
+	* libio/ftello64.c: Likewise.
+	* libio/getc.c: Likewise.
+	* libio/getchar.c: Likewise.
+	* libio/iofclose.c: Likewise.
+	* libio/iofflush.c: Likewise.
+	* libio/iofgetpos.c: Likewise.
+	* libio/iofgetpos64.c: Likewise.
+	* libio/iofgets.c: Likewise.
+	* libio/iofputs.c: Likewise.
+	* libio/iofread.c: Likewise.
+	* libio/iofsetpos.c: Likewise.
+	* libio/iofsetpos64.c: Likewise.
+	* libio/ioftell.c: Likewise.
+	* libio/iofwrite.c: Likewise.
+	* libio/iogetdelim.c: Likewise.
+	* libio/iogets.c: Likewise.
+	* libio/ioputs.c: Likewise.
+	* libio/ioseekoff.c: Likewise.
+	* libio/ioseekpos.c: Likewise.
+	* libio/iosetbuffer.c: Likewise.
+	* libio/iosetvbuf.c: Likewise.
+	* libio/ioungetc.c: Likewise.
+	* libio/iovsprintf.c: Likewise.
+	* libio/iovsscanf.c: Likewise.
+	* libio/oldfileops.c: Likewise.
+	* libio/oldiofclose.c: Likewise.
+	* libio/peekc.c: Likewise.
+	* libio/putc.c: Likewise.
+	* libio/putchar.c: Likewise.
+	* libio/rewind.c: Likewise.
+
+	* malloc/mtrace.c: Pretty print.
+
+	* misc/mntent.h (struct mentent): Make string elements const char *.
+
+	* nis/nis_printf.c: Optimize I/O a little bit.
+
+	* signal/Makefile (distribute): Add sigset-cvt-mask.h.
+	* sysdeps/generic/sigset-cvt-mask.h: New file.
+	* sysdeps/unix/sysv/linux/sigset-cvt-mask.h: New file.
+	* sysdeps/unix/sysv/sysv4/sigset-cvt-mask.h: New file.
+	* sysdeps/posix/sigvec.c: Rewrite the use definitions from
+	sigset-cvt-mask.h to do the dirty work.
+	Patches by Joe Keane.
+
+	* sysdeps/posix/mkstemp.c: Save one precious byte of rodata.
+
+	* sysdeps/unix/sysv/linux/i386/sysdep.h: Rewrite PSEUDO etc to make
+	syscall_error label in case of PIC anonymous.
+	* sysdeps/unix/sysv/linux/i386/i686/sysdep.h: Likewise.
+	* sysdeps/unix/sysv/linux/i386/clone.S: Adapt for this change.
+	* sysdeps/unix/sysv/linux/i386/mmap.S: Adapt for this change.
+	* sysdeps/unix/sysv/linux/i386/s_pread64.S: Adapt for this change.
+	* sysdeps/unix/sysv/linux/i386/s_pwrite64.S: Adapt for this change.
+	* sysdeps/unix/sysv/linux/i386/socket.S: Adapt for this change.
+	* sysdeps/unix/sysv/linux/i386/syscall.S: Adapt for this change.
+
 1998-06-05  Ulrich Drepper  <drepper@cygnus.com>
 
 	* sunrpc/xdr_rec.c (xdrrec_create): Add cast for *_ops array since
diff --git a/configure b/configure
index cdc0c9d9d3..56540890ee 100755
--- a/configure
+++ b/configure
@@ -3330,10 +3330,14 @@ while test -n "$ac_sources"; do
 done
 EOF
 cat >> $CONFIG_STATUS <<EOF
-echo '$config_vars' >> config.make; test -d bits || mkdir bits
+config_vars='$config_vars'
 EOF
 cat >> $CONFIG_STATUS <<\EOF
 
+case $CONFIG_FILES in *config.make*)
+echo "$config_vars" >> config.make;;
+esac
+test -d bits || mkdir bits
 exit 0
 EOF
 chmod +x $CONFIG_STATUS
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 308175a8ae..4c4c8abdc5 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -102,7 +102,8 @@ _dl_open (const char *file, int mode)
 	  asm ("" : "=r" (reloc) : "0" (reloc));
 
 	  (*reloc) (l, _dl_object_relocation_scope (l),
-		    (mode & RTLD_BINDING_MASK) == RTLD_LAZY);
+		    ((mode & RTLD_BINDING_MASK) == RTLD_LAZY
+		     || _dl_profile != NULL), _dl_profile != NULL);
 	  *_dl_global_scope_end = NULL;
 	}
 
diff --git a/elf/dl-profile.c b/elf/dl-profile.c
index c7ac360811..a9f8dd6226 100644
--- a/elf/dl-profile.c
+++ b/elf/dl-profile.c
@@ -436,7 +436,6 @@ _dl_start_profile (struct link_map *map, const char *output_dir)
 
 
 void
-internal_function
 _dl_mcount (ElfW(Addr) frompc, ElfW(Addr) selfpc)
 {
   uint16_t *topcindex;
@@ -479,7 +478,7 @@ _dl_mcount (ElfW(Addr) frompc, ElfW(Addr) selfpc)
 
   /* We have to look through the chain of arcs whether there is already
      an entry for our arc.  */
-  while (fromp->here->from_pc == frompc)
+  while (fromp->here->from_pc != frompc)
     {
       if (fromp->link != 0)
 	do
@@ -523,8 +522,7 @@ _dl_mcount (ElfW(Addr) frompc, ElfW(Addr) selfpc)
 	      data[newarc].self_pc = selfpc;
 	      data[newarc].count = 0;
 	      fromp->link = 0;
-
-	      narcs++;
+	      ++narcs;
 
 	      break;
 	    }
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index 898fb48e42..e0eae3c2ae 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -28,7 +28,8 @@
 
 void
 internal_function
-_dl_relocate_object (struct link_map *l, struct link_map *scope[], int lazy)
+_dl_relocate_object (struct link_map *l, struct link_map *scope[], int lazy,
+		     int consider_profiling)
 {
   if (l->l_relocated)
     return;
@@ -72,9 +73,9 @@ _dl_relocate_object (struct link_map *l, struct link_map *scope[], int lazy)
 			  l->l_name, (flags)))
 
 #include "dynamic-link.h"
-    ELF_DYNAMIC_RELOCATE (l, lazy, 1);
+    ELF_DYNAMIC_RELOCATE (l, lazy, consider_profiling);
 
-    if (_dl_profile_map == l)
+    if (_dl_profile != NULL)
       {
 	/* Allocate the array which will contain the already found
 	   relocations.  */
diff --git a/elf/dl-support.c b/elf/dl-support.c
index 9012a0c2a6..85f656c2fd 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -58,6 +58,9 @@ struct link_map *_dl_profile_map;
 /* Names of shared object for which the RPATHs should be ignored.  */
 const char *_dl_inhibit_rpath;
 
+/* This is the address of the last stack address ever used.  */
+void *__libc_stack_end;
+
 
 static void non_dynamic_init (void) __attribute__ ((unused));
 
diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h
index aedee20700..9d7ae3d3fa 100644
--- a/elf/dynamic-link.h
+++ b/elf/dynamic-link.h
@@ -1,5 +1,5 @@
 /* Inline functions for dynamic linking.
-   Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1995, 1996, 1997, 1998 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
@@ -161,10 +161,8 @@ elf_get_dynamic_info (ElfW(Dyn) *dyn,
    to inline functions containing inlines themselves.  */
 #define ELF_DYNAMIC_RELOCATE(map, lazy, consider_profile) \
   do {									      \
-    int profile = (consider_profile && _dl_profile != NULL		      \
-		   && _dl_name_match_p (_dl_profile, (map)));		      \
-    int edr_lazy = elf_machine_runtime_setup ((map), (lazy) || profile,	      \
-					      profile);			      \
+    int edr_lazy = elf_machine_runtime_setup ((map), (lazy),		      \
+					      (consider_profile));	      \
     ELF_DYNAMIC_DO_REL ((map), edr_lazy);				      \
     ELF_DYNAMIC_DO_RELA ((map), edr_lazy);				      \
   } while (0)
diff --git a/elf/elf.h b/elf/elf.h
index fcc8a5384a..80f10d6472 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -1,5 +1,5 @@
 /* This file defines standard ELF types, structures, and macros.
-   Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ian Lance Taylor <ian@cygnus.com>.
 
@@ -21,13 +21,13 @@
 #ifndef _ELF_H
 #define	_ELF_H 1
 
-#include <sys/cdefs.h>
+#include <features.h>
 
 __BEGIN_DECLS
 
 /* Standard ELF types.  */
 
-#include <inttypes.h>
+#include <stdint.h>
 
 /* Type for a 16-bit quantity.  */
 typedef uint16_t Elf32_Half;
diff --git a/elf/ldsodefs.h b/elf/ldsodefs.h
index a2bfc0b210..45c2a5ec64 100644
--- a/elf/ldsodefs.h
+++ b/elf/ldsodefs.h
@@ -363,7 +363,8 @@ extern struct link_map *_dl_new_object (char *realname, const char *libname,
    If LAZY is nonzero, don't relocate its PLT.  */
 extern void _dl_relocate_object (struct link_map *map,
 				 struct link_map *scope[],
-				 int lazy) internal_function;
+				 int lazy, int consider_profiling)
+     internal_function;
 
 /* Check the version dependencies of all objects available through
    MAP.  If VERBOSE print some more diagnostics.  */
@@ -406,8 +407,7 @@ extern void _dl_start_profile (struct link_map *map, const char *output_dir)
      internal_function;
 
 /* The actual functions used to keep book on the calls.  */
-extern void _dl_mcount (ElfW(Addr) frompc, ElfW(Addr) selfpc)
-     internal_function;
+extern void _dl_mcount (ElfW(Addr) frompc, ElfW(Addr) selfpc);
 
 
 /* Show the members of the auxiliary array passed up from the kernel.  */
diff --git a/elf/rtld.c b/elf/rtld.c
index fe676f7005..58f9da8ef8 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -93,6 +93,9 @@ const char *_dl_inhibit_rpath;		/* RPATH values which should be
    never be called.  */
 int _dl_starting_up;
 
+/* This variable contains the lowest stack address ever used.  */
+void *__libc_stack_end;
+
 static void dl_main (const ElfW(Phdr) *phdr,
 		     ElfW(Half) phent,
 		     ElfW(Addr) *user_entry);
@@ -201,7 +204,7 @@ relocate_doit (void *a)
   struct relocate_args *args = (struct relocate_args *) a;
 
   _dl_relocate_object (args->l, _dl_object_relocation_scope (args->l),
-		       args->lazy);
+		       args->lazy, 0);
 }
 
 static void
@@ -852,6 +855,11 @@ of this helper program; chances are you did not intend to run this program.\n\
        know that because it is self-contained).  */
 
     struct link_map *l;
+    int consider_profiling = _dl_profile != NULL;
+
+    /* If we are profiling we also must do lazy reloaction.  */
+    lazy |= consider_profiling;
+
     l = _dl_loaded;
     while (l->l_next)
       l = l->l_next;
@@ -859,7 +867,8 @@ of this helper program; chances are you did not intend to run this program.\n\
       {
 	if (l != &_dl_rtld_map)
 	  {
-	    _dl_relocate_object (l, _dl_object_relocation_scope (l), lazy);
+	    _dl_relocate_object (l, _dl_object_relocation_scope (l), lazy,
+				 consider_profiling);
 	    *_dl_global_scope_end = NULL;
 	  }
 	l = l->l_prev;
@@ -875,7 +884,7 @@ of this helper program; chances are you did not intend to run this program.\n\
     if (_dl_rtld_map.l_opencount > 0)
       /* There was an explicit ref to the dynamic linker as a shared lib.
 	 Re-relocate ourselves with user-controlled symbol definitions.  */
-      _dl_relocate_object (&_dl_rtld_map, &_dl_default_scope[2], 0);
+      _dl_relocate_object (&_dl_rtld_map, &_dl_default_scope[2], 0, 0);
   }
 
   {
diff --git a/elf/sprof.c b/elf/sprof.c
index 95e96646d1..477d95a283 100644
--- a/elf/sprof.c
+++ b/elf/sprof.c
@@ -68,15 +68,15 @@ extern int __profile_frequency __P ((void));
 static void print_version (FILE *stream, struct argp_state *state);
 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
 
-#define OPT_COUNT_TOTAL	1
-#define OPT_TEST 2
+#define OPT_TEST	1
 
 /* Definitions of arguments for argp functions.  */
 static const struct argp_option options[] =
 {
   { NULL, 0, NULL, 0, N_("Output selection:") },
-  { "count-total", OPT_COUNT_TOTAL, NULL, 0,
-    N_("print number of invocations for each function") },
+  { "flat-profile", 'p', NULL, 0,
+    N_("generate flat profile with counts and ticks") },
+
   { "test", OPT_TEST, NULL, OPTION_HIDDEN, NULL },
   { NULL, 0, NULL, 0, NULL }
 };
@@ -101,7 +101,9 @@ static struct argp argp =
 static enum
 {
   NONE = 0,
-  COUNT_TOTAL
+  FLAT_MODE = 1 << 0,
+
+  DEFAULT_MODE = FLAT_MODE
 } mode;
 
 /* If nonzero the total number of invocations of a function is emitted.  */
@@ -135,6 +137,7 @@ struct known_symbol
   size_t size;
 
   uintmax_t ticks;
+  uintmax_t calls;
 };
 
 
@@ -173,6 +176,7 @@ struct profdata
   off_t size;
 
   char *hist;
+  struct gmon_hist_hdr *hist_hdr;
   uint16_t *kcount;
   uint32_t narcs;		/* Number of arcs in toset.  */
   struct here_cg_arc_record *data;
@@ -192,7 +196,9 @@ static void unload_shobj (struct shobj *shobj);
 static struct profdata *load_profdata (const char *name, struct shobj *shobj);
 static void unload_profdata (struct profdata *profdata);
 static void count_total_ticks (struct shobj *shobj, struct profdata *profdata);
+static void count_calls (struct shobj *shobj, struct profdata *profdata);
 static void read_symbols (struct shobj *shobj);
+static void generate_flat_profile (struct profdata *profdata);
 
 
 int
@@ -266,26 +272,19 @@ no filename for profiling data given and shared object `%s' has no soname"),
 
   read_symbols (shobj_handle);
 
+  /* Count the ticks.  */
+  count_total_ticks (shobj_handle, profdata_handle);
+
+  /* Count the calls.  */
+  count_calls (shobj_handle, profdata_handle);
+
+  /* If no mode is specified fall back to the default mode.  */
+  if (mode == NONE)
+    mode = DEFAULT_MODE;
+
   /* Do some work.  */
-  switch (mode)
-    {
-    case COUNT_TOTAL:
-      count_total_ticks (shobj_handle, profdata_handle);
-      {
-	size_t n;
-	for (n = 0; n < symidx; ++n)
-	  if (sortsym[n]->ticks != 0)
-	    printf ("Name: %-30s, Ticks: %" PRIdMAX "\n", sortsym[n]->name,
-		    sortsym[n]->ticks);
-	printf ("Total ticks: %" PRIdMAX "\n", total_ticks);
-      }
-      break;
-    case NONE:
-      /* Do nothing.  */
-      break;
-    default:
-      assert (! "Internal error");
-    }
+  if (mode & FLAT_MODE)
+    generate_flat_profile (profdata_handle);
 
   /* Free the resources.  */
   unload_shobj (shobj_handle);
@@ -301,9 +300,6 @@ parse_opt (int key, char *arg, struct argp_state *state)
 {
   switch (key)
     {
-    case OPT_COUNT_TOTAL:
-      mode = COUNT_TOTAL;
-      break;
     case OPT_TEST:
       do_test = 1;
       break;
@@ -689,6 +685,8 @@ load_profdata (const char *name, struct shobj *shobj)
 
   /* Pointer to data after the header.  */
   result->hist = (char *) ((struct gmon_hdr *) addr + 1);
+  result->hist_hdr = (struct gmon_hist_hdr *) ((char *) result->hist
+					       + sizeof (uint32_t));
   result->kcount = (uint16_t *) ((char *) result->hist + sizeof (uint32_t)
 				 + sizeof (struct gmon_hist_hdr));
 
@@ -709,7 +707,7 @@ load_profdata (const char *name, struct shobj *shobj)
   *(char **) hist_hdr.high_pc = (char *) shobj->highpc - shobj->map->l_addr;
   if (do_test)
     printf ("low_pc = %p\nhigh_pc = %p\n",
-	    hist_hdr.low_pc, hist_hdr.high_pc);
+	    *(char **) hist_hdr.low_pc, *(char **) hist_hdr.high_pc);
   *(int32_t *) hist_hdr.hist_size = shobj->kcountsize / sizeof (HISTCOUNTER);
   *(int32_t *) hist_hdr.prof_rate = __profile_frequency ();
   strncpy (hist_hdr.dimen, "seconds", sizeof (hist_hdr.dimen));
@@ -718,7 +716,7 @@ load_profdata (const char *name, struct shobj *shobj)
   /* Test whether the header of the profiling data is ok.  */
   if (memcmp (addr, &gmon_hdr, sizeof (struct gmon_hdr)) != 0
       || *(uint32_t *) result->hist != GMON_TAG_TIME_HIST
-      || memcmp (result->hist + sizeof (uint32_t), &hist_hdr,
+      || memcmp (result->hist_hdr, &hist_hdr,
 		 sizeof (struct gmon_hist_hdr)) != 0
       || narcsp[-1] != GMON_TAG_CG_ARC)
     {
@@ -802,6 +800,49 @@ count_total_ticks (struct shobj *shobj, struct profdata *profdata)
 }
 
 
+static struct known_symbol *
+find_symbol (uintptr_t addr)
+{
+  size_t sidx = 0;
+
+  while (sidx < symidx)
+    {
+      uintptr_t start = sortsym[sidx]->addr;
+      uintptr_t end = start + sortsym[sidx]->size;
+
+      if (addr >= start && addr < end)
+	return sortsym[sidx];
+
+      if (addr < start)
+	break;
+
+      ++sidx;
+    }
+
+  return NULL;
+}
+
+
+static void
+count_calls (struct shobj *shobj, struct profdata *profdata)
+{
+  struct here_cg_arc_record *data = profdata->data;
+  uint32_t narcs = profdata->narcs;
+  uint32_t cnt;
+
+  for (cnt = 0; cnt < narcs; ++cnt)
+    {
+      uintptr_t here = data[cnt].self_pc;
+      struct known_symbol *symbol;
+
+      /* Find the symbol for this address.  */
+      symbol = find_symbol (here);
+      if (symbol != NULL)
+	symbol->calls += data[cnt].count;
+    }
+}
+
+
 static int
 symorder (const void *o1, const void *o2)
 {
@@ -843,6 +884,7 @@ read_symbols (struct shobj *shobj)
 	     || ELFW(ST_TYPE) (sym->st_info) == STT_NOTYPE)
 	    && sym->st_size != 0)
 	  {
+	    struct known_symbol **existp;
 	    struct known_symbol *newsym
 	      = (struct known_symbol *) obstack_alloc (&shobj->ob_sym,
 						       sizeof (*newsym));
@@ -853,9 +895,25 @@ read_symbols (struct shobj *shobj)
 	    newsym->addr = sym->st_value;
 	    newsym->size = sym->st_size;
 	    newsym->ticks = 0;
-
-	    tsearch (newsym, &symroot, symorder);
-	    ++n;
+	    newsym->calls = 0;
+
+	    existp = tfind (newsym, &symroot, symorder);
+	    if (existp == NULL)
+	      {
+		/* New function.  */
+		tsearch (newsym, &symroot, symorder);
+		++n;
+	      }
+	    else
+	      {
+		/* The function is already defined.  See whether we have
+		   a better name here.  */
+		if ((*existp)->name[0] == '_' && newsym->name[0] != '_')
+		  *existp = newsym;
+		else
+		  /* We don't need the allocated memory.  */
+		  obstack_free (&shobj->ob_sym, newsym);
+	      }
 	  }
     }
   else
@@ -872,11 +930,12 @@ read_symbols (struct shobj *shobj)
 	 dynamic symbol table!!  */
       while ((void *) symtab < (void *) strtab)
 	{
-	  if (/*(ELFW(ST_TYPE)(symtab->st_info) == STT_FUNC
-		|| ELFW(ST_TYPE)(symtab->st_info) == STT_NOTYPE)
-		&&*/ symtab->st_size != 0)
+	  if ((ELFW(ST_TYPE)(symtab->st_info) == STT_FUNC
+	       || ELFW(ST_TYPE)(symtab->st_info) == STT_NOTYPE)
+	      && symtab->st_size != 0)
 	    {
 	      struct known_symbol *newsym;
+	      struct known_symbol **existp;
 
 	      newsym =
 		(struct known_symbol *) obstack_alloc (&shobj->ob_sym,
@@ -889,8 +948,23 @@ read_symbols (struct shobj *shobj)
 	      newsym->size = symtab->st_size;
 	      newsym->ticks = 0;
 
-	      tsearch (newsym, &symroot, symorder);
-	      ++n;
+	      existp = tfind (newsym, &symroot, symorder);
+	      if (existp == NULL)
+		{
+		  /* New function.  */
+		  tsearch (newsym, &symroot, symorder);
+		  ++n;
+		}
+	      else
+		{
+		  /* The function is already defined.  See whether we have
+		     a better name here.  */
+		  if ((*existp)->name[0] == '_' && newsym->name[0] != '_')
+		    *existp = newsym;
+		  else
+		    /* We don't need the allocated memory.  */
+		    obstack_free (&shobj->ob_sym, newsym);
+		}
 	    }
 	}
 
@@ -903,3 +977,75 @@ read_symbols (struct shobj *shobj)
 
   twalk (symroot, printsym);
 }
+
+
+static int
+countorder (const void *p1, const void *p2)
+{
+  struct known_symbol *s1 = (struct known_symbol *) p1;
+  struct known_symbol *s2 = (struct known_symbol *) p2;
+
+  if (s1->ticks != s2->ticks)
+    return (int) (s2->ticks - s1->ticks);
+
+  if (s1->calls != s2->calls)
+    return (int) (s2->calls - s1->calls);
+
+  return strcmp (s1->name, s2->name);
+}
+
+
+static double tick_unit;
+static uintmax_t cumu_ticks;
+
+static void
+printflat (const void *node, VISIT value, int level)
+{
+  if (value == leaf || value == postorder)
+    {
+      struct known_symbol *s = *(struct known_symbol **) node;
+
+      cumu_ticks += s->ticks;
+
+      printf ("%6.2f%10.2f%9.2f%9" PRIdMAX "%9.2f%9.2f  %s\n",
+	      total_ticks ? (100.0 * s->ticks) / total_ticks : 0.0,
+	      tick_unit * cumu_ticks,
+	      tick_unit * s->ticks,
+	      s->calls,
+	      s->calls ? (s->ticks * 1000000) * tick_unit / s->calls : 0,
+	      0.0,	/* FIXME: don't know about called functions.  */
+	      s->name);
+    }
+}
+
+
+/* ARGUSED */
+static void
+freenoop (void *p)
+{
+}
+
+
+static void
+generate_flat_profile (struct profdata *profdata)
+{
+  size_t n;
+  void *data = NULL;
+
+  tick_unit = 1.0 / *(uint32_t *) profdata->hist_hdr->prof_rate;
+
+  printf ("Flat profile:\n\n"
+	  "Each sample counts as %g %s.\n",
+	  tick_unit, profdata->hist_hdr->dimen);
+  fputs ("  %   cumulative   self              self     total\n"
+	 " time   seconds   seconds    calls  us/call  us/call  name\n",
+	 stdout);
+
+  for (n = 0; n < symidx; ++n)
+    if (sortsym[n]->calls != 0 || sortsym[n]->ticks != 0)
+      tsearch (sortsym[n], &data, countorder);
+
+  twalk (data, printflat);
+
+  tdestroy (data, freenoop);
+}
diff --git a/libc.map b/libc.map
index 91aa3bc0f1..a7a1b049dd 100644
--- a/libc.map
+++ b/libc.map
@@ -474,6 +474,7 @@ GLIBC_2.1 {
     # global variables
     _IO_2_1_stdin_; _IO_2_1_stdout_; _IO_2_1_stderr_;
     __gconv_alias_db; __gconv_nmodules; __gconv_modules_db;
+    _dl_profile;
 
     # This is for ix86 only.
     _fp_hw;
@@ -489,6 +490,7 @@ GLIBC_2.1 {
     __syscall_rt_sigqueueinfo;
     __xstat64; __fxstat64; __lxstat64;
     __pread64; __pwrite64;
+    __backtrace; __backtracesyms;
 
     # helper functions
     __libc_current_sigrtmin; __libc_current_sigrtmax; __libc_allocate_rtsig;
@@ -533,6 +535,9 @@ GLIBC_2.1 {
 
     authdes_create; authdes_getucred; authdes_pk_create;
 
+    # b*
+    backtrace; backtracesyms;
+
     # c*
     capget; capset; cbc_crypt; creat64;
 
diff --git a/libio/fgetc.c b/libio/fgetc.c
index 174e60fa3f..094c5fe62f 100644
--- a/libio/fgetc.c
+++ b/libio/fgetc.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1995, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1995, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -35,6 +35,7 @@ fgetc (fp)
   _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, fp);
   _IO_flockfile (fp);
   result = _IO_getc_unlocked (fp);
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   return result;
 }
diff --git a/libio/fileops.c b/libio/fileops.c
index e5ffb245aa..1219abea5d 100644
--- a/libio/fileops.c
+++ b/libio/fileops.c
@@ -460,7 +460,8 @@ _IO_file_sync (fp)
     fp->_offset = _IO_pos_BAD;
   /* FIXME: Cleanup - can this be shared? */
   /*    setg(base(), ptr, ptr); */
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   return retval;
 }
 
diff --git a/libio/fputc.c b/libio/fputc.c
index 22cdfab9a8..3ec8b693e9 100644
--- a/libio/fputc.c
+++ b/libio/fputc.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -36,6 +36,7 @@ fputc (c, fp)
   _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, fp);
   _IO_flockfile (fp);
   result = _IO_putc_unlocked (c, fp);
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   return result;
 }
diff --git a/libio/freopen.c b/libio/freopen.c
index 0452e7e6bb..22f2434ecb 100644
--- a/libio/freopen.c
+++ b/libio/freopen.c
@@ -54,6 +54,7 @@ freopen (filename, mode, fp)
   else
 #endif
     result = _IO_freopen (filename, mode, fp);
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   return result;
 }
diff --git a/libio/freopen64.c b/libio/freopen64.c
index 78e994df46..c5216317a2 100644
--- a/libio/freopen64.c
+++ b/libio/freopen64.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -40,7 +40,8 @@ freopen64 (filename, mode, fp)
   _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, fp);
   _IO_flockfile (fp);
   result = _IO_freopen64 (filename, mode, fp);
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   return result;
 #else
   __set_errno (ENOSYS);
diff --git a/libio/fseek.c b/libio/fseek.c
index f2563d33f2..f9284574c7 100644
--- a/libio/fseek.c
+++ b/libio/fseek.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -37,6 +37,7 @@ fseek (fp, offset, whence)
   _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, fp);
   _IO_flockfile (fp);
   result = _IO_fseek (fp, offset, whence);
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   return result;
 }
diff --git a/libio/fseeko.c b/libio/fseeko.c
index 0ebdfa937e..1836047012 100644
--- a/libio/fseeko.c
+++ b/libio/fseeko.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -37,6 +37,7 @@ fseeko (fp, offset, whence)
   _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, fp);
   _IO_flockfile (fp);
   result = _IO_fseek (fp, offset, whence);
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   return result;
 }
diff --git a/libio/fseeko64.c b/libio/fseeko64.c
index 81c17b398c..55699ae938 100644
--- a/libio/fseeko64.c
+++ b/libio/fseeko64.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -39,7 +39,8 @@ fseeko64 (fp, offset, whence)
   _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, fp);
   _IO_flockfile (fp);
   result = _IO_fseek (fp, offset, whence);
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   return result;
 #else
   __set_errno (ENOSYS);
diff --git a/libio/ftello.c b/libio/ftello.c
index 7585eea9ec..662b954c54 100644
--- a/libio/ftello.c
+++ b/libio/ftello.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -37,7 +37,8 @@ ftello (fp)
   _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, fp);
   _IO_flockfile (fp);
   pos = _IO_seekoff (fp, 0, _IO_seek_cur, 0);
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   if (pos == _IO_pos_BAD)
     {
 #ifdef EIO
diff --git a/libio/ftello64.c b/libio/ftello64.c
index 886591dca9..96eeb184a4 100644
--- a/libio/ftello64.c
+++ b/libio/ftello64.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -38,7 +38,8 @@ ftello64 (fp)
   _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, fp);
   _IO_flockfile (fp);
   pos = _IO_seekoff (fp, 0, _IO_seek_cur, 0);
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   if (pos == _IO_pos_BAD)
     {
 #ifdef EIO
diff --git a/libio/getc.c b/libio/getc.c
index 1dc53b5ed6..81a4b52c83 100644
--- a/libio/getc.c
+++ b/libio/getc.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -37,7 +37,8 @@ _IO_getc (fp)
   _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, fp);
   _IO_flockfile (fp);
   result = _IO_getc_unlocked (fp);
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   return result;
 }
 
diff --git a/libio/getchar.c b/libio/getchar.c
index 93194b3912..fdc2ec3a87 100644
--- a/libio/getchar.c
+++ b/libio/getchar.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -33,8 +33,9 @@ getchar ()
 {
   int result;
   _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, stdin);
-  _IO_flockfile (stdin);
+  _IO_flockfile (_IO_stdin);
   result = _IO_getc_unlocked (stdin);
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (_IO_stdin);
+  _IO_cleanup_region_end (0);
   return result;
 }
diff --git a/libio/iofclose.c b/libio/iofclose.c
index 7100425556..f896e09b7e 100644
--- a/libio/iofclose.c
+++ b/libio/iofclose.c
@@ -43,7 +43,8 @@ _IO_new_fclose (fp)
   else
     status = fp->_flags & _IO_ERR_SEEN ? -1 : 0;
   _IO_FINISH (fp);
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   if (fp != _IO_stdin && fp != _IO_stdout && fp != _IO_stderr)
     {
       fp->_IO_file_flags = 0;
diff --git a/libio/iofflush.c b/libio/iofflush.c
index 540c99d535..724ff26ac8 100644
--- a/libio/iofflush.c
+++ b/libio/iofflush.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -39,7 +39,8 @@ _IO_fflush (fp)
       _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, fp);
       _IO_flockfile (fp);
       result = _IO_SYNC (fp) ? EOF : 0;
-      _IO_cleanup_region_end (1);
+      _IO_funlockfile (fp);
+      _IO_cleanup_region_end (0);
       return result;
     }
 }
diff --git a/libio/iofgetpos.c b/libio/iofgetpos.c
index 6afc323136..5fed6c3685 100644
--- a/libio/iofgetpos.c
+++ b/libio/iofgetpos.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -36,7 +36,8 @@ _IO_fgetpos (fp, posp)
   _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, fp);
   _IO_flockfile (fp);
   pos = _IO_seekoff (fp, 0, _IO_seek_cur, 0);
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   if (pos == _IO_pos_BAD)
     {
       /* ANSI explicitly requires setting errno to a positive value on
diff --git a/libio/iofgetpos64.c b/libio/iofgetpos64.c
index 0cb79d6619..8a7733bfb5 100644
--- a/libio/iofgetpos64.c
+++ b/libio/iofgetpos64.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -37,7 +37,8 @@ _IO_fgetpos64 (fp, posp)
   _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, fp);
   _IO_flockfile (fp);
   pos = _IO_seekoff (fp, 0, _IO_seek_cur, 0);
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   if (pos == _IO_pos_BAD)
     {
       /* ANSI explicitly requires setting errno to a positive value on
diff --git a/libio/iofgets.c b/libio/iofgets.c
index 91db09f342..d61fb81481 100644
--- a/libio/iofgets.c
+++ b/libio/iofgets.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -54,7 +54,8 @@ _IO_fgets (buf, n, fp)
       result = buf;
     }
   fp->_IO_file_flags |= old_error;
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   return result;
 }
 
diff --git a/libio/iofputs.c b/libio/iofputs.c
index 1a329bbe26..1805387303 100644
--- a/libio/iofputs.c
+++ b/libio/iofputs.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -40,7 +40,8 @@ _IO_fputs (str, fp)
     result = EOF;
   else
     result = 1;
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   return result;
 }
 
diff --git a/libio/iofread.c b/libio/iofread.c
index c83d2b638c..36640065d5 100644
--- a/libio/iofread.c
+++ b/libio/iofread.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1995, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1995, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -40,7 +40,8 @@ _IO_fread (buf, size, count, fp)
   _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, fp);
   _IO_flockfile (fp);
   bytes_read = _IO_sgetn (fp, (char *) buf, bytes_requested);
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   return bytes_requested == bytes_read ? count : bytes_read / size;
 }
 
diff --git a/libio/iofsetpos.c b/libio/iofsetpos.c
index a8d816f5a3..cbf77347e7 100644
--- a/libio/iofsetpos.c
+++ b/libio/iofsetpos.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1995, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1995, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -47,7 +47,8 @@ _IO_fsetpos (fp, posp)
     }
   else
     result = 0;
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   return result;
 }
 
diff --git a/libio/iofsetpos64.c b/libio/iofsetpos64.c
index 534e0cf3ca..13ce0fb3cb 100644
--- a/libio/iofsetpos64.c
+++ b/libio/iofsetpos64.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1995, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1995, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -48,7 +48,8 @@ _IO_fsetpos64 (fp, posp)
     }
   else
     result = 0;
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   return result;
 #else
   __set_errno (ENOSYS);
diff --git a/libio/ioftell.c b/libio/ioftell.c
index d8a1ce1d24..3a0e7a6bc3 100644
--- a/libio/ioftell.c
+++ b/libio/ioftell.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -36,7 +36,8 @@ _IO_ftell (fp)
   _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, fp);
   _IO_flockfile (fp);
   pos = _IO_seekoff (fp, 0, _IO_seek_cur, 0);
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   if (pos == _IO_pos_BAD)
     {
 #ifdef EIO
diff --git a/libio/iofwrite.c b/libio/iofwrite.c
index 5bc525ffc7..0f82797ecf 100644
--- a/libio/iofwrite.c
+++ b/libio/iofwrite.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -40,7 +40,8 @@ _IO_fwrite (buf, size, count, fp)
   _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, fp);
   _IO_flockfile (fp);
   written = _IO_sputn (fp, (const char *) buf, request);
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   /* Many traditional implementations return 0 if size==0 && count > 0,
      but ANSI requires us to return count in this case. */
   if (written == request)
diff --git a/libio/iogetdelim.c b/libio/iogetdelim.c
index 50918b3e8d..56524d6840 100644
--- a/libio/iogetdelim.c
+++ b/libio/iogetdelim.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1994, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -115,7 +115,8 @@ _IO_getdelim (lineptr, n, delimiter, fp)
   result = cur_len;
 
 unlock_return:
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   return result;
 }
 
diff --git a/libio/iogets.c b/libio/iogets.c
index a61699d694..b36d29ba6c 100644
--- a/libio/iogets.c
+++ b/libio/iogets.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -65,7 +65,8 @@ _IO_gets (buf)
   buf[count] = 0;
   retval = buf;
 unlock_return:
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (_IO_stdin);
+  _IO_cleanup_region_end (0);
   return retval;
 }
 
diff --git a/libio/ioputs.c b/libio/ioputs.c
index ab5e6aaa4c..9ed8fe60a2 100644
--- a/libio/ioputs.c
+++ b/libio/ioputs.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -40,7 +40,8 @@ _IO_puts (str)
     result = len + 1;
   else
     result = EOF;
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (_IO_stdout);
+  _IO_cleanup_region_end (0);
   return result;
 }
 
diff --git a/libio/ioseekoff.c b/libio/ioseekoff.c
index 13086ee912..b83e1ad797 100644
--- a/libio/ioseekoff.c
+++ b/libio/ioseekoff.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -49,6 +49,7 @@ _IO_seekoff (fp, offset, dir, mode)
     }
   retval = _IO_SEEKOFF (fp, offset, dir, mode);
 
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   return retval;
 }
diff --git a/libio/ioseekpos.c b/libio/ioseekpos.c
index 5b59ed7d99..c81c333676 100644
--- a/libio/ioseekpos.c
+++ b/libio/ioseekpos.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -43,6 +43,7 @@ _IO_seekpos (fp, pos, mode)
     _IO_free_backup_area (fp);
   retval = _IO_SEEKPOS (fp, pos, mode);
 
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   return retval;
 }
diff --git a/libio/iosetbuffer.c b/libio/iosetbuffer.c
index f140a9ad04..d615da570c 100644
--- a/libio/iosetbuffer.c
+++ b/libio/iosetbuffer.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -38,7 +38,8 @@ _IO_setbuffer (fp, buf, size)
   if (!buf)
     size = 0;
   (void) _IO_SETBUF (fp, buf, size);
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
 }
 
 #ifdef weak_alias
diff --git a/libio/iosetvbuf.c b/libio/iosetvbuf.c
index 65eeea51a6..02f4eefb5e 100644
--- a/libio/iosetvbuf.c
+++ b/libio/iosetvbuf.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -91,7 +91,8 @@ _IO_setvbuf (fp, buf, mode, size)
     }
   result = _IO_SETBUF (fp, buf, size) == NULL ? EOF : 0;
 unlock_return:
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   return result;
 }
 
diff --git a/libio/ioungetc.c b/libio/ioungetc.c
index 07f38e747b..abc27ffb33 100644
--- a/libio/ioungetc.c
+++ b/libio/ioungetc.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -37,7 +37,8 @@ _IO_ungetc (c, fp)
   _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, fp);
   _IO_flockfile (fp);
   result = _IO_sputbackc (fp, (unsigned char) c);
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   return result;
 }
 
diff --git a/libio/iovsprintf.c b/libio/iovsprintf.c
index 34919588ce..a1ece2da47 100644
--- a/libio/iovsprintf.c
+++ b/libio/iovsprintf.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -44,11 +44,8 @@ _IO_vsprintf (string, format, args)
   _IO_init (&sf._sbf._f, 0);
   _IO_JUMPS (&sf._sbf._f) = &_IO_str_jumps;
   _IO_str_init_static (&sf._sbf._f, string, -1, string);
-  _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, &sf);
-  _IO_flockfile (&sf._sbf._f);
   ret = _IO_vfprintf (&sf._sbf._f, format, args);
   _IO_putc_unlocked ('\0', &sf._sbf._f);
-  _IO_cleanup_region_end (1);
   return ret;
 }
 
diff --git a/libio/iovsscanf.c b/libio/iovsscanf.c
index 1917d63e6d..923e8290a4 100644
--- a/libio/iovsscanf.c
+++ b/libio/iovsscanf.c
@@ -41,10 +41,7 @@ _IO_vsscanf (string, format, args)
   _IO_init (&sf._sbf._f, 0);
   _IO_JUMPS (&sf._sbf._f) = &_IO_str_jumps;
   _IO_str_init_static (&sf._sbf._f, (char*)string, 0, NULL);
-  _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, &sf);
-  _IO_flockfile (&sf._sbf._f);
   ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL);
-  _IO_cleanup_region_end (1);
   return ret;
 }
 
diff --git a/libio/oldfileops.c b/libio/oldfileops.c
index 7cf4fdf22c..251dc78c6c 100644
--- a/libio/oldfileops.c
+++ b/libio/oldfileops.c
@@ -426,7 +426,8 @@ _IO_old_file_sync (fp)
     fp->_old_offset = _IO_pos_BAD;
   /* FIXME: Cleanup - can this be shared? */
   /*    setg(base(), ptr, ptr); */
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   return retval;
 }
 
diff --git a/libio/oldiofclose.c b/libio/oldiofclose.c
index 5f3e1020d8..e256d57ac2 100644
--- a/libio/oldiofclose.c
+++ b/libio/oldiofclose.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1995, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1995, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -44,7 +44,8 @@ _IO_old_fclose (fp)
   else
     status = fp->_flags & _IO_ERR_SEEN ? -1 : 0;
   _IO_FINISH (fp);
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   if (fp != _IO_stdin && fp != _IO_stdout && fp != _IO_stderr)
     {
       fp->_IO_file_flags = 0;
diff --git a/libio/peekc.c b/libio/peekc.c
index 0b3b5140c2..8ad274e558 100644
--- a/libio/peekc.c
+++ b/libio/peekc.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -37,6 +37,7 @@ _IO_peekc_locked (fp)
   _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, fp);
   _IO_flockfile (fp);
   result = _IO_peekc_unlocked (fp);
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   return result;
 }
diff --git a/libio/putc.c b/libio/putc.c
index 3c35c365f0..72cd2a1a05 100644
--- a/libio/putc.c
+++ b/libio/putc.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1995, 1996, 1997, 1998 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
@@ -31,7 +31,8 @@ _IO_putc (c, fp)
   _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, fp);
   _IO_flockfile (fp);
   result = _IO_putc_unlocked (c, fp);
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
   return result;
 }
 
diff --git a/libio/putchar.c b/libio/putchar.c
index 1e1dd13762..143796d20c 100644
--- a/libio/putchar.c
+++ b/libio/putchar.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1995, 1996, 1997, 1998 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
@@ -30,6 +30,7 @@ putchar (c)
 			       _IO_stdout);
   _IO_flockfile (_IO_stdout);
   result = _IO_putc_unlocked (c, _IO_stdout);
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (_IO_stdout);
+  _IO_cleanup_region_end (0);
   return result;
 }
diff --git a/libio/rewind.c b/libio/rewind.c
index bce27575fd..fb6afbc77a 100644
--- a/libio/rewind.c
+++ b/libio/rewind.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU IO Library.
 
    This library is free software; you can redistribute it and/or
@@ -34,5 +34,6 @@ rewind (fp)
   _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, fp);
   _IO_flockfile (fp);
   _IO_rewind (fp);
-  _IO_cleanup_region_end (1);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
 }
diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog
index 4b4de6a250..c89ef1e515 100644
--- a/linuxthreads/ChangeLog
+++ b/linuxthreads/ChangeLog
@@ -1,3 +1,7 @@
+1998-06-07 13:47  Ulrich Drepper  <drepper@cygnus.com>
+
+	* sysdeps/pthread/bits/libc-lock.h: Optimize cleanup handlers a bit.
+
 1998-06-03  Andreas Jaeger  <aj@arthur.rhein-neckar.de>
 
 	* attr.c: Correct typo.
diff --git a/linuxthreads/sysdeps/pthread/bits/libc-lock.h b/linuxthreads/sysdeps/pthread/bits/libc-lock.h
index 530d48c6da..ed64cbfa0f 100644
--- a/linuxthreads/sysdeps/pthread/bits/libc-lock.h
+++ b/linuxthreads/sysdeps/pthread/bits/libc-lock.h
@@ -1,5 +1,5 @@
 /* libc-internal interface for mutex locks.  LinuxThreads version.
-   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 1998 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
@@ -119,13 +119,14 @@ typedef pthread_key_t __libc_key_t;
 /* Start critical region with cleanup.  */
 #define __libc_cleanup_region_start(FCT, ARG) \
   { struct _pthread_cleanup_buffer _buffer;				      \
-    if (_pthread_cleanup_push_defer != NULL) {				      \
+    int _avail = _pthread_cleanup_push_defer != NULL;			      \
+    if (_avail) {							      \
       _pthread_cleanup_push_defer (&_buffer, (FCT), (ARG));		      \
     }
 
 /* End critical region with cleanup.  */
 #define __libc_cleanup_region_end(DOIT) \
-    if (_pthread_cleanup_push_defer != NULL) {				      \
+    if (_avail) {							      \
       _pthread_cleanup_pop_restore (&_buffer, (DOIT));			      \
     }									      \
   }
diff --git a/malloc/mtrace.c b/malloc/mtrace.c
index f3c1387274..64fb62a131 100644
--- a/malloc/mtrace.c
+++ b/malloc/mtrace.c
@@ -146,7 +146,7 @@ tr_mallochook (size, caller)
 
   tr_where (caller);
   /* We could be printing a NULL here; that's OK.  */
-  fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long)size);
+  fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
 
   if (hdr == mallwatch)
     tr_break ();
@@ -184,11 +184,12 @@ tr_reallochook (ptr, size, caller)
   tr_where (caller);
   if (hdr == NULL)
     /* Failed realloc.  */
-    fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long)size);
+    fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
   else if (ptr == NULL)
-    fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long)size);
+    fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
   else
-    fprintf (mallstream, "< %p\n> %p %#lx\n", ptr, hdr, (unsigned long)size);
+    fprintf (mallstream, "< %p\n> %p %#lx\n", ptr, hdr,
+	     (unsigned long int) size);
 
   if (hdr == mallwatch)
     tr_break ();
diff --git a/misc/mntent.h b/misc/mntent.h
index fc93022cd4..1d079a3e52 100644
--- a/misc/mntent.h
+++ b/misc/mntent.h
@@ -1,5 +1,5 @@
 /* Utilities for reading/writing fstab, mtab, etc.
-   Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1995, 1996, 1997, 1998 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
@@ -53,10 +53,10 @@ __BEGIN_DECLS
 /* Structure describing a mount table entry.  */
 struct mntent
   {
-    char *mnt_fsname;		/* Device or server for filesystem.  */
-    char *mnt_dir;		/* Directory mounted on.  */
-    char *mnt_type;		/* Type of filesystem: ufs, nfs, etc.  */
-    char *mnt_opts;		/* Comma-separated options for fs.  */
+    const char *mnt_fsname;	/* Device or server for filesystem.  */
+    const char *mnt_dir;	/* Directory mounted on.  */
+    const char *mnt_type;	/* Type of filesystem: ufs, nfs, etc.  */
+    const char *mnt_opts;	/* Comma-separated options for fs.  */
     int mnt_freq;		/* Dump frequency (in days).  */
     int mnt_passno;		/* Pass number for `fsck'.  */
   };
diff --git a/nis/nis_print.c b/nis/nis_print.c
index 5aa43c340f..01a2d9dcec 100644
--- a/nis/nis_print.c
+++ b/nis/nis_print.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997 Free Software Foundation, Inc.
+/* Copyright (c) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
 
@@ -150,7 +150,7 @@ nis_print_rights (const u_long access)
 
       acc >>= 8;
     }
-  printf ("%s", result);
+  fputs (result, stdout);
 }
 
 void
@@ -176,20 +176,19 @@ nis_print_directory (const directory_obj *dir)
 	  fputs (_("None.\n"), stdout);
 	  break;
 	case NIS_PK_DH:
-	  fprintf (stdout, _("Diffie-Hellmann (%d bits)\n"),
-		   (sptr->pkey.n_len - 1) * 4);
+	  printf (_("Diffie-Hellmann (%d bits)\n"),
+		  (sptr->pkey.n_len - 1) * 4);
 	  /* sptr->pkey.n_len counts the last 0, too */
 	  break;
 	case NIS_PK_RSA:
-	  fprintf (stdout, _("RSA (%d bits)\n"),
-		   (sptr->pkey.n_len - 1) * 4);
+	  printf (_("RSA (%d bits)\n"), (sptr->pkey.n_len - 1) * 4);
 	  break;
 	case NIS_PK_KERB:
 	  fputs (_("Kerberos.\n"), stdout);
 	  break;
 	default:
-	  fprintf (stdout, _("Unknown (type = %d, bits = %d)\n"),
-		   sptr->key_type, (sptr->pkey.n_len - 1) * 4);
+	  printf (_("Unknown (type = %d, bits = %d)\n"), sptr->key_type,
+		  (sptr->pkey.n_len - 1) * 4);
 	  break;
 	}
 
@@ -214,7 +213,7 @@ nis_print_directory (const directory_obj *dir)
 	      if (ptr->uaddr != NULL && strlen (ptr->uaddr) > 0)
 		printf ("%s\n", ptr->uaddr);
 	      else
-		printf ("-\n");
+		fputs ("-\n", stdout);
 	      ptr++;
 	    }
 	}
@@ -233,7 +232,7 @@ nis_print_directory (const directory_obj *dir)
 	{
 	  nis_print_rights (ptr->oa_rights);
 	  printf (_("\tType         : %s\n"), nis_nstype2str (ptr->oa_otype));
-	  printf (_("\tAccess rights: "));
+	  fputs (_("\tAccess rights: "), stdout);
 	  nis_print_rights (ptr->oa_rights);
 	  fputs ("\n", stdout);
 	  ptr++;
diff --git a/signal/Makefile b/signal/Makefile
index cec0782df3..ee15a2c5f9 100644
--- a/signal/Makefile
+++ b/signal/Makefile
@@ -38,7 +38,7 @@ routines	:= signal raise killpg \
 
 tests		:= tst-signal
 
-distribute	:= sigsetops.h testrtsig.h
+distribute	:= sigsetops.h testrtsig.h sigset-cvt-mask.h
 
 
 include ../Rules
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
index 85558a1574..a40acb75d4 100644
--- a/stdio-common/vfprintf.c
+++ b/stdio-common/vfprintf.c
@@ -1472,7 +1472,12 @@ do_positional:
 
 all_done:
   /* Unlock the stream.  */
-  __libc_cleanup_region_end (1);
+#ifdef USE_IN_LIBIO
+  _IO_funlockfile (s);
+#else
+  __funlockfile (s);
+#endif
+  __libc_cleanup_region_end (0);
 
   return done;
 }
diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf.c
index 7666c87936..c1ff2690b7 100644
--- a/stdio-common/vfscanf.c
+++ b/stdio-common/vfscanf.c
@@ -100,7 +100,9 @@
 # define LOCK_STREAM(S)							      \
   __libc_cleanup_region_start ((void (*) (void *)) &_IO_funlockfile, (S));    \
   _IO_flockfile (S)
-# define UNLOCK_STREAM __libc_cleanup_region_end (1)
+# define UNLOCK_STREAM(S)						      \
+  _IO_funlockfile (S);							      \
+  __libc_cleanup_region_end (0)
 #else
 # define ungetc(c, s)	((void) (c != EOF && --read_in), ungetc (c, s))
 # define inchar()	(c == EOF ? EOF					      \
@@ -143,12 +145,14 @@
 # define flockfile(S) /* nothing */
 # define funlockfile(S) /* nothing */
 # define LOCK_STREAM(S)
-# define UNLOCK_STREAM
+# define UNLOCK_STREAM(S)
 #else
 # define LOCK_STREAM(S)							      \
   __libc_cleanup_region_start (&__funlockfile, (S));			      \
   __flockfile (S)
-# define UNLOCK_STREAM __libc_cleanup_region_end (1)
+# define UNLOCK_STREAM(S)						      \
+  __funlockfile (S);							      \
+  __libc_cleanup_region_end (0)
 #endif
 #endif
 
@@ -1216,7 +1220,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
     }
 
   /* Unlock stream.  */
-  UNLOCK_STREAM;
+  UNLOCK_STREAM (s);
 
   return done;
 }
diff --git a/sysdeps/generic/libc-start.c b/sysdeps/generic/libc-start.c
index 3225a7ce5d..1e07929e7e 100644
--- a/sysdeps/generic/libc-start.c
+++ b/sysdeps/generic/libc-start.c
@@ -25,11 +25,12 @@ extern void __libc_init_first (int argc, char **argv, char **envp);
 extern int _dl_starting_up;
 weak_extern (_dl_starting_up)
 extern int __libc_multiple_libcs;
+extern void *__libc_stack_end;
 
 int
 __libc_start_main (int (*main) (int, char **, char **), int argc,
 		   char **argv, void (*init) (void), void (*fini) (void),
-		   void (*rtld_fini) (void))
+		   void (*rtld_fini) (void), void *stack_end)
 {
 #ifndef PIC
   /* The next variable is only here to work around a bug in gcc <= 2.7.2.2.
@@ -38,6 +39,9 @@ __libc_start_main (int (*main) (int, char **, char **), int argc,
   int *dummy_addr = &_dl_starting_up;
 
   __libc_multiple_libcs = dummy_addr && !_dl_starting_up;
+
+  /* Store the lowest stack address.  */
+  __libc_stack_end = stack_end;
 #endif
 
   /* Set the global _environ variable correctly.  */
diff --git a/sysdeps/generic/sigset-cvt-mask.h b/sysdeps/generic/sigset-cvt-mask.h
new file mode 100644
index 0000000000..749ed5e613
--- /dev/null
+++ b/sysdeps/generic/sigset-cvt-mask.h
@@ -0,0 +1,24 @@
+/* Convert between lowlevel sigmask and libc representation of sigset_t.
+   Generic version.
+   Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Joe Keane <jgk@jgk.org>.
+
+   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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#define sigset_set_old_mask(set, mask) (*(set) = (unsigned long int) (mask))
+
+#define sigset_get_old_mask(set, mask) ((mask) = (unsigned int) *(set))
diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h
index 2f936e3d1e..542c35f190 100644
--- a/sysdeps/i386/dl-machine.h
+++ b/sysdeps/i386/dl-machine.h
@@ -105,8 +105,11 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
       if (profile)
 	{
 	  got[2] = (Elf32_Addr) &_dl_runtime_profile;
-	  /* Say that we really want profiling and the timers are started.  */
-	  _dl_profile_map = l;
+
+	  if (_dl_name_match_p (_dl_profile, l))
+	    /* This is the object we are looking for.  Say that we really
+	       want profiling and the timers are started.  */
+	    _dl_profile_map = l;
 	}
       else
 	/* This function will get called to fix up the GOT entry indicated by
@@ -209,6 +212,8 @@ _dl_start_user:\n\
 	call 0f\n\
 0:	popl %ebx\n\
 	addl $_GLOBAL_OFFSET_TABLE_+[.-0b], %ebx\n\
+	# Store the highest stack address\n\
+	movl %esp,__libc_stack_end@GOT(%ebx)\n\
 	# See if we were run as a command with the executable file\n\
 	# name as an extra leading argument.\n\
 	movl _dl_skip_args@GOT(%ebx), %eax\n\
diff --git a/sysdeps/i386/elf/start.S b/sysdeps/i386/elf/start.S
index 95f74ed647..019e749a6f 100644
--- a/sysdeps/i386/elf/start.S
+++ b/sysdeps/i386/elf/start.S
@@ -53,6 +53,11 @@ _start:
 	   boundary to avoid penalties from misaligned accesses.  Thanks
 	   to Edward Seidl <seidl@janed.com> for pointing this out.  */
 	andl $0xfffffff8, %esp
+
+	/* Provide the highest stack address to the user code (for stacks
+	   which grow downwards).  */
+	pushl %esp
+
 	pushl %edx		/* Push address of the shared library
 				   termination function.  */
 
diff --git a/sysdeps/posix/mkstemp.c b/sysdeps/posix/mkstemp.c
index f0db5d5d53..2c9c96bdcc 100644
--- a/sysdeps/posix/mkstemp.c
+++ b/sysdeps/posix/mkstemp.c
@@ -33,7 +33,7 @@ int
 mkstemp (template)
      char *template;
 {
-  static const char letters[]
+  static const char letters[62]
     = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
   static uint64_t value;
   struct timeval tv;
diff --git a/sysdeps/posix/sigvec.c b/sysdeps/posix/sigvec.c
index 12285fad66..cc4839d73f 100644
--- a/sysdeps/posix/sigvec.c
+++ b/sysdeps/posix/sigvec.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 92, 94, 95, 96, 97 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 92, 94, 95, 96, 97, 98 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,55 +20,20 @@
 #include <errno.h>
 #include <stddef.h>
 
+/* Include macros to convert between `sigset_t' and old-style mask. */
+#include "sigset-cvt-mask.h"
 
 /* We use a wrapper handler to support SV_RESETHAND.  */
-
-static __sighandler_t wrapped_handlers[NSIG];
-static sigset_t wrapped_masks[NSIG];
-
-static void wrapper_handler __P ((int sig));
-static inline int convert_mask __P ((sigset_t *set, const int mask));
-
-static void
-wrapper_handler (sig)
-     int sig;
+struct sigvec_wrapper_data
 {
-  int save;
-  struct sigaction act;
+  __sighandler_t sw_handler;
+  unsigned int sw_mask;
+};
 
-  act.sa_handler = SIG_DFL;
-  act.sa_mask = wrapped_masks[sig];
-  act.sa_flags = 0;
-  save = errno;
-  (void) __sigaction (sig, &act, (struct sigaction *) NULL);
-  __set_errno (save);
+static void sigvec_wrapper_handler __P ((int sig));
 
-  (*wrapped_handlers[sig]) (sig);
-}
+static struct sigvec_wrapper_data sigvec_wrapper_data[NSIG];
 
-static inline int
-convert_mask (set, mask)
-     sigset_t *set;
-     const int mask;
-{
-  register int sig;
-
-  if (sizeof (*set) == sizeof (mask))
-    *(int *) set = mask;
-  else if (sizeof (*set) == sizeof (unsigned long int))
-    *(unsigned long int *) set = (unsigned int) mask;
-  else
-    {
-      if (__sigemptyset (set) < 0)
-	return -1;
-
-      for (sig = 1; sig < NSIG && sig <= sizeof (mask) * 8; ++sig)
-	if ((mask & sigmask (sig)) && __sigaddset (set, sig) < 0)
-	  return -1;
-    }
-
-  return 0;
-}
 
 /* If VEC is non-NULL, set the handler for SIG to the `sv_handler' member
    of VEC.  The signals in `sv_mask' will be blocked while the handler runs.
@@ -91,25 +56,32 @@ __sigvec (sig, vec, ovec)
 	n = NULL;
       else
 	{
-	  n = &new;
-	  n->sa_handler = vec->sv_handler;
-	  if (convert_mask (&n->sa_mask, vec->sv_mask) < 0)
-	    return -1;
-	  n->sa_flags = 0;
-
-	  if (vec->sv_flags & SV_ONSTACK)
+	  __sighandler_t handler;
+	  unsigned int mask;
+	  unsigned int sv_flags;
+	  unsigned int sa_flags;
+
+	  handler = vec->sv_handler;
+	  mask = vec->sv_mask;
+	  sv_flags = vec->sv_flags;
+	  sa_flags = 0;
+	  if (sv_flags & SV_ONSTACK)
 	    {
 #ifdef SA_ONSTACK
-	      n->sa_flags |= SA_ONSTACK;
+	      sa_flags |= SA_ONSTACK;
 #else
 	      __set_errno (ENOSYS);
 	      return -1;
 #endif
 	    }
 #ifdef SA_RESTART
-	  if (!(vec->sv_flags & SV_INTERRUPT))
-	    n->sa_flags |= SA_RESTART;
+	  if (!(sv_flags & SV_INTERRUPT))
+	    sa_flags |= SA_RESTART;
 #endif
+	  n = &new;
+	  new.sa_handler = handler;
+	  sigset_set_old_mask (&new.sa_mask, mask);
+	  new.sa_flags = sa_flags;
 	}
 
       if (__sigaction (sig, n, &old) < 0)
@@ -117,12 +89,18 @@ __sigvec (sig, vec, ovec)
     }
   else
     {
+      __sighandler_t handler;
+      unsigned int mask;
+      struct sigvec_wrapper_data *data;
       struct sigaction wrapper;
 
-      wrapper.sa_handler = wrapper_handler;
-      wrapped_handlers[sig] = vec->sv_handler;
-      if (convert_mask (&wrapped_masks[sig], vec->sv_mask) < 0)
-	return -1;
+      handler = vec->sv_handler;
+      mask = (unsigned int)vec->sv_mask;
+      data = &sigvec_wrapper_data[sig];
+      wrapper.sa_handler = sigvec_wrapper_handler;
+      /* FIXME: should we set wrapper.sa_mask, wrapper.sa_flags??  */
+      data->sw_handler = handler;
+      data->sw_mask = mask;
 
       if (__sigaction (sig, &wrapper, &old) < 0)
 	return -1;
@@ -130,38 +108,58 @@ __sigvec (sig, vec, ovec)
 
   if (ovec != NULL)
     {
-      register int i;
-      int mask = 0;
-
-      if (sizeof (int) == sizeof (sigset_t))
-	mask = *(int *) &old.sa_mask;
-      else if (sizeof (unsigned long int) == sizeof (sigset_t))
-	mask = *(unsigned long int *) &old.sa_mask;
-      else
-	for (i = 1; i < NSIG && i <= sizeof (mask) * 8; ++i)
-	  if (__sigismember (&old.sa_mask, i))
-	    mask |= sigmask (i);
-
-      ovec->sv_mask = mask;
-      ovec->sv_flags = 0;
+      __sighandler_t handler;
+      unsigned int sv_flags;
+      unsigned int sa_flags;
+      unsigned int mask;
+
+      handler = old.sa_handler;
+      sv_flags = 0;
+      sa_flags = old.sa_flags;
+      if (handler == sigvec_wrapper_handler)
+	{
+	  handler = sigvec_wrapper_data[sig].sw_handler;
+	  /* should we use data->sw_mask?? */
+	  sv_flags |= SV_RESETHAND;
+	}
+      sigset_get_old_mask (&old.sa_mask, mask);
 #ifdef SA_ONSTACK
-      if (old.sa_flags & SA_ONSTACK)
-	ovec->sv_flags |= SV_ONSTACK;
+     if (sa_flags & SA_ONSTACK)
+	sv_flags |= SV_ONSTACK;
 #endif
 #ifdef SA_RESTART
-      if (!(old.sa_flags & SA_RESTART))
+     if (!(sa_flags & SA_RESTART))
 #endif
-	ovec->sv_flags |= SV_INTERRUPT;
-      if (old.sa_handler == wrapper_handler)
-	{
-	  ovec->sv_flags |= SV_RESETHAND;
-	  ovec->sv_handler = wrapped_handlers[sig];
-	}
-      else
-	ovec->sv_handler = old.sa_handler;
+	sv_flags |= SV_INTERRUPT;
+      ovec->sv_handler = handler;
+      ovec->sv_mask = (int)mask;
+      ovec->sv_flags = (int)sv_flags;
     }
 
   return 0;
 }
 
 weak_alias (__sigvec, sigvec)
+
+
+static void
+sigvec_wrapper_handler (sig)
+     int sig;
+{
+  struct sigvec_wrapper_data *data;
+  unsigned int mask;
+  struct sigaction act;
+  int save;
+  __sighandler_t handler;
+
+  data = &sigvec_wrapper_data[sig];
+  mask = data->sw_mask;
+  act.sa_handler = SIG_DFL;
+  sigset_set_old_mask (&act.sa_mask, mask);
+  act.sa_flags = 0;
+  save = errno;
+  handler = data->sw_handler;
+  (void) __sigaction (sig, &act, (struct sigaction *) NULL);
+  __set_errno (save);
+  (*handler) (sig);
+}
diff --git a/sysdeps/unix/sysv/linux/i386/clone.S b/sysdeps/unix/sysv/linux/i386/clone.S
index 88d0e27549..d654d98c7a 100644
--- a/sysdeps/unix/sysv/linux/i386/clone.S
+++ b/sysdeps/unix/sysv/linux/i386/clone.S
@@ -33,10 +33,10 @@ ENTRY(__clone)
 	movl	$-EINVAL,%eax
 	movl	4(%esp),%ecx		/* no NULL function pointers */
 	testl	%ecx,%ecx
-	jz	syscall_error
+	jz	SYSCALL_ERROR_LABEL
 	movl	8(%esp),%ecx		/* no NULL stack pointers */
 	testl	%ecx,%ecx
-	jz	syscall_error
+	jz	SYSCALL_ERROR_LABEL
 
 	/* Insert the argument onto the new stack.  */
 	subl	$8,%ecx
@@ -56,7 +56,7 @@ ENTRY(__clone)
 	popl	%ebx
 
 	test	%eax,%eax
-	jl	syscall_error
+	jl	SYSCALL_ERROR_LABEL
 	jz	thread_start
 
 L(pseudo_end):
diff --git a/sysdeps/unix/sysv/linux/i386/i686/sysdep.h b/sysdeps/unix/sysv/linux/i386/i686/sysdep.h
index 001f3fc4d7..3f1391f8a4 100644
--- a/sysdeps/unix/sysv/linux/i386/i686/sysdep.h
+++ b/sysdeps/unix/sysv/linux/i386/i686/sysdep.h
@@ -31,12 +31,10 @@
 /* Store (- %eax) into errno through the GOT.  */
 # ifdef _LIBC_REENTRANT
 #  define SYSCALL_ERROR_HANDLER						      \
-  .type syscall_error,@function;					      \
-0:movl (%esp),%ebx;							      \
+1:movl (%esp),%ebx;							      \
   ret;									      \
-syscall_error:								      \
-  pushl %ebx;								      \
-  call 0b;								      \
+0:pushl %ebx;								      \
+  call 1b;								      \
   addl $_GLOBAL_OFFSET_TABLE_, %ebx;					      \
   xorl %edx, %edx;							      \
   subl %eax, %edx;							      \
@@ -46,25 +44,22 @@ syscall_error:								      \
   popl %ebx;								      \
   movl %ecx, (%eax);							      \
   movl $-1, %eax;							      \
-  jmp L(pseudo_end);							      \
-  .size syscall_error,.-syscall_error;
+  jmp L(pseudo_end);
 /* A quick note: it is assumed that the call to `__errno_location' does
    not modify the stack!  */
 # else
 #  define SYSCALL_ERROR_HANDLER						      \
   .type syscall_error,@function;					      \
-0:movl (%esp),%ecx;							      \
+1:movl (%esp),%ecx;							      \
   ret;									      \
-syscall_error:								      \
-  call 0b;								      \
+0:call 1b;								      \
   addl $_GLOBAL_OFFSET_TABLE_, %ecx;					      \
   xorl %edx, %edx;							      \
   subl %eax, %edx;							      \
   movl errno@GOT(%ecx), %ecx;						      \
   movl %edx, (%ecx);							      \
   movl $-1, %eax;							      \
-  jmp L(pseudo_end);							      \
-  .size syscall_error,.-syscall_error;
+  jmp L(pseudo_end);
 # endif	/* _LIBC_REENTRANT */
 #endif	/* PIC */
 
diff --git a/sysdeps/unix/sysv/linux/i386/mmap.S b/sysdeps/unix/sysv/linux/i386/mmap.S
index 5c2449e961..e0dde22a9f 100644
--- a/sysdeps/unix/sysv/linux/i386/mmap.S
+++ b/sysdeps/unix/sysv/linux/i386/mmap.S
@@ -37,7 +37,7 @@ ENTRY (__mmap)
 
 	/* If 0 > %eax > -4096 there was an error.  */
 	cmpl $-4096, %eax
-	ja syscall_error
+	ja SYSCALL_ERROR_LABEL
 
 	/* Successful; return the syscall's value.  */
 L(pseudo_end):
diff --git a/sysdeps/unix/sysv/linux/i386/s_pread64.S b/sysdeps/unix/sysv/linux/i386/s_pread64.S
index 23d7d14ba5..7817cf7980 100644
--- a/sysdeps/unix/sysv/linux/i386/s_pread64.S
+++ b/sysdeps/unix/sysv/linux/i386/s_pread64.S
@@ -44,10 +44,10 @@ ENTRY (__syscall_pread64)
 	movl	0x10(%esp,1),%ebx
 	/* Load syscall number into %eax.  */
 	movl	$SYS_ify(pread), %eax
-	int	$0x80		/* Do the system call.  */
-	POPARGS_5		/* Restore register contents.  */
-	cmpl	$-4095, %eax	/* Check %eax for error.  */
-	jae	syscall_error	/* Jump to error handler if error.  */
+	int	$0x80			/* Do the system call.  */
+	POPARGS_5			/* Restore register contents.  */
+	cmpl	$-4095, %eax		/* Check %eax for error.  */
+	jae	SYSCALL_ERROR_LABEL	/* Jump to error handler if error.  */
 #endif
 L(pseudo_end):
 	ret			/* Return to caller.  */
diff --git a/sysdeps/unix/sysv/linux/i386/s_pwrite64.S b/sysdeps/unix/sysv/linux/i386/s_pwrite64.S
index 7b72d12f0b..89449b6fb5 100644
--- a/sysdeps/unix/sysv/linux/i386/s_pwrite64.S
+++ b/sysdeps/unix/sysv/linux/i386/s_pwrite64.S
@@ -44,10 +44,10 @@ ENTRY (__syscall_pwrite64)
 	movl	0x10(%esp,1),%ebx
 	/* Load syscall number into %eax.  */
 	movl	$SYS_ify(pwrite), %eax
-	int	$0x80		/* Do the system call.  */
-	POPARGS_5		/* Restore register contents.  */
-	cmpl	$-4095, %eax	/* Check %eax for error.  */
-	jae	syscall_error	/* Jump to error handler if error.  */
+	int	$0x80			/* Do the system call.  */
+	POPARGS_5			/* Restore register contents.  */
+	cmpl	$-4095, %eax		/* Check %eax for error.  */
+	jae	SYSCALL_ERROR_LABEL	/* Jump to error handler if error.  */
 #endif
 L(pseudo_end):
 	ret			/* Return to caller.  */
diff --git a/sysdeps/unix/sysv/linux/i386/socket.S b/sysdeps/unix/sysv/linux/i386/socket.S
index 4326676bc2..245d37a17f 100644
--- a/sysdeps/unix/sysv/linux/i386/socket.S
+++ b/sysdeps/unix/sysv/linux/i386/socket.S
@@ -55,7 +55,7 @@ ENTRY (__socket)
 
 	/* %eax is < 0 if there was an error.  */
 	cmpl $-125, %eax
-	jae syscall_error
+	jae SYSCALL_ERROR_LABEL
 
 	/* Successful; return the syscall's value.  */
 L(pseudo_end):
diff --git a/sysdeps/unix/sysv/linux/i386/syscall.S b/sysdeps/unix/sysv/linux/i386/syscall.S
index 349408de30..48328c2a0e 100644
--- a/sysdeps/unix/sysv/linux/i386/syscall.S
+++ b/sysdeps/unix/sysv/linux/i386/syscall.S
@@ -30,7 +30,7 @@ ENTRY (syscall)
 	int $0x80		/* Do the system call.  */
 	POPARGS_5		/* Restore register contents.  */
 	cmpl $-4095, %eax	/* Check %eax for error.  */
-	jae syscall_error	/* Jump to error handler if error.  */
+	jae SYSCALL_ERROR_LABEL	/* Jump to error handler if error.  */
 L(pseudo_end):
 	ret			/* Return to caller.  */
 
diff --git a/sysdeps/unix/sysv/linux/i386/sysdep.h b/sysdeps/unix/sysv/linux/i386/sysdep.h
index 5231d3e9a1..8c046efed7 100644
--- a/sysdeps/unix/sysv/linux/i386/sysdep.h
+++ b/sysdeps/unix/sysv/linux/i386/sysdep.h
@@ -46,13 +46,22 @@
    is a real error number.  Linus said he will make sure the no syscall
    returns a value in -1 .. -4095 as a valid result so we can savely
    test with -4095.  */
+
+/* We don't want the label for the error handle to be global when we define
+   it here.  */
+#ifdef PIC
+# define SYSCALL_ERROR_LABEL 0f
+#else
+# define SYSCALL_ERROR_LABEL syscall_error
+#endif
+
 #undef	PSEUDO
 #define	PSEUDO(name, syscall_name, args)				      \
   .text;								      \
   ENTRY (name)								      \
     DO_CALL (args, syscall_name);					      \
     cmpl $-4095, %eax;							      \
-    jae syscall_error;							      \
+    jae SYSCALL_ERROR_LABEL;						      \
   L(pseudo_end):
 
 #undef	PSEUDO_END
@@ -66,13 +75,11 @@
 /* Store (- %eax) into errno through the GOT.  */
 #ifdef _LIBC_REENTRANT
 #define SYSCALL_ERROR_HANDLER						      \
-  .type syscall_error,@function;					      \
-syscall_error:								      \
-  pushl %ebx;								      \
-  call 0f;								      \
-0:popl %ebx;								      \
+0:pushl %ebx;								      \
+  call 1f;								      \
+1:popl %ebx;								      \
   xorl %edx, %edx;							      \
-  addl $_GLOBAL_OFFSET_TABLE_+[.-0b], %ebx;				      \
+  addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx;				      \
   subl %eax, %edx;							      \
   pushl %edx;								      \
   call __errno_location@PLT;						      \
@@ -80,24 +87,20 @@ syscall_error:								      \
   popl %ebx;								      \
   movl %ecx, (%eax);							      \
   movl $-1, %eax;							      \
-  jmp L(pseudo_end);							      \
-  .size syscall_error,.-syscall_error;
+  jmp L(pseudo_end);
 /* A quick note: it is assumed that the call to `__errno_location' does
    not modify the stack!  */
 #else
 #define SYSCALL_ERROR_HANDLER						      \
-  .type syscall_error,@function;					      \
-syscall_error:								      \
-  call 0f;								      \
-0:popl %ecx;								      \
+0:call 1f;								      \
+1:popl %ecx;								      \
   xorl %edx, %edx;							      \
-  addl $_GLOBAL_OFFSET_TABLE_+[.-0b], %ecx;				      \
+  addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ecx;				      \
   subl %eax, %edx;							      \
   movl errno@GOT(%ecx), %ecx;						      \
   movl %edx, (%ecx);							      \
   movl $-1, %eax;							      \
-  jmp L(pseudo_end);							      \
-  .size syscall_error,.-syscall_error;
+  jmp L(pseudo_end);
 #endif	/* _LIBC_REENTRANT */
 #endif	/* PIC */
 
diff --git a/sysdeps/unix/sysv/linux/sigset-cvt-mask.h b/sysdeps/unix/sysv/linux/sigset-cvt-mask.h
new file mode 100644
index 0000000000..aefb805394
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/sigset-cvt-mask.h
@@ -0,0 +1,35 @@
+/* Convert between lowlevel sigmask and libc representation of sigset_t.
+   Linux version.
+   Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Joe Keane <jgk@jgk.org>.
+
+   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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#define sigset_set_old_mask(set, mask) \
+  do {									      \
+    unsigned long int *__ptr;						      \
+    int __cnt;								      \
+    __ptr = &(set)->__val[0];						      \
+    *__ptr++ = (unsigned long int) (mask);				      \
+    __cnt = _SIGSET_NWORDS - 2;						      \
+    do									      \
+      *__ptr++ = 0ul;							      \
+    while (--__cnt >= 0);						      \
+  } while (0)
+
+#define sigset_get_old_mask(set, mask) \
+  ((mask) = (unsigned int) (set)->__val[0])
diff --git a/sysdeps/unix/sysv/sysv4/sigset-cvt-mask.h b/sysdeps/unix/sysv/sysv4/sigset-cvt-mask.h
new file mode 100644
index 0000000000..4daab22bc5
--- /dev/null
+++ b/sysdeps/unix/sysv/sysv4/sigset-cvt-mask.h
@@ -0,0 +1,33 @@
+/* Convert between lowlevel sigmask and libc representation of sigset_t.
+   SysVr4 version.
+   Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Joe Keane <jgk@jgk.org>.
+
+   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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#define sigset_set_old_mask(set, mask) \
+  do {									      \
+    unsigned long int *__ptr;						      \
+    __ptr = &(set)->__sigbits[0];					      \
+    __ptr[0] = (mask);							      \
+    __ptr[1] = 0ul;							      \
+    __ptr[2] = 0ul;							      \
+    __ptr[3] = 0ul;							      \
+  } while (0)
+
+#define sigset_get_old_mask(set, mask) \
+  ((mask) = (unsigned int) (set)->__sigbits[0])