summary refs log tree commit diff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1997-03-21 20:00:48 +0000
committerUlrich Drepper <drepper@redhat.com>1997-03-21 20:00:48 +0000
commit5ae9d168f66cc6b40f74cfb4a8f2631fc1df6a2a (patch)
tree5157016d80fd69eef4b7f2c74f83c37eebba50d1
parentf752bfe37962db44ac8db553d840f8215966911e (diff)
downloadglibc-5ae9d168f66cc6b40f74cfb4a8f2631fc1df6a2a.tar.gz
glibc-5ae9d168f66cc6b40f74cfb4a8f2631fc1df6a2a.tar.xz
glibc-5ae9d168f66cc6b40f74cfb4a8f2631fc1df6a2a.zip
Update.
1997-03-21 20:55  Ulrich Drepper  <drepper@cygnus.com>

	* sysdeps/generic/machine-gmon.h: Update copyright.

	* sysdeps/i386/Makefile [$(subdir)=gmon] (sysdep_routines): Add
	i386-mcount.
	* sysdeps/i386/dl-machine.h [PROF] (_dl_runtime_resolve): Don't
	use regparam mechanism for call of `fixup' call.
	* sysdeps/i386/Dist: New file.
	* sysdeps/i386/i386-mcount.S: New file.  `mcount' entry point.
	* sysdeps/i386/machine-gmon.h: New file.  i386 specific version
	of gmon definitions.

1997-03-20 13:39  Andreas Jaeger  <aj@arthur.pfalz.de>

	* stdlib/tst-strtol.c (main): Save the value of errno since printf
	may modify it, use the saved errno everywhere.
	* stdlib/tst-strtod.c (main): Likewise.

1997-03-21 05:54  Ulrich Drepper  <drepper@cygnus.com>

	* posix/glob.c (glob): Fix completely broken handling of
	GLOB_BRACE and partly broken handling of GLOB_TILDE.
	Reported by Dennis Henriksen <opus@flamingo.osrl.dk>.

1997-03-20 20:22  Ulrich Drepper  <drepper@cygnus.com>

	* sysdeps/unix/sysv/linux/readv.c: Don't emulate readv with small
	UIO_FASTIOV value by multiple readv calls since we need atomicity.
	* sysdeps/unix/sysv/linux/writev.c: Likewise.
	Reported by Matthis Urlichs.

1997-03-20 04:34  Roland McGrath  <roland@baalperazim.frob.com>

	* sysdeps/unix/sysv/linux/i386/sysdep.S (CALL_MCOUNT): Clear this
	macro so ENTRY(__syscall_error) doesn't insert a call to _mcount,
	which clobbers %eax.

	* Makeconfig [$(elf)=yes] (+prector, +postctor): New variables for
	crtbegin.o/crtend.o, using gcc to find them.
	(+link): Use them.

1997-03-20 00:06  Richard Henderson  <rth@tamu.edu>

	* gmon/sys/gmon.h: Revert the bulk of the 960930 changes, as they
	affect the alignment, and therefore the end padding of the structs.
	Reported by David Mosberger <davidm@azstarnet.com>.
	* gmon.c: Declare the variables with aligned tags to compensate.
	Use __writev instead of write for the I/O.

	* misc/sys/uio.h: Declare __writev and __readv.
	* sysdeps/posix/readv.c: Rename and alias readv to __readv.
	* sysdeps/posix/writev.c: Likewise for writev.
	* sysdeps/stub/readv.c: Likewise.
	* sysdeps/stub/writev.c: Likewise.
	* sysdeps/unix/syscalls.list: Likewise.
	* sysdeps/unix/sysv/linux/readv.c: Likewise.
	* sysdeps/unix/sysv/linux/writev.c: Likewise.

	* stdlib/testdiv.c: Exit with error status when we have an error.
	* sysdeps/alpha/div.S: Initialize `quotient' and `mask'.
	* sysdeps/alpha/ldiv.S: Likewise.

	* sysdeps/unix/sysv/linux/alpha/ioperm.c: Include ctype.h for isdigit.

1997-03-20 14:51  Ulrich Drepper  <drepper@cygnus.com>

	* nis/nis_file.c: Unify error handling.

1997-03-19 18:36  Thorsten Kukuk  <kukuk@vt.uni-paderborn.de>

	* nis/nis_file.c (writeColdStartFile): Fix typo.
	* nis/nis_free.c (nis_free_endpoints): Use unsigned int.
	* nis/nis_free.c (nis_free_servers): Likewise.
	* nis/rpcsvc/nislib.h: Likewise.

	* sunrpc/rpc/netdb.h: Add setrpcent and endrpcent prototypes.
-rw-r--r--ChangeLog78
-rw-r--r--FAQ2
-rw-r--r--Makeconfig6
-rw-r--r--gmon/gmon.c94
-rw-r--r--gmon/sys/gmon_out.h48
-rw-r--r--misc/sys/uio.h6
-rw-r--r--nis/nis_file.c18
-rw-r--r--nis/nis_free.c4
-rw-r--r--nis/rpcsvc/nislib.h4
-rw-r--r--posix/glob.c294
-rw-r--r--stdlib/testdiv.c12
-rw-r--r--stdlib/tst-strtod.c33
-rw-r--r--stdlib/tst-strtol.c13
-rw-r--r--sunrpc/rpc/netdb.h2
-rw-r--r--sysdeps/alpha/div.S21
-rw-r--r--sysdeps/alpha/ldiv.S19
-rw-r--r--sysdeps/generic/machine-gmon.h34
-rw-r--r--sysdeps/i386/Dist2
-rw-r--r--sysdeps/i386/Makefile4
-rw-r--r--sysdeps/i386/dl-machine.h32
-rw-r--r--sysdeps/i386/i386-mcount.S65
-rw-r--r--sysdeps/i386/machine-gmon.h41
-rw-r--r--sysdeps/posix/readv.c9
-rw-r--r--sysdeps/posix/writev.c9
-rw-r--r--sysdeps/stub/readv.c31
-rw-r--r--sysdeps/stub/writev.c31
-rw-r--r--sysdeps/unix/syscalls.list4
-rw-r--r--sysdeps/unix/sysv/linux/alpha/ioperm.c1
-rw-r--r--sysdeps/unix/sysv/linux/i386/sysdep.S5
-rw-r--r--sysdeps/unix/sysv/linux/readv.c32
-rw-r--r--sysdeps/unix/sysv/linux/writev.c31
31 files changed, 668 insertions, 317 deletions
diff --git a/ChangeLog b/ChangeLog
index df79015bbd..57b1588e66 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,81 @@
+1997-03-21 20:55  Ulrich Drepper  <drepper@cygnus.com>
+
+	* sysdeps/generic/machine-gmon.h: Update copyright.
+
+	* sysdeps/i386/Makefile [$(subdir)=gmon] (sysdep_routines): Add
+	i386-mcount.
+	* sysdeps/i386/dl-machine.h [PROF] (_dl_runtime_resolve): Don't
+	use regparam mechanism for call of `fixup' call.
+	* sysdeps/i386/Dist: New file.
+	* sysdeps/i386/i386-mcount.S: New file.  `mcount' entry point.
+	* sysdeps/i386/machine-gmon.h: New file.  i386 specific version
+	of gmon definitions.
+
+1997-03-20 13:39  Andreas Jaeger  <aj@arthur.pfalz.de>
+
+	* stdlib/tst-strtol.c (main): Save the value of errno since printf
+	may modify it, use the saved errno everywhere.
+	* stdlib/tst-strtod.c (main): Likewise.
+
+1997-03-21 05:54  Ulrich Drepper  <drepper@cygnus.com>
+
+	* posix/glob.c (glob): Fix completely broken handling of
+	GLOB_BRACE and partly broken handling of GLOB_TILDE.
+	Reported by Dennis Henriksen <opus@flamingo.osrl.dk>.
+
+1997-03-20 20:22  Ulrich Drepper  <drepper@cygnus.com>
+
+	* sysdeps/unix/sysv/linux/readv.c: Don't emulate readv with small
+	UIO_FASTIOV value by multiple readv calls since we need atomicity.
+	* sysdeps/unix/sysv/linux/writev.c: Likewise.
+	Reported by Matthis Urlichs.
+
+1997-03-20 04:34  Roland McGrath  <roland@baalperazim.frob.com>
+
+	* sysdeps/unix/sysv/linux/i386/sysdep.S (CALL_MCOUNT): Clear this
+	macro so ENTRY(__syscall_error) doesn't insert a call to _mcount,
+	which clobbers %eax.
+
+	* Makeconfig [$(elf)=yes] (+prector, +postctor): New variables for
+	crtbegin.o/crtend.o, using gcc to find them.
+	(+link): Use them.
+
+1997-03-20 00:06  Richard Henderson  <rth@tamu.edu>
+
+	* gmon/sys/gmon.h: Revert the bulk of the 960930 changes, as they
+	affect the alignment, and therefore the end padding of the structs.
+	Reported by David Mosberger <davidm@azstarnet.com>.
+	* gmon.c: Declare the variables with aligned tags to compensate.
+	Use __writev instead of write for the I/O.
+
+	* misc/sys/uio.h: Declare __writev and __readv.
+	* sysdeps/posix/readv.c: Rename and alias readv to __readv.
+	* sysdeps/posix/writev.c: Likewise for writev.
+	* sysdeps/stub/readv.c: Likewise.
+	* sysdeps/stub/writev.c: Likewise.
+	* sysdeps/unix/syscalls.list: Likewise.
+	* sysdeps/unix/sysv/linux/readv.c: Likewise.
+	* sysdeps/unix/sysv/linux/writev.c: Likewise.
+
+	* stdlib/testdiv.c: Exit with error status when we have an error.
+	* sysdeps/alpha/div.S: Initialize `quotient' and `mask'.
+	* sysdeps/alpha/ldiv.S: Likewise.
+
+	* sysdeps/unix/sysv/linux/alpha/ioperm.c: Include ctype.h for isdigit.
+
+1997-03-20 14:51  Ulrich Drepper  <drepper@cygnus.com>
+
+	* nis/nis_file.c: Unify error handling.
+
+1997-03-19 18:36  Thorsten Kukuk  <kukuk@vt.uni-paderborn.de>
+
+	* nis/nis_file.c (writeColdStartFile): Fix typo.
+	* nis/nis_free.c (nis_free_endpoints): Use unsigned int.
+	* nis/nis_free.c (nis_free_servers): Likewise.
+	* nis/rpcsvc/nislib.h: Likewise.
+
+	* sunrpc/rpc/netdb.h: Add setrpcent and endrpcent prototypes.
+
 1997-03-20 06:07  Ulrich Drepper  <drepper@cygnus.com>
 
 	* sysdeps/powerpc/dl-machine.h: Fix typo in last change.
diff --git a/FAQ b/FAQ
index c7d6445ea6..f8a638fd3b 100644
--- a/FAQ
+++ b/FAQ
@@ -609,7 +609,7 @@ e.g. i486-linux.
                 # GNU libc version 2 does not supply these;
                 # we want them from GCC.
 -               extra_parts="crtbegin.o crtend.o"
-+               extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS..o"
++               extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
                 ;;
          i[3456]86-go32-msdos | i[3456]86-*-go32)
                cpu_type=i386
diff --git a/Makeconfig b/Makeconfig
index 10bca6018a..38437d4dd2 100644
--- a/Makeconfig
+++ b/Makeconfig
@@ -320,10 +320,10 @@ endif
 ifndef +link
 +link = $(CC) -nostdlib -nostartfiles -o $@ \
 	      $(sysdep-LDFLAGS) $(config-LDFLAGS) $(LDFLAGS)  \
-	      $(addprefix $(csu-objpfx),start.o) $(+preinit) \
+	      $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+prector) \
 	      $(filter-out $(addprefix $(csu-objpfx),start.o) $(+preinit) \
 		$(link-extra-libs) $(common-objpfx)libc% $(+postinit),$^) \
-	      $(link-extra-libs) $(link-libc) $(+postinit)
+	      $(link-extra-libs) $(link-libc) $(+postctor) $(+postinit)
 endif
 ifndef config-LDFLAGS
 ifeq (yes,$(build-shared))
@@ -374,6 +374,8 @@ endif
 ifeq ($(elf),yes)
 +preinit = $(addprefix $(csu-objpfx),crti.o)
 +postinit = $(addprefix $(csu-objpfx),crtn.o)
++prector = `$(CC) --print-file-name=crtbegin.o`
++postctor = `$(CC) --print-file-name=crtend.o`
 endif
 csu-objpfx = $(common-objpfx)csu/
 elf-objpfx = $(common-objpfx)elf/
diff --git a/gmon/gmon.c b/gmon/gmon.c
index 6dc4cb5998..e00b339367 100644
--- a/gmon/gmon.c
+++ b/gmon/gmon.c
@@ -34,6 +34,7 @@
 #include <sys/time.h>
 #include <sys/gmon.h>
 #include <sys/gmon_out.h>
+#include <sys/uio.h>
 
 #include <stdio.h>
 #include <fcntl.h>
@@ -165,21 +166,26 @@ static void
 write_hist (fd)
      int fd;
 {
-  const u_char tag = GMON_TAG_TIME_HIST;
-  struct gmon_hist_hdr thdr;
+  u_char tag = GMON_TAG_TIME_HIST;
+  struct gmon_hist_hdr thdr __attribute__ ((aligned (__alignof__ (char *))));
 
   if (_gmonparam.kcountsize > 0)
     {
-      thdr.low_pc = _gmonparam.lowpc;
-      thdr.high_pc = _gmonparam.highpc;
-      thdr.hist_size = _gmonparam.kcountsize / sizeof(HISTCOUNTER);
-      thdr.prof_rate = __profile_frequency();
-      strncpy(thdr.dimen, "seconds", sizeof(thdr.dimen));
+      struct iovec iov[3] =
+        {
+	  { &tag, sizeof (tag) },
+	  { &thdr, sizeof (struct gmon_hist_hdr) },
+	  { _gmonparam.kcount, _gmonparam.kcountsize }
+	};
+
+      *(char **) thdr.low_pc = (char *) _gmonparam.lowpc;
+      *(char **) thdr.high_pc = (char *) _gmonparam.highpc;
+      *(int *) thdr.hist_size = _gmonparam.kcountsize / sizeof (HISTCOUNTER);
+      *(int *) thdr.prof_rate = __profile_frequency ();
+      strncpy (thdr.dimen, "seconds", sizeof (thdr.dimen));
       thdr.dimen_abbrev = 's';
 
-      write(fd, &tag, sizeof(tag));
-      write(fd, &thdr, sizeof(thdr));
-      write(fd, _gmonparam.kcount, _gmonparam.kcountsize);
+      __writev (fd, iov, 3);
     }
 }
 
@@ -188,12 +194,19 @@ static void
 write_call_graph (fd)
      int fd;
 {
-  const u_char tag = GMON_TAG_CG_ARC;
-  struct gmon_cg_arc_record raw_arc;
+  u_char tag = GMON_TAG_CG_ARC;
+  struct gmon_cg_arc_record raw_arc
+    __attribute__ ((aligned (__alignof__ (char*))));
   int from_index, to_index, from_len;
   u_long frompc;
 
-  from_len = _gmonparam.fromssize / sizeof(*_gmonparam.froms);
+  struct iovec iov[2] =
+    {
+      { &tag, sizeof (tag) },
+      { &raw_arc, sizeof (struct gmon_cg_arc_record) }
+    };
+
+  from_len = _gmonparam.fromssize / sizeof (*_gmonparam.froms);
   for (from_index = 0; from_index < from_len; ++from_index)
     {
       if (_gmonparam.froms[from_index] == 0)
@@ -201,17 +214,16 @@ write_call_graph (fd)
 
       frompc = _gmonparam.lowpc;
       frompc += (from_index * _gmonparam.hashfraction
-		 * sizeof(*_gmonparam.froms));
+		 * sizeof (*_gmonparam.froms));
       for (to_index = _gmonparam.froms[from_index];
 	   to_index != 0;
 	   to_index = _gmonparam.tos[to_index].link)
 	{
-	  raw_arc.from_pc = frompc;
-	  raw_arc.self_pc = _gmonparam.tos[to_index].selfpc;
-	  raw_arc.count = _gmonparam.tos[to_index].count;
+	  *(char **) raw_arc.from_pc = (char *)frompc;
+	  *(char **) raw_arc.self_pc = (char *)_gmonparam.tos[to_index].selfpc;
+	  *(int *) raw_arc.count = _gmonparam.tos[to_index].count;
 
-	  write(fd, &tag, sizeof(tag));
-	  write(fd, &raw_arc, sizeof(raw_arc));
+	  __writev (fd, iov, 2);
 	}
     }
 }
@@ -222,22 +234,32 @@ write_bb_counts (fd)
      int fd;
 {
   struct __bb *grp;
-  const u_char tag = GMON_TAG_BB_COUNT;
+  u_char tag = GMON_TAG_BB_COUNT;
   int ncounts;
   int i;
 
+  struct iovec bbhead[2] =
+    {
+      { &tag, sizeof (tag) },
+      { &ncounts, sizeof (ncounts) }
+    };
+  struct iovec bbbody[2];
+
+  bbbody[0].iov_len = sizeof (grp->addresses[0]);
+  bbbody[1].iov_len = sizeof (grp->addresses[0]);
+
   /* Write each group of basic-block info (all basic-blocks in a
      compilation unit form a single group). */
 
   for (grp = __bb_head; grp; grp = grp->next)
     {
       ncounts = grp->ncounts;
-      write(fd, &tag, sizeof(tag));
-      write(fd, &ncounts, sizeof(ncounts));
+      __writev (fd, bbhead, 2);
       for (i = 0; i < ncounts; ++i)
 	{
-	  write(fd, &grp->addresses[i], sizeof(grp->addresses[0]));
-	  write(fd, &grp->counts[i], sizeof(grp->counts[0]));
+	  bbbody[0].iov_base = (char *) &grp->addresses[i];
+	  bbbody[1].iov_base = &grp->counts[i];
+	  __writev (fd, bbbody, 2);
 	}
     }
 }
@@ -246,31 +268,31 @@ write_bb_counts (fd)
 void
 _mcleanup ()
 {
-    struct gmon_hdr ghdr;
+    struct gmon_hdr ghdr __attribute__ ((aligned (__alignof__ (int))));
     int fd;
 
-    moncontrol(0);
-    fd = open("gmon.out", O_CREAT|O_TRUNC|O_WRONLY, 0666);
+    moncontrol (0);
+    fd = __open ("gmon.out", O_CREAT|O_TRUNC|O_WRONLY, 0666);
     if (fd < 0)
       {
-	perror("_mcleanup: gmon.out");
+	perror ("_mcleanup: gmon.out");
 	return;
       }
 
     /* write gmon.out header: */
-    memset(&ghdr, 0, sizeof(ghdr));
-    memcpy(&ghdr.cookie[0], GMON_MAGIC, sizeof(ghdr.cookie));
-    ghdr.version = GMON_VERSION;
-    write(fd, &ghdr, sizeof(ghdr));
+    memset (&ghdr, 0, sizeof (struct gmon_hdr));
+    memcpy (&ghdr.cookie[0], GMON_MAGIC, sizeof (ghdr.cookie));
+    *(int *) ghdr.version = GMON_VERSION;
+    __write (fd, &ghdr, sizeof (struct gmon_hdr));
 
     /* write PC histogram: */
-    write_hist(fd);
+    write_hist (fd);
 
     /* write call-graph: */
-    write_call_graph(fd);
+    write_call_graph (fd);
 
     /* write basic-block execution counts: */
-    write_bb_counts(fd);
+    write_bb_counts (fd);
 
-    close(fd);
+    __close (fd);
 }
diff --git a/gmon/sys/gmon_out.h b/gmon/sys/gmon_out.h
index 94e815d94b..36059cc572 100644
--- a/gmon/sys/gmon_out.h
+++ b/gmon/sys/gmon_out.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by David Mosberger <davidm@cs.arizona.edu>.
 
@@ -40,30 +40,36 @@ __BEGIN_DECLS
  * always comes first in gmon.out and is then followed by a series
  * records defined below.
  */
-struct gmon_hdr {
-  char cookie[4];
-  int version;
-  int spare[3];
-};
+struct gmon_hdr
+  {
+    char cookie[4];
+    char version[4];
+    char spare[3 * 4];
+  };
 
 /* types of records in this file: */
-typedef enum {
-  GMON_TAG_TIME_HIST = 0, GMON_TAG_CG_ARC = 1, GMON_TAG_BB_COUNT = 2
-} GMON_Record_Tag;
+typedef enum
+  {
+    GMON_TAG_TIME_HIST = 0,
+    GMON_TAG_CG_ARC = 1,
+    GMON_TAG_BB_COUNT = 2
+  } GMON_Record_Tag;
 
-struct gmon_hist_hdr {
-  unsigned long low_pc;			/* base pc address of sample buffer */
-  unsigned long high_pc;		/* max pc address of sampled buffer */
-  int hist_size;			/* size of sample buffer */
-  int prof_rate;			/* profiling clock rate */
-  char dimen[15];			/* phys. dim., usually "seconds" */
-  char dimen_abbrev;			/* usually 's' for "seconds" */
-};
+struct gmon_hist_hdr
+  {
+    char low_pc[sizeof (char *)];	/* base pc address of sample buffer */
+    char high_pc[sizeof (char *)];	/* max pc address of sampled buffer */
+    char hist_size[4];			/* size of sample buffer */
+    char prof_rate[4];			/* profiling clock rate */
+    char dimen[15];			/* phys. dim., usually "seconds" */
+    char dimen_abbrev;			/* usually 's' for "seconds" */
+  };
 
-struct gmon_cg_arc_record {
-  unsigned long from_pc;		/* address within caller's body */
-  unsigned long self_pc;		/* address within callee's body */
-  int count;				/* number of arc traversals */
+struct gmon_cg_arc_record
+  {
+    char from_pc[sizeof (char *)];	/* address within caller's body */
+    char self_pc[sizeof (char *)];	/* address within callee's body */
+    char count[4];			/* number of arc traversals */
 };
 
 __END_DECLS
diff --git a/misc/sys/uio.h b/misc/sys/uio.h
index bc49324cc5..901f9bbc25 100644
--- a/misc/sys/uio.h
+++ b/misc/sys/uio.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1992, 1996 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1992, 1996, 1997 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
@@ -34,6 +34,8 @@ __BEGIN_DECLS
    The buffers are filled in the order specified.
    Operates just like `read' (see <unistd.h>) except that data are
    put in VECTOR instead of a contiguous buffer.  */
+extern ssize_t __readv __P ((int __fd, __const struct iovec *__vector,
+			     int __count));
 extern ssize_t readv __P ((int __fd, __const struct iovec *__vector,
 			   int __count));
 
@@ -42,6 +44,8 @@ extern ssize_t readv __P ((int __fd, __const struct iovec *__vector,
    The data is written in the order specified.
    Operates just like `write' (see <unistd.h>) except that the data
    are taken from VECTOR instead of a contiguous buffer.  */
+extern ssize_t __writev __P ((int __fd, __const struct iovec *__vector,
+			      int __count));
 extern ssize_t writev __P ((int __fd, __const struct iovec *__vector,
 			    int __count));
 
diff --git a/nis/nis_file.c b/nis/nis_file.c
index 002e72ed20..ccff52f0bc 100644
--- a/nis/nis_file.c
+++ b/nis/nis_file.c
@@ -23,6 +23,9 @@
 #include <rpcsvc/nis.h>
 #include <rpcsvc/nislib.h>
 
+
+static const char cold_start_file[] = "/var/nis/NIS_COLD_START";
+
 directory_obj *
 readColdStartFile (void)
 {
@@ -30,17 +33,17 @@ readColdStartFile (void)
   FILE *in;
   directory_obj obj;
 
-  in = fopen ("/var/nis/NIS_COLD_START", "rb");
+  in = fopen (cold_start_file, "rb");
   if (in == NULL)
     {
-      fputs (_("Error: Could not open /var/nis/NIS_COLD_START!\n"), stdout);
+      printf (_("Error while opening %s for reading: %m"), cold_start_file);
       return NULL;
     }
   memset (&obj, '\0', sizeof (obj));
   xdrstdio_create (&xdrs, in, XDR_DECODE);
   if (!xdr_directory_obj (&xdrs, &obj))
     {
-      fputs (("Error while reading /var/nis/NIS_COLD_START!\n"), stdout);
+      printf (_("Error while reading %s: %m"), cold_start_file);
       return NULL;
     }
 
@@ -53,16 +56,19 @@ writeColdStartFile (const directory_obj *obj)
   XDR xdrs;
   FILE *out;
 
-  out = fopen ("/var/nis/NIS_COLD_START", "wb");
+  out = fopen (cold_start_file, "wb");
   if (out == NULL)
-    return FALSE;
+    {
+      printf (_("Error while opening %s for writing: %m"), cold_start_file);
+      return FALSE;
+    }
 
   xdrstdio_create (&xdrs, out, XDR_ENCODE);
   /* XXX The following cast is bad!  Shouldn't the XDR functions take
      pointers to const objects?  */
   if (!xdr_directory_obj (&xdrs, (directory_obj *) obj))
     {
-      fputs (_("Error while reading /var/nis/NIS_COLD_START!\n"), stdout);
+      printf (_("Error while writing %s: %m"), cold_start_file);
       return FALSE;
     }
 
diff --git a/nis/nis_free.c b/nis/nis_free.c
index 35b7331372..60399c1655 100644
--- a/nis/nis_free.c
+++ b/nis/nis_free.c
@@ -67,7 +67,7 @@ nis_free_request (ib_request *ibreq)
 }
 
 void
-nis_free_endpoints (endpoint *ep, int len)
+nis_free_endpoints (endpoint *ep, unsigned int len)
 {
   int i;
 
@@ -95,7 +95,7 @@ nis_free_endpoints (endpoint *ep, int len)
 }
 
 void
-nis_free_servers (nis_server *obj, int len)
+nis_free_servers (nis_server *obj, unsigned int len)
 {
   int i;
 
diff --git a/nis/rpcsvc/nislib.h b/nis/rpcsvc/nislib.h
index 2ad38ef9c8..b01270b22d 100644
--- a/nis/rpcsvc/nislib.h
+++ b/nis/rpcsvc/nislib.h
@@ -144,8 +144,8 @@ extern void nis_freeresult __P ((nis_result *));
 /* (XXX INTERNAL FUNCTIONS, SHOULD NOT BE USED !!) */
 extern void nis_free_attr __P ((nis_attr *));
 extern void nis_free_request __P ((ib_request *));
-extern void nis_free_endpoints __P ((endpoint *, int));
-extern void nis_free_servers __P ((nis_server *, int));
+extern void nis_free_endpoints __P ((endpoint *, unsigned int));
+extern void nis_free_servers __P ((nis_server *, unsigned int));
 extern void nis_free_directory __P ((directory_obj *));
 extern void nis_free_group __P ((group_obj *));
 extern void nis_free_table __P ((table_obj *));
diff --git a/posix/glob.c b/posix/glob.c
index ac26a1af21..86a79b08a1 100644
--- a/posix/glob.c
+++ b/posix/glob.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc.
 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public License as
@@ -33,6 +33,10 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
+/* Outcomment the following line for production quality code.  */
+/* #define NDEBUG 1 */
+#include <assert.h>
+
 
 /* Comment out all this code if we are using the GNU C Library, and are not
    actually compiling the library itself.  This code is part of the GNU C
@@ -159,7 +163,7 @@ extern void bcopy ();
   ((void) ((better_be_zero) == 0 ? (bzero((s), (n)), 0) : (abort(), 0)))
 #endif	/* Not ANSI_STRING.  */
 
-#ifndef	HAVE_STRCOLL
+#if !defined HAVE_STRCOLL && !defined _LIBC
 #define	strcoll	strcmp
 #endif
 
@@ -254,6 +258,51 @@ static int glob_in_dir __P ((const char *pattern, const char *directory,
 static int prefix_array __P ((const char *prefix, char **array, size_t n));
 static int collated_compare __P ((const __ptr_t, const __ptr_t));
 
+
+/* Find the end of the sub-pattern in a brace expression.  We define
+   this as an inline function if the compiler permits.  */
+static
+#if __GNUC__ - 0 >= 2
+inline
+#endif
+const char *
+next_brace_sub (const char *begin)
+{
+  unsigned int depth = 0;
+  const char *cp = begin;
+
+  while (1)
+    {
+      if (depth == 0)
+	{
+	  if (*cp != ',' && *cp != '}' && *cp != '\0')
+	    {
+	      if (*cp == '{')
+		++depth;
+	      ++cp;
+	      continue;
+	    }
+	}
+      else
+	{
+	  while (*cp != '\0' && (*cp != '}' || depth > 0))
+	    {
+	      if (*cp == '}')
+		++depth;
+	      ++cp;
+	    }
+	  if (*cp == '\0')
+	    /* An incorrectly terminated brace expression.  */
+	    return NULL;
+
+	  continue;
+	}
+      break;
+    }
+
+  return cp;
+}
+
 /* Do glob searching for PATTERN, placing results in PGLOB.
    The bits defined above may be set in FLAGS.
    If a directory cannot be opened or read and ERRFUNC is not nil,
@@ -286,38 +335,59 @@ glob (pattern, flags, errfunc, pglob)
       const char *begin = strchr (pattern, '{');
       if (begin != NULL)
 	{
+	  /* Allocate working buffer large enough for our work.  Note that
+	    we have at least an opening and closing brace.  */
 	  int firstc;
-	  size_t restlen;
-	  const char *p, *end, *next;
-	  unsigned int depth = 0;
-
-	  /* Find the end of the brace expression, by counting braces.
-	     While we're at it, notice the first comma at top brace level.  */
-	  end = begin + 1;
-	  next = NULL;
-	  while (1)
+	  char *alt_start;
+	  const char *p;
+	  const char *next;
+	  const char *rest;
+	  size_t rest_len;
+#ifdef __GNUC__
+	  char onealt[strlen (pattern) - 1];
+#else
+	  char *onealt = (char *) malloc (strlen (pattern) - 1);
+	  if (onealt == NULL)
 	    {
-	      switch (*end++)
+	      if (!(flags & GLOB_APPEND))
+		globfree (pglob);
+	      return GLOB_NOSPACE;
+	    }
+#endif
+
+	  /* We know the prefix for all sub-patterns.  */
+	  memcpy (onealt, pattern, begin - pattern);
+	  alt_start = &onealt[begin - pattern];
+
+	  /* Find the first sub-pattern and at the same time find the
+	     rest after the closing brace.  */
+	  next = next_brace_sub (begin + 1);
+	  if (next == NULL)
+	    {
+	      /* It is an illegal expression.  */
+#ifndef __GNUC__
+	      free (onealt);
+#endif
+	      return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
+	    }
+
+	  /* Now find the end of the whole brace expression.  */
+	  rest = next;
+	  while (*rest != '}')
+	    {
+	      rest = next_brace_sub (rest + 1);
+	      if (rest == NULL)
 		{
-		case ',':
-		  if (depth == 0 && next == NULL)
-		    next = end;
-		  continue;
-		case '{':
-		  ++depth;
-		  continue;
-		case '}':
-		  if (depth-- == 0)
-		    break;
-		  continue;
-		case '\0':
-		  return glob (pattern, flags &~ GLOB_BRACE, errfunc, pglob);
+		  /* It is an illegal expression.  */
+#ifndef __GNUC__
+		  free (onealt);
+#endif
+		  return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
 		}
-	      break;
 	    }
-	  restlen = strlen (end) + 1;
-	  if (next == NULL)
-	    next = end;
+	  /* Please note that we now can be sure the brace expression
+	     is well-formed.  */
+	  rest_len = strlen (++rest) + 1;
 
 	  /* We have a brace expression.  BEGIN points to the opening {,
 	     NEXT points past the terminator of the first element, and END
@@ -334,72 +404,47 @@ glob (pattern, flags, errfunc, pglob)
 	    }
 	  firstc = pglob->gl_pathc;
 
-	  /* In this loop P points to the beginning of the current element
-	     and NEXT points past its terminator.  */
 	  p = begin + 1;
 	  while (1)
 	    {
-	      /* Construct a whole name that is one of the brace
-		 alternatives in a temporary buffer.  */
 	      int result;
-	      size_t bufsz = (begin - pattern) + (next - 1 - p) + restlen;
-#ifdef __GNUC__
-	      char onealt[bufsz];
-#else
-	      char *onealt = malloc (bufsz);
-	      if (onealt == NULL)
-		{
-		  if (!(flags & GLOB_APPEND))
-		    globfree (pglob);
-		  return GLOB_NOSPACE;
-		}
-#endif
-	      memcpy (onealt, pattern, begin - pattern);
-	      memcpy (&onealt[begin - pattern], p, next - 1 - p);
-	      memcpy (&onealt[(begin - pattern) + (next - 1 - p)],
-		      end, restlen);
+
+	      /* Construct the new glob expression.  */
+	      memcpy (alt_start, p, next - p);
+	      memcpy (&alt_start[next - p], rest, rest_len);
+
 	      result = glob (onealt,
-			     ((flags & ~(GLOB_NOCHECK|GLOB_NOMAGIC)) |
-			      GLOB_APPEND), errfunc, pglob);
-#ifndef __GNUC__
-	      free (onealt);
-#endif
+			     ((flags & ~(GLOB_NOCHECK|GLOB_NOMAGIC))
+			      | GLOB_APPEND), errfunc, pglob);
 
 	      /* If we got an error, return it.  */
 	      if (result && result != GLOB_NOMATCH)
 		{
+#ifndef __GNUC__
+		  free (onealt);
+#endif
 		  if (!(flags & GLOB_APPEND))
 		    globfree (pglob);
 		  return result;
 		}
 
-	      /* Advance past this alternative and process the next.  */
-	      p = next;
-	      depth = 0;
-	    scan:
-	      switch (*p++)
-		{
-		case ',':
-		  if (depth == 0)
-		    {
-		      /* Found the next alternative.  Loop to glob it.  */
-		      next = p;
-		      continue;
-		    }
-		  goto scan;
-		case '{':
-		  ++depth;
-		  goto scan;
-		case '}':
-		  if (depth-- == 0)
-		    /* End of the brace expression.  Break out of the loop.  */
-		    break;
-		  goto scan;
-		}
+	      if (*next == '}')
+		/* We saw the last entry.  */
+		break;
+
+	      p = next + 1;
+	      next = next_brace_sub (p);
+	      assert (next != NULL);
 	    }
 
-	  if (pglob->gl_pathc == firstc &&
-	      !(flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
+#ifndef __GNUC__
+	  free (onealt);
+#endif
+
+	  if (pglob->gl_pathc != firstc)
+	    /* We found some entries.  */
+	    return 0;
+	  else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
 	    return GLOB_NOMATCH;
 	}
     }
@@ -452,19 +497,19 @@ glob (pattern, flags, errfunc, pglob)
 #ifndef VMS
   if ((flags & GLOB_TILDE) && dirname[0] == '~')
     {
-      if (dirname[1] == '\0')
+      if (dirname[1] == '\0' || dirname[1] == '/')
 	{
 	  /* Look up home directory.  */
-	  dirname = getenv ("HOME");
+	  char *home_dir = getenv ("HOME");
 #ifdef _AMIGA
-	  if (dirname == NULL || dirname[0] == '\0')
-	    dirname = "SYS:";
+	  if (home_dir == NULL || home_dir[0] == '\0')
+	    home_dir = "SYS:";
 #else
 #ifdef WIN32
-	  if (dirname == NULL || dirname[0] == '\0')
-            dirname = "c:/users/default"; /* poor default */
+	  if (home_dir == NULL || home_dir[0] == '\0')
+            home_dir = "c:/users/default"; /* poor default */
 #else
-	  if (dirname == NULL || dirname[0] == '\0')
+	  if (home_dir == NULL || home_dir[0] == '\0')
 	    {
 	      extern char *getlogin __P ((void));
 	      extern int getlogin_r __P ((char *, size_t));
@@ -501,39 +546,74 @@ glob (pattern, flags, errfunc, pglob)
 		  success = p != NULL;
 #endif
 		  if (success)
-		    dirname = p->pw_dir;
+		    home_dir = p->pw_dir;
 		}
 	    }
-	  if (dirname == NULL || dirname[0] == '\0')
-	    dirname = (char *) "~"; /* No luck.  */
+	  if (home_dir == NULL || home_dir[0] == '\0')
+	    home_dir = (char *) "~"; /* No luck.  */
 #endif /* WIN32 */
 #endif
+	  /* Now construct the full directory.  */
+	  if (dirname[1] == '\0')
+	    dirname = home_dir;
+	  else
+	    {
+	      char *newp;
+	      size_t home_len = strlen (home_dir);
+	      newp = __alloca (home_len + dirlen);
+	      memcpy (newp, home_dir, home_len);
+	      memcpy (&newp[home_len], &dirname[1], dirlen);
+	      dirname = newp;
+	    }
 	}
+#if !defined _AMIGA && !defined WIN32
       else
 	{
-#ifdef _AMIGA
-	  if (dirname == NULL || dirname[0] == '\0')
-	    dirname = "SYS:";
-#else
-#ifdef WIN32
-	  if (dirname == NULL || dirname[0] == '\0')
-            dirname = "c:/users/default"; /* poor default */
-#else
+	  char *end_name = strchr (dirname, '/');
+	  char *user_name;
+	  char *home_dir;
+
+	  if (end_name == NULL)
+	    user_name = dirname + 1;
+	  else
+	    {
+	      user_name = __alloca (end_name - dirname);
+	      memcpy (user_name, dirname + 1, end_name - dirname);
+	      user_name[end_name - dirname - 1] = '\0';
+	    }
+
 	  /* Look up specific user's home directory.  */
+	  {
 #if defined HAVE_GETPWNAM_R || defined _LIBC
-	  size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
-	  char *pwtmpbuf = __alloca (buflen);
-	  struct passwd pwbuf, *p;
-	  if (__getpwnam_r (dirname + 1, &pwbuf, pwtmpbuf, buflen, &p) >= 0)
-	    dirname = p->pw_dir;
+	    size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
+	    char *pwtmpbuf = __alloca (buflen);
+	    struct passwd pwbuf, *p;
+	    if (__getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) >= 0)
+	      home_dir = p->pw_dir;
+	    else
+	      home_dir = NULL;
 #else
-	  struct passwd *p = getpwnam (dirname + 1);
-	  if (p != NULL)
-	    dirname = p->pw_dir;
-#endif
-#endif /* WIN32 */
+	    struct passwd *p = getpwnam (user_name);
+	    if (p != NULL)
+	      home_dir = p->pw_dir;
+	    else
+	      home_dir = NULL;
 #endif
+	  }
+	  /* If we found a home directory use this.  */
+	  if (home_dir != NULL)
+	    {
+	      char *newp;
+	      size_t home_len = strlen (home_dir);
+	      size_t rest_len = end_name == NULL ? 0 : strlen (end_name);
+	      newp = __alloca (home_len + rest_len + 1);
+	      memcpy (newp, home_dir, home_len);
+	      memcpy (&newp[home_len], end_name, rest_len);
+	      newp[home_len + rest_len] = '\0';
+	      dirname = newp;
+	    }
 	}
+#endif	/* Not Amiga && not Win32.  */
     }
 #endif	/* Not VMS.  */
 
diff --git a/stdlib/testdiv.c b/stdlib/testdiv.c
index a3ae5c98d0..9a5341cf50 100644
--- a/stdlib/testdiv.c
+++ b/stdlib/testdiv.c
@@ -22,11 +22,19 @@
 int
 main (void)
 {
+  int err = 0;
   int i, j;
   while (scanf ("%d %d\n", &i, &j) == 2)
     {
       div_t d = div (i, j);
-      printf ("%d / %d = %d + %d/%d\n", i, j, d.quot, d.rem, j);
+      printf ("%d / %d = %d + %d/%d", i, j, d.quot, d.rem, j);
+      if (i == d.quot * j + d.rem)
+	fputs ("  OK\n", stdout);
+      else
+	{
+	  fputs ("  FAILED\n", stdout);
+	  err = 1;
+	}
     }
-  return 0;
+  return err;
 }
diff --git a/stdlib/tst-strtod.c b/stdlib/tst-strtod.c
index a76529c4dd..316fff93b9 100644
--- a/stdlib/tst-strtod.c
+++ b/stdlib/tst-strtod.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1996 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1996, 1997 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
@@ -49,6 +49,7 @@ main (int argc, char ** argv)
   register const struct ltest *lt;
   char *ep;
   int status = 0;
+  int save_errno;
 
   for (lt = tests; lt->str != NULL; ++lt)
     {
@@ -56,30 +57,32 @@ main (int argc, char ** argv)
 
       errno = 0;
       d = strtod(lt->str, &ep);
-      printf("strtod(\"%s\") test %u",
+      save_errno = errno;
+      printf ("strtod (\"%s\") test %u",
 	     lt->str, (unsigned int) (lt - tests));
-      if (d == lt->expect && *ep == lt->left && errno == lt->err)
-	puts("\tOK");
+      if (d == lt->expect && *ep == lt->left && save_errno == lt->err)
+	puts ("\tOK");
       else
 	{
-	  puts("\tBAD");
+	  puts ("\tBAD");
 	  if (d != lt->expect)
-	    printf("  returns %.60g, expected %.60g\n", d, lt->expect);
+	    printf ("  returns %.60g, expected %.60g\n", d, lt->expect);
 	  if (lt->left != *ep)
 	    {
 	      char exp1[5], exp2[5];
-	      expand(exp1, *ep);
-	      expand(exp2, lt->left);
-	      printf("  leaves '%s', expected '%s'\n", exp1, exp2);
+	      expand (exp1, *ep);
+	      expand (exp2, lt->left);
+	      printf ("  leaves '%s', expected '%s'\n", exp1, exp2);
 	    }
-	  if (errno != lt->err)
-	    printf("  errno %d (%s)  instead of %d (%s)\n",
-		   errno, strerror(errno), lt->err, strerror(lt->err));
+	  if (save_errno != lt->err)
+	    printf ("  errno %d (%s)  instead of %d (%s)\n",
+		    save_errno, strerror (save_errno),
+		    lt->err, strerror (lt->err));
 	  status = 1;
 	}
     }
 
-  exit(status ? EXIT_FAILURE : EXIT_SUCCESS);
+  exit (status ? EXIT_FAILURE : EXIT_SUCCESS);
 }
 
 static void
@@ -87,11 +90,11 @@ expand (dst, c)
      char *dst;
      register int c;
 {
-  if (isprint(c))
+  if (isprint (c))
     {
       dst[0] = c;
       dst[1] = '\0';
     }
   else
-    (void) sprintf(dst, "%#.3o", (unsigned int) c);
+    (void) sprintf (dst, "%#.3o", (unsigned int) c);
 }
diff --git a/stdlib/tst-strtol.c b/stdlib/tst-strtol.c
index 085787196b..13286912c7 100644
--- a/stdlib/tst-strtol.c
+++ b/stdlib/tst-strtol.c
@@ -106,9 +106,10 @@ main (int argc, char ** argv)
 	      expand (exp2, lt->left);
 	      printf ("  leaves '%s', expected '%s'\n", exp1, exp2);
 	    }
-	  if (errno != lt->err)
+	  if (save_errno != lt->err)
 	    printf ("  errno %d (%s)  instead of %d (%s)\n",
-		    errno, strerror (errno), lt->err, strerror (lt->err));
+		    save_errno, strerror (save_errno),
+		    lt->err, strerror (lt->err));
 	  status = 1;
 	}
     }
@@ -119,9 +120,10 @@ main (int argc, char ** argv)
 
       errno = 0;
       ul = strtoul (lt->str, &ep, lt->base);
+      save_errno = errno;
       printf ("strtoul(\"%s\", , %d) test %u",
 	      lt->str, lt->base, (unsigned int) (lt - tests));
-      if (ul == lt->expect && *ep == lt->left && errno == lt->err)
+      if (ul == lt->expect && *ep == lt->left && save_errno == lt->err)
 	puts("\tOK");
       else
 	{
@@ -136,9 +138,10 @@ main (int argc, char ** argv)
 	      expand (exp2, lt->left);
 	      printf ("  leaves '%s', expected '%s'\n", exp1, exp2);
 	    }
-	  if (errno != lt->err)
+	  if (save_errno != lt->err)
 	    printf ("  errno %d (%s) instead of %d (%s)\n",
-		    errno, strerror (errno), lt->err, strerror (lt->err));
+		    save_errno, strerror (save_errno),
+		    lt->err, strerror (lt->err));
 	  status = 1;
 	}
     }
diff --git a/sunrpc/rpc/netdb.h b/sunrpc/rpc/netdb.h
index e0c1d7de6e..914f825ad4 100644
--- a/sunrpc/rpc/netdb.h
+++ b/sunrpc/rpc/netdb.h
@@ -50,6 +50,8 @@ struct rpcent
   int r_number;		/* RPC program number.  */
 };
 
+extern void setrpcent __P ((int _stayopen));
+extern void endrpcent __P ((void));
 extern struct rpcent *getrpcbyname __P ((__const char *__name));
 extern struct rpcent *getrpcbynumber __P ((int __number));
 extern struct rpcent *getrpcent __P ((void));
diff --git a/sysdeps/alpha/div.S b/sysdeps/alpha/div.S
index 6c461c40d4..6a5c4429e8 100644
--- a/sysdeps/alpha/div.S
+++ b/sysdeps/alpha/div.S
@@ -1,7 +1,6 @@
-/* Copyright (C) 1996 Free Software Foundation, Inc.
-   Contributed by Richard Henderson (rth@tamu.edu)
-
+/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
+   Contributed by Richard Henderson <rth@tamu.edu>.
 
    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
@@ -14,10 +13,9 @@
    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.  */
-
+   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.  */
 
 #include <sysdep.h>
 
@@ -44,7 +42,6 @@ div:
 	.prologue 0
 #endif
 
-#define dividend  t0
 #define divisor   t1
 #define mask      t2
 #define quotient  t3
@@ -54,11 +51,13 @@ div:
 #define compare   t7
 
 	/* find correct sign for input to unsigned divide loop. */
+	negl	a1, modulus			# e0    :
+	negl	a2, divisor			# .. e1 :
 	sextl	a1, a1				# e0    :
 	sextl	a2, a2				# .. e1 :
-	negl	a1, dividend			# e0    :
-	negl	a2, divisor			# .. e1 :
-	cmovge	a1, a1, dividend		# e0    :
+	mov	zero, quotient			# e0    :
+	mov	1, mask				# .. e1 :
+	cmovge	a1, a1, modulus			# e0    :
 	cmovge	a2, a2, divisor			# .. e1 :
 	beq	a2, $divbyzero			# e1    :
 	unop					#       :
diff --git a/sysdeps/alpha/ldiv.S b/sysdeps/alpha/ldiv.S
index ebbe055870..08bf8eb08d 100644
--- a/sysdeps/alpha/ldiv.S
+++ b/sysdeps/alpha/ldiv.S
@@ -1,7 +1,6 @@
-/* Copyright (C) 1996 Free Software Foundation, Inc.
-   Contributed by Richard Henderson (rth@tamu.edu)
-
+/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
+   Contributed by Richard Henderson <rth@tamu.edu>.
 
    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
@@ -14,10 +13,9 @@
    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.  */
-
+   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.  */
 
 #include <sysdep.h>
 
@@ -44,7 +42,6 @@ ldiv:
 	.prologue 0
 #endif
 
-#define dividend  t0
 #define divisor   t1
 #define mask      t2
 #define quotient  t3
@@ -54,11 +51,13 @@ ldiv:
 #define compare   t7
 
 	/* find correct sign for input to unsigned divide loop. */
-	mov	a1, dividend			# e0    :
+	mov	a1, modulus			# e0    :
 	mov	a2, divisor			# .. e1 :
 	negq	a1, tmp1			# e0    :
 	negq	a2, tmp2			# .. e1 :
-	cmovlt	a1, tmp1, dividend		# e0    :
+	mov	zero, quotient			# e0    :
+	mov	1, mask				# .. e1 :
+	cmovlt	a1, tmp1, modulus		# e0    :
 	cmovlt	a2, tmp2, divisor		# .. e1 :
 	beq	a2, $divbyzero			# e1    :
 	unop					#       :
diff --git a/sysdeps/generic/machine-gmon.h b/sysdeps/generic/machine-gmon.h
index 31f852dece..c4a2168322 100644
--- a/sysdeps/generic/machine-gmon.h
+++ b/sysdeps/generic/machine-gmon.h
@@ -1,21 +1,21 @@
 /* Machine-dependent definitions for profiling support.  Generic GCC 2 version.
-Copyright (C) 1996 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.  */
+   Copyright (C) 1996, 1997 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
 
 /* GCC version 2 gives us a perfect magical function to get
    just the information we need:
diff --git a/sysdeps/i386/Dist b/sysdeps/i386/Dist
new file mode 100644
index 0000000000..50c07d120a
--- /dev/null
+++ b/sysdeps/i386/Dist
@@ -0,0 +1,2 @@
+i386-mcount.S
+machine-gmon.h
diff --git a/sysdeps/i386/Makefile b/sysdeps/i386/Makefile
index 21caf42052..35e0422bdb 100644
--- a/sysdeps/i386/Makefile
+++ b/sysdeps/i386/Makefile
@@ -5,6 +5,10 @@ asm-CPPFLAGS := $(asm-CPPFLAGS) -DGAS_SYNTAX
 # The i386 `long double' is a distinct type we support.
 long-double-fcts = yes
 
+ifeq ($(subdir),gmon)
+sysdep_routines += i386-mcount
+endif
+
 ifeq ($(subdir),elf)
 CFLAGS-rtld.c += -Wno-uninitialized -Wno-unused
 CFLAGS-dl-load.c += -Wno-unused
diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h
index 90ec6ce9f9..40623e795c 100644
--- a/sysdeps/i386/dl-machine.h
+++ b/sysdeps/i386/dl-machine.h
@@ -70,11 +70,16 @@ elf_machine_load_address (void)
   (dynamic_info)[DT_RELSZ]->d_un.d_val -= sizeof (Elf32_Rel);
 
 
+#ifndef PROF
 /* We add a declaration of this function here so that in dl-runtime.c
    the ELF_MACHINE_RUNTIME_TRAMPOLINE macro really can pass the parameters
-   in registers.  */
+   in registers.
+
+   We cannot use this scheme for profiling because the _mcount call
+   destroys the passed register information.  */
 static ElfW(Addr) fixup (struct link_map *l, ElfW(Word) reloc_offset)
      __attribute__ ((regparm (2), unused));
+#endif
 
 /* Set up the loaded object described by L so its unrelocated PLT
    entries will jump to the on-demand fixup code in dl-runtime.c.  */
@@ -101,7 +106,8 @@ elf_machine_runtime_setup (struct link_map *l, int lazy)
 
   /* This code is used in dl-runtime.c to call the `fixup' function
      and then redirect to the address it returns.  */
-#define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\
+#ifndef PROF
+# define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\
 	.globl _dl_runtime_resolve
 	.type _dl_runtime_resolve, @function
 _dl_runtime_resolve:
@@ -117,6 +123,28 @@ _dl_runtime_resolve:
 	ret $8			# Jump to function address.
 	.size _dl_runtime_resolve, .-_dl_runtime_resolve
 ");
+#else
+# define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\
+	.globl _dl_runtime_resolve
+	.type _dl_runtime_resolve, @function
+_dl_runtime_resolve:
+	pushl %eax		# Preserve registers otherwise clobbered.
+	pushl %ecx
+	pushl %edx
+	movl 16(%esp), %edx	# Push the arguments for `fixup'
+	movl 12(%esp), %eax
+	pushl %edx
+	pushl %eax
+	call fixup		# Call resolver.
+	popl %edx		# Pop the parameters
+	popl %ecx
+	popl %edx		# Get register content back.
+	popl %ecx
+	xchgl %eax, (%esp)	# Get %eax contents end store function address.
+	ret $8			# Jump to function address.
+	.size _dl_runtime_resolve, .-_dl_runtime_resolve
+");
+#endif
 /* The PLT uses Elf32_Rel relocs.  */
 #define elf_machine_relplt elf_machine_rel
 }
diff --git a/sysdeps/i386/i386-mcount.S b/sysdeps/i386/i386-mcount.S
new file mode 100644
index 0000000000..60d52e98fa
--- /dev/null
+++ b/sysdeps/i386/i386-mcount.S
@@ -0,0 +1,65 @@
+/* i386-specific implemetation of profiling support.
+   Copyright (C) 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+   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.  */
+
+#include <sysdep.h>
+
+/* We need a special version of the `mcount' function since for ix86 it
+   must not clobber any register.  This has several reasons:
+     - there is a bug in gcc as of version 2.7.2.2 which prohibits the
+       use of profiling together with nested functions
+     - the ELF `fixup' function uses GCC's regparm feature
+     - some (future) systems might want to pass parameters in registers.  */
+
+	ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(_mcount)
+	ASM_TYPE_DIRECTIVE(C_SYMBOL_NAME(_mcount), @function)
+	.align ALIGNARG(4)
+C_LABEL(_mcount)
+	/* Save the caller-clobbered registers.  */
+	pushl %eax
+	pushl %ecx
+	pushl %edx
+
+	movl 12(%esp), %eax
+	movl 4(%ebp), %ecx
+	pushl %eax
+	pushl %ecx
+
+#ifdef PIC
+	call 1f
+1:	popl %ecx
+	addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ecx
+	movl C_SYMBOL_NAME(__mcount_internal@GOTOFF)(%ecx), %eax
+	call *%eax
+#else
+	call C_SYMBOL_NAME(__mcount_internal)
+#endif
+	popl %ecx
+	popl %eax	/* Pop the parameters.  */
+
+	/* Pop the saved registers.  Please note that `mcount' has no
+	   return value.  */
+	popl %edx
+	popl %ecx
+	popl %eax
+	ret
+	ASM_SIZE_DIRECTIVE(C_SYMBOL_NAME(_mcount))
+
+#undef mcount
+weak_alias(_mcount, mcount)
diff --git a/sysdeps/i386/machine-gmon.h b/sysdeps/i386/machine-gmon.h
new file mode 100644
index 0000000000..496a57eb84
--- /dev/null
+++ b/sysdeps/i386/machine-gmon.h
@@ -0,0 +1,41 @@
+/* i386-specific implemetation of profiling support.
+   Copyright (C) 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+   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.  */
+
+#include <sysdep.h>
+
+/* We need a special version of the `mcount' function since for ix86 it
+   must not clobber any register.  This has several reasons:
+     - there is a bug in gcc as of version 2.7.2.2 which prohibits the
+       use of profiling together with nested functions
+     - the ELF `fixup' function uses GCC's regparm feature
+     - some (future) systems might want to pass parameters in registers.  */
+
+/* We must not pollute the global namespace.  */
+#define mcount_internal __mcount_internal
+
+void mcount_internal (u_long frompc, u_long selfpc);
+
+#define _MCOUNT_DECL(frompc, selfpc) \
+void mcount_internal (u_long frompc, u_long selfpc)
+
+
+/* Define MCOUNT as empty since we have a the implementation in another
+   file.  */
+#define MCOUNT
diff --git a/sysdeps/posix/readv.c b/sysdeps/posix/readv.c
index 878accaf92..e4a2163f6d 100644
--- a/sysdeps/posix/readv.c
+++ b/sysdeps/posix/readv.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1992, 1996 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1992, 1996, 1997 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
@@ -27,7 +27,7 @@
    Operates just like `read' (see <unistd.h>) except that data are
    put in VECTOR instead of a contiguous buffer.  */
 ssize_t
-readv (fd, vector, count)
+__readv (fd, vector, count)
      int fd;
      const struct iovec *vector;
      int count;
@@ -46,7 +46,7 @@ readv (fd, vector, count)
   buffer = (char *) __alloca (bytes);
 
   /* Read the data.  */
-  bytes_read = read (fd, buffer, bytes);
+  bytes_read = __read (fd, buffer, bytes);
   if (bytes_read <= 0)
     return -1;
 
@@ -67,3 +67,6 @@ readv (fd, vector, count)
 
   return bytes_read;
 }
+#ifndef __readv
+weak_alias (__readv, readv)
+#endif
diff --git a/sysdeps/posix/writev.c b/sysdeps/posix/writev.c
index 2f0572f837..f6f685ce7a 100644
--- a/sysdeps/posix/writev.c
+++ b/sysdeps/posix/writev.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1992, 1996 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1992, 1996, 1997 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
@@ -27,7 +27,7 @@
    Operates just like `write' (see <unistd.h>) except that the data
    are taken from VECTOR instead of a contiguous buffer.  */
 ssize_t
-writev (fd, vector, count)
+__writev (fd, vector, count)
      int fd;
      const struct iovec *vector;
      int count;
@@ -61,5 +61,8 @@ writev (fd, vector, count)
 	break;
     }
 
-  return write (fd, buffer, bytes);
+  return __write (fd, buffer, bytes);
 }
+#ifndef __writev
+weak_alias (__writev, writev)
+#endif
diff --git a/sysdeps/stub/readv.c b/sysdeps/stub/readv.c
index b537499b07..a3240df239 100644
--- a/sysdeps/stub/readv.c
+++ b/sysdeps/stub/readv.c
@@ -1,20 +1,20 @@
-/* Copyright (C) 1991, 1995, 1996 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
+/* Copyright (C) 1991, 1995, 1996, 1997 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 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.
+   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.  */
+   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.  */
 
 #include <errno.h>
 #include <unistd.h>
@@ -26,7 +26,7 @@ Cambridge, MA 02139, USA.  */
    Operates just like `read' (see <unistd.h>) except that data are
    put in VECTOR instead of a contiguous buffer.  */
 int
-readv (fd, vector, count)
+__readv (fd, vector, count)
      int fd;
      const struct iovec *vector;
      size_t count;
@@ -34,5 +34,6 @@ readv (fd, vector, count)
   __set_errno (ENOSYS);
   return -1;
 }
+weak_alias (__readv, readv)
 
 stub_warning (readv)
diff --git a/sysdeps/stub/writev.c b/sysdeps/stub/writev.c
index 593880c0e9..1fd7c2ec73 100644
--- a/sysdeps/stub/writev.c
+++ b/sysdeps/stub/writev.c
@@ -1,20 +1,20 @@
-/* Copyright (C) 1991, 1995, 1996 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
+/* Copyright (C) 1991, 1995, 1996, 1997 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 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.
+   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.  */
+   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.  */
 
 #include <errno.h>
 #include <unistd.h>
@@ -26,7 +26,7 @@ Cambridge, MA 02139, USA.  */
    Operates just like `write' (see <unistd.h>) except that the data
    are taken from VECTOR instead of a contiguous buffer.  */
 int
-writev (fd, vector, count)
+__writev (fd, vector, count)
      int fd;
      const struct iovec *vector;
      size_t count;
@@ -34,5 +34,6 @@ writev (fd, vector, count)
   __set_errno (ENOSYS);
   return -1;
 }
+weak_alias (__writev, writev)
 
 stub_warning (writev)
diff --git a/sysdeps/unix/syscalls.list b/sysdeps/unix/syscalls.list
index 9a2325c35c..5ececa058c 100644
--- a/sysdeps/unix/syscalls.list
+++ b/sysdeps/unix/syscalls.list
@@ -31,7 +31,7 @@ profil		-	profil		4	profil
 ptrace		-	ptrace		4	ptrace
 read		-	read		3	__libc_read	__read read
 readlink	-	readlink	3	__readlink	readlink
-readv		-	readv		3	readv
+readv		-	readv		3	__readv		readv
 reboot		-	reboot		1	reboot
 rename		-	rename		2	rename
 rmdir		-	rmdir		1	__rmdir		rmdir
@@ -62,4 +62,4 @@ uname		-	uname		1	uname
 unlink		-	unlink		1	__unlink	unlink
 utimes		-	utimes		2	__utimes	utimes
 write		-	write		3	__libc_write	__write write
-writev		-	writev		3	writev
+writev		-	writev		3	__writev	writev
diff --git a/sysdeps/unix/sysv/linux/alpha/ioperm.c b/sysdeps/unix/sysv/linux/alpha/ioperm.c
index b39f39a0d7..63bf17588a 100644
--- a/sysdeps/unix/sysv/linux/alpha/ioperm.c
+++ b/sysdeps/unix/sysv/linux/alpha/ioperm.c
@@ -35,6 +35,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
+#include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
diff --git a/sysdeps/unix/sysv/linux/i386/sysdep.S b/sysdeps/unix/sysv/linux/i386/sysdep.S
index 4b86d1dfe7..a686495818 100644
--- a/sysdeps/unix/sysv/linux/i386/sysdep.S
+++ b/sysdeps/unix/sysv/linux/i386/sysdep.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/* Copyright (C) 1995, 1996, 1997 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
@@ -45,6 +45,9 @@ _errno = errno	/* This name is expected by hj's libc.so.5 startup code.  */
    The code for Linux is almost identical to the canonical Unix/i386
    code, except that the error number in %eax is negated.  */
 
+#undef CALL_MCOUNT
+#define CALL_MCOUNT /* Don't insert the profiling call, it clobbers %eax.  */
+
 ENTRY (__syscall_error)
 	negl %eax
 
diff --git a/sysdeps/unix/sysv/linux/readv.c b/sysdeps/unix/sysv/linux/readv.c
index c8ff55ab45..2c215ce920 100644
--- a/sysdeps/unix/sysv/linux/readv.c
+++ b/sysdeps/unix/sysv/linux/readv.c
@@ -23,6 +23,8 @@
 #include <sys/uio.h>
 
 extern ssize_t __syscall_readv __P ((int, __const struct iovec *, int));
+static ssize_t __atomic_readv_replacement __P ((int, __const struct iovec *,
+						int));
 
 
 /* Not all versions of the kernel support the large number of records.  */
@@ -34,7 +36,7 @@ extern ssize_t __syscall_readv __P ((int, __const struct iovec *, int));
 /* We should deal with kernel which have a smaller UIO_FASTIOV as well
    as a very big count.  */
 ssize_t
-readv (fd, vector, count)
+__readv (fd, vector, count)
      int fd;
      const struct iovec *vector;
      int count;
@@ -44,25 +46,15 @@ readv (fd, vector, count)
 
   bytes_read = __syscall_readv (fd, vector, count);
 
-  if (bytes_read < 0 && errno == EINVAL && count > UIO_FASTIOV)
-    {
-      int i;
+  if (bytes_read >= 0 || errno != EINVAL || count <= UIO_FASTIOV)
+    return bytes_read;
 
-      /* Restore the old error value as if nothing happened.  */
-      __set_errno (errno_saved);
+  /* Restore the old error value as if nothing happened.  */
+  __set_errno (errno_saved);
 
-      bytes_read = 0;
-      for (i = 0; i < count; i += UIO_FASTIOV)
-	{
-	  ssize_t bytes = __syscall_readv (fd, vector + i,
-					   MIN (count - i, UIO_FASTIOV));
-
-	  if (bytes < 0)
-	    return bytes;
-
-	  bytes_read += bytes;
-	}
-    }
-
-  return bytes_read;
+  return __atomic_readv_replacement (fd, vector, count);
 }
+weak_alias (__readv, readv)
+
+#define __readv static __atomic_readv_replacement
+#include <sysdeps/posix/readv.c>
diff --git a/sysdeps/unix/sysv/linux/writev.c b/sysdeps/unix/sysv/linux/writev.c
index d147186b51..31e794fb04 100644
--- a/sysdeps/unix/sysv/linux/writev.c
+++ b/sysdeps/unix/sysv/linux/writev.c
@@ -23,6 +23,9 @@
 #include <sys/uio.h>
 
 extern ssize_t __syscall_writev __P ((int, const struct iovec *, int));
+static ssize_t __atomic_writev_replacement __P ((int, const struct iovec *,
+						 int));
+
 
 /* Not all versions of the kernel support the large number of records.  */
 #ifndef UIO_FASTIOV
@@ -33,7 +36,7 @@ extern ssize_t __syscall_writev __P ((int, const struct iovec *, int));
 /* We should deal with kernel which have a smaller UIO_FASTIOV as well
    as a very big count.  */
 ssize_t
-writev (fd, vector, count)
+__writev (fd, vector, count)
      int fd;
      const struct iovec *vector;
      int count;
@@ -43,23 +46,15 @@ writev (fd, vector, count)
 
   bytes_written = __syscall_writev (fd, vector, count);
 
-  if (bytes_written < 0 && errno == EINVAL && count > UIO_FASTIOV)
-    {
-      int i;
-
-      /* Restore the old error value as if nothing happened.  */
-      __set_errno (errno_saved);
+  if (bytes_written >= 0 || errno != EINVAL || count <= UIO_FASTIOV)
+    return bytes_written;
 
-      bytes_written = 0;
-      for (i = 0; i < count; i += UIO_FASTIOV)
-	{
-	  ssize_t bytes = __syscall_writev (fd, vector + i,
-					    MIN (count - i, UIO_FASTIOV));
+  /* Restore the old error value as if nothing happened.  */
+  __set_errno (errno_saved);
 
-	  if (bytes < 0)
-	    return bytes_written > 0 ? bytes_written : bytes;
-	}
-    }
-
-  return bytes_written;
+  return __atomic_writev_replacement (fd, vector, count);
 }
+weak_alias (__writev, writev)
+
+#define __writev static __atomic_writev_replacement
+#include <sysdeps/posix/writev.c>