summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog27
-rw-r--r--elf/rtld.c174
-rw-r--r--sunrpc/rpc_main.c6
-rw-r--r--sysdeps/generic/hp-timing.h80
-rw-r--r--sysdeps/i386/dl-machine.h2
-rw-r--r--sysdeps/i386/i686/Makefile3
-rw-r--r--sysdeps/i386/i686/hp-timing.c24
-rw-r--r--sysdeps/i386/i686/hp-timing.h160
-rw-r--r--sysdeps/unix/sysv/linux/arm/Dist2
9 files changed, 468 insertions, 10 deletions
diff --git a/ChangeLog b/ChangeLog
index f7b3c0de96..51109f1d58 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,30 @@
+1998-12-27  Ulrich Drepper  <drepper@cygnus.com>
+
+	* elf/dl-lookup.c (_dl_num_relocations): New variable.
+	(do_lookup): Increment _dl_num_relocations for every call.
+	* elf/rtld.c (print_statistics): New function.
+	(_dl_debug_statistics): New variable.  Set when statistics are asked
+	for.
+	(rtld_total_time, relocate_time, load_time): New variables.  Used
+	in print_statistics.
+	(_dl_start): Record start and end time of startup.  Call
+	print_statistics if needed.
+	(dk_main): Record times for relocations and loading.
+	(process_dl_debug): Recognize statistics.
+
+	Low-level, low-overhead, high-precision timing funcationality.
+	* sysdeps/generic/hp-timing.h: New file.
+	* sysdeps/i386/i686/Makefile: New file.
+	* sysdeps/i386/i686/hp-timing.h: New file.
+	* sysdeps/i386/i686/hp-timing.c: New file.
+
+	* sysdeps/i386/dl-machine.h (elf_machine_rel): Reverse order of OR
+	clauses to avoid accessing global variables during rtld relocation.
+
+	* sunrpc/rpc_main.c: Unify messages.
+
+	* sysdeps/unix/sysv/linux/arm/Dist: Add ioperm.c and sys/io.h.
+
 1998-12-27  Roland McGrath  <roland@baalperazim.frob.com>
 
 	* sysdeps/mach/hurd/bits/statfs.h (struct statfs, struct statfs64):
diff --git a/elf/rtld.c b/elf/rtld.c
index 38c7b051b1..df6a945105 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -26,6 +26,7 @@
 #include <stdio-common/_itoa.h>
 #include <entry.h>
 #include <fpu_control.h>
+#include <hp-timing.h>
 #include "dynamic-link.h"
 #include "dl-librecon.h"
 
@@ -58,6 +59,8 @@ static void print_unresolved (int errcode, const char *objname,
 static void print_missing_version (int errcode, const char *objname,
 				   const char *errsting);
 
+/* Print the various times we collected.  */
+static void print_statistics (void);
 
 /* This is a list of all the modes the dynamic loader can be in.  */
 enum mode { normal, list, verify, trace };
@@ -86,6 +89,7 @@ int _dl_debug_symbols;
 int _dl_debug_versions;
 int _dl_debug_reloc;
 int _dl_debug_files;
+int _dl_debug_statistics;
 const char *_dl_inhibit_rpath;		/* RPATH values which should be
 					   ignored.  */
 const char *_dl_origin_path;
@@ -118,6 +122,12 @@ struct link_map _dl_rtld_map;
 struct libname_list _dl_rtld_libname;
 struct libname_list _dl_rtld_libname2;
 
+/* Variable for statistics.  */
+static hp_timing_t rtld_total_time;
+static hp_timing_t relocate_time;
+static hp_timing_t load_time;
+extern unsigned long int _dl_num_relocations;	/* in dl-lookup.c */
+
 #ifdef RTLD_START
 RTLD_START
 #else
@@ -128,6 +138,8 @@ static ElfW(Addr)
 _dl_start (void *arg)
 {
   struct link_map bootstrap_map;
+  hp_timing_t start_time;
+  ElfW(Addr) start_addr;
 
   /* This #define produces dynamic linking inline functions for
      bootstrap relocation instead of general-purpose relocation.  */
@@ -136,6 +148,9 @@ _dl_start (void *arg)
   ((*(sym))->st_shndx == SHN_UNDEF ? 0 : bootstrap_map.l_addr)
 #include "dynamic-link.h"
 
+  if (HP_TIMING_INLINE && HP_TIMING_AVAIL)
+    HP_TIMING_NOW (start_time);
+
   /* Figure out the run-time load address of the dynamic linker itself.  */
   bootstrap_map.l_addr = elf_machine_load_address ();
 
@@ -160,6 +175,16 @@ _dl_start (void *arg)
      the operating system's program loader where to find the program
      header table in core.  */
 
+  if (HP_TIMING_AVAIL)
+    {
+      /* If it hasn't happen yet record the startup time.  */
+      if (! HP_TIMING_INLINE)
+	HP_TIMING_NOW (start_time);
+
+      /* Initialize the timing functions.  */
+      HP_TIMING_DIFF_INIT ();
+    }
+
   /* Transfer data about ourselves to the permanent link_map structure.  */
   _dl_rtld_map.l_addr = bootstrap_map.l_addr;
   _dl_rtld_map.l_ld = bootstrap_map.l_ld;
@@ -176,7 +201,23 @@ _dl_start (void *arg)
      file access.  It will call `dl_main' (below) to do all the real work
      of the dynamic linker, and then unwind our frame and run the user
      entry point on the same stack we entered on.  */
-  return _dl_sysdep_start (arg, &dl_main);
+  start_addr =  _dl_sysdep_start (arg, &dl_main);
+
+  if (HP_TIMING_AVAIL)
+    {
+      hp_timing_t end_time;
+
+      /* Get the current time.  */
+      HP_TIMING_NOW (end_time);
+
+      /* Compute the difference.  */
+      HP_TIMING_DIFF (rtld_total_time, start_time, end_time);
+    }
+
+  if (_dl_debug_statistics)
+    print_statistics ();
+
+  return start_addr;
 }
 
 /* Now life is peachy; we can do all normal operations.
@@ -300,6 +341,9 @@ dl_main (const ElfW(Phdr) *phdr,
   int has_interp = 0;
   unsigned int i;
   int paths_initialized = 0;
+  hp_timing_t start;
+  hp_timing_t stop;
+  hp_timing_t diff;
 
   /* Process the environment variable which control the behaviour.  */
   process_envvars (&mode, &lazy);
@@ -413,7 +457,13 @@ of this helper program; chances are you did not intend to run this program.\n\
 	    }
 	}
       else
-	_dl_map_object (NULL, _dl_argv[0], 0, lt_library, 0);
+	{
+	  HP_TIMING_NOW (start);
+	  _dl_map_object (NULL, _dl_argv[0], 0, lt_library, 0);
+	  HP_TIMING_NOW (stop);
+	  
+	  HP_TIMING_DIFF (load_time, start, stop);
+	}
 
       phdr = _dl_loaded->l_phdr;
       phent = _dl_loaded->l_phnum;
@@ -562,6 +612,9 @@ of this helper program; chances are you did not intend to run this program.\n\
 	 containing a '/' are ignored since it is insecure.  */
       char *list = strdupa (preloadlist);
       char *p;
+
+      HP_TIMING_NOW (start);
+
       while ((p = strsep (&list, " :")) != NULL)
 	if (p[0] != '\0'
 	    && (! __libc_enable_secure || strchr (p, '/') == NULL))
@@ -572,6 +625,10 @@ of this helper program; chances are you did not intend to run this program.\n\
 	      /* It is no duplicate.  */
 	      ++npreloads;
 	  }
+
+      HP_TIMING_NOW (stop);
+      HP_TIMING_DIFF (diff, start, stop);
+      HP_TIMING_ACCUM_NT (load_time, diff);
     }
 
   /* Read the contents of the file.  */
@@ -621,6 +678,8 @@ of this helper program; chances are you did not intend to run this program.\n\
 	  file[file_size - 1] = '\0';
 	}
 
+      HP_TIMING_NOW (start);
+
       if (file != problem)
 	{
 	  char *p;
@@ -646,6 +705,10 @@ of this helper program; chances are you did not intend to run this program.\n\
 	    ++npreloads;
 	}
 
+      HP_TIMING_NOW (stop);
+      HP_TIMING_DIFF (diff, start, stop);
+      HP_TIMING_ACCUM_NT (load_time, diff);
+
       /* We don't need the file anymore.  */
       __munmap (file, file_size);
     }
@@ -668,7 +731,11 @@ of this helper program; chances are you did not intend to run this program.\n\
   /* Load all the libraries specified by DT_NEEDED entries.  If LD_PRELOAD
      specified some libraries to load, these are inserted before the actual
      dependencies in the executable's searchlist for symbol resolution.  */
+  HP_TIMING_NOW (start);
   _dl_map_object_deps (_dl_loaded, preloads, npreloads, mode == trace, 0);
+  HP_TIMING_NOW (stop);
+  HP_TIMING_DIFF (diff, start, stop);
+  HP_TIMING_ACCUM_NT (load_time, diff);
 
   /* Mark all objects as being in the global scope.  */
   for (i = _dl_loaded->l_searchlist.r_nlist; i > 0; )
@@ -884,6 +951,9 @@ of this helper program; chances are you did not intend to run this program.\n\
 
     struct link_map *l;
     int consider_profiling = _dl_profile != NULL;
+    hp_timing_t start;
+    hp_timing_t stop;
+    hp_timing_t add;
 
     /* If we are profiling we also must do lazy reloaction.  */
     lazy |= consider_profiling;
@@ -891,13 +961,19 @@ of this helper program; chances are you did not intend to run this program.\n\
     l = _dl_loaded;
     while (l->l_next)
       l = l->l_next;
+
+    HP_TIMING_NOW (start);
     do
       {
 	if (l != &_dl_rtld_map)
 	  _dl_relocate_object (l, l->l_scope, lazy, consider_profiling);
 
 	l = l->l_prev;
-      } while (l);
+      }
+    while (l);
+    HP_TIMING_NOW (stop);
+
+    HP_TIMING_DIFF (relocate_time, start, stop);
 
     /* Do any necessary cleanups for the startup OS interface code.
        We do these now so that no calls are made after rtld re-relocation
@@ -907,9 +983,15 @@ of this helper program; chances are you did not intend to run this program.\n\
     _dl_sysdep_start_cleanup ();
 
     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_loaded->l_scope, 0, 0);
+      {
+	/* There was an explicit ref to the dynamic linker as a shared lib.
+	   Re-relocate ourselves with user-controlled symbol definitions.  */
+	HP_TIMING_NOW (start);
+	_dl_relocate_object (&_dl_rtld_map, _dl_loaded->l_scope, 0, 0);
+	HP_TIMING_NOW (stop);
+	HP_TIMING_DIFF (add, start, stop);
+	HP_TIMING_ACCUM_NT (relocate_time, add);
+      }
   }
 
   /* Now set up the variable which helps the assembler startup code.  */
@@ -1101,6 +1183,14 @@ a filename can be specified using the LD_DEBUG_OUTPUT environment variable.\n",
 		}
 	      break;
 
+	    case 10:
+	      if (memcmp (dl_debug, "statistics", 10) == 0)
+		{
+		  _dl_debug_statistics = 1;
+		  continue;
+		}
+	      break;
+
 	    default:
 	      break;
 	    }
@@ -1110,6 +1200,7 @@ a filename can be specified using the LD_DEBUG_OUTPUT environment variable.\n",
 	    char *startp = strndupa (dl_debug, len);
 	    _dl_sysdep_error ("warning: debug option `", startp,
 			      "' unknown; try LD_DEBUG=help\n", NULL);
+	    break;
 	  }
 	}
     }
@@ -1291,3 +1382,74 @@ process_envvars (enum mode *modep, int *lazyp)
 
   *modep = mode;
 }
+
+
+/* Print the various times we collected.  */
+static void
+print_statistics (void)
+{
+  char buf[200];
+  char *cp;
+  char *wp;
+
+  /* Total time rtld used.  */
+  if (HP_TIMING_AVAIL)
+    {
+      HP_TIMING_PRINT (buf, sizeof (buf), rtld_total_time);
+      _dl_debug_message (1, "\nruntime linker statistics:\n"
+			 "  total startup time in dynamic loader: ",
+			 buf, "\n", NULL);
+    }
+
+  /* Print relocation statistics.  */
+  if (HP_TIMING_AVAIL)
+    {
+      HP_TIMING_PRINT (buf, sizeof (buf), relocate_time);
+      _dl_debug_message (1, "            time needed for relocation: ", buf,
+			 NULL);
+      cp = _itoa_word ((1000 * relocate_time) / rtld_total_time,
+		       buf + sizeof (buf), 10, 0);
+      wp = buf;
+      switch (buf + sizeof (buf) - cp)
+	{
+	case 3:
+	  *wp++ = *cp++;
+	case 2:
+	  *wp++ = *cp++;
+	case 1:
+	  *wp++ = '.';
+	  *wp++ = *cp++;
+	}
+      *wp = '\0';
+      _dl_debug_message (0, " (", buf, "%)\n", NULL);
+    }
+
+  buf[sizeof (buf) - 1] = '\0';
+  _dl_debug_message (1, "                 number of relocations: ",
+		     _itoa_word (_dl_num_relocations,
+				 buf + sizeof (buf) - 1, 10, 0),
+		     "\n", NULL);
+
+  /* Time spend while loading the object and the dependencies.  */
+  if (HP_TIMING_AVAIL)
+    {
+      HP_TIMING_PRINT (buf, sizeof (buf), load_time);
+      _dl_debug_message (1, "           time needed to load objects: ", buf,
+			 NULL);
+      cp = _itoa_word ((1000 * load_time) / rtld_total_time,
+		       buf + sizeof (buf), 10, 0);
+      wp = buf;
+      switch (buf + sizeof (buf) - cp)
+	{
+	case 3:
+	  *wp++ = *cp++;
+	case 2:
+	  *wp++ = *cp++;
+	case 1:
+	  *wp++ = '.';
+	  *wp++ = *cp++;
+	}
+      *wp = '\0';
+      _dl_debug_message (0, " (", buf, "%)\n", NULL);
+    }
+}
diff --git a/sunrpc/rpc_main.c b/sunrpc/rpc_main.c
index 8302f810c4..2229c564fe 100644
--- a/sunrpc/rpc_main.c
+++ b/sunrpc/rpc_main.c
@@ -459,7 +459,7 @@ check_nettype (const char *name, const char *list_to_check[])
 	  return 1;
 	}
     }
-  fprintf (stderr, _ ("illegal nettype :\'%s\'\n"), name);
+  fprintf (stderr, _ ("illegal nettype :`%s'\n"), name);
   return 0;
 }
 
@@ -1144,7 +1144,7 @@ checkfiles (const char *infile, const char *outfile)
       else
 	{
 	  fprintf (stderr,
-		   _("file '%s' already exists and may be overwritten\n"),
+		   _("file `%s' already exists and may be overwritten\n"),
 		   outfile);
 	  crash ();
 	}
@@ -1411,7 +1411,7 @@ parseargs (int argc, const char *argv[], struct commandline *cmd)
 static void
 usage (void)
 {
-  fprintf (stderr, _("usage:  %s infile\n"), cmdname);
+  fprintf (stderr, _("usage: %s infile\n"), cmdname);
   fprintf (stderr, _("\t%s [-abkCLNTM][-Dname[=value]] [-i size] \
 [-I [-K seconds]] [-Y path] infile\n"), cmdname);
   fprintf (stderr, _("\t%s [-c | -h | -l | -m | -t | -Sc | -Ss | -Sm] \
diff --git a/sysdeps/generic/hp-timing.h b/sysdeps/generic/hp-timing.h
new file mode 100644
index 0000000000..7795f510d5
--- /dev/null
+++ b/sysdeps/generic/hp-timing.h
@@ -0,0 +1,80 @@
+/* High precision, low overhead timing functions.  i686 version.
+   Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+   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.  */
+
+#ifndef _HP_TIMING_H
+#define _HP_TIMING_H	1
+
+
+/* There are no generic definitions for the times.  We could write something
+   using the `gettimeofday' system call where available but the overhead of
+   the system call might be too high.
+
+   In case a platform supports timers in the hardware the following macros
+   and types must be defined:
+
+   - HP_TIMING_AVAIL: test for availability.
+
+   - HP_TIMING_INLINE: this macro is non-zero if the functionality is not
+     implemented using function calls but instead uses some inlined code
+     which might simply consist of a few assembler instructions.  We have to
+     know this since we might want to use the macros here in places where we
+     cannot make function calls.
+
+   - hp_timing_t: This is the type for variables used to store the time
+     values.
+
+   - HP_TIMING_ZERO: clear `hp_timing_t' object.
+
+   - HP_TIMING_NOW: place timestamp for current time in variable given as
+     parameter.
+
+   - HP_TIMING_DIFF_INIT: do whatever is necessary to be able to use the
+     HP_TIMING_DIFF macro.
+
+   - HP_TIMING_DIFF: compute difference between two times and store it
+     in a third.  Source and destination might overlap.
+
+   - HP_TIMING_ACCUM: add time difference to another variable.  This might
+     be a bit more complicated to implement for some platforms as the
+     operation should be thread-safe and 64bit arithmetic on 32bit platforms
+     is not.
+
+   - HP_TIMING_ACCUM_NT: this is the variant for situations where we know
+     there are no threads involved.
+
+   - HP_TIMING_PRINT: write decimal representation of the timing value into
+     the given string.  This operation need not be inline even though
+     HP_TIMING_INLINE is specified.
+
+*/
+
+/* Provide dummy definitions.  */
+#define HP_TIMING_AVAIL		(0)
+#define HP_TIMING_INLINE	(0)
+typedef int hp_timing_t;
+#define HP_TIMING_ZERO(Var)
+#define HP_TIMING_NOW(var)
+#define HP_TIMING_DIFF_INIT()
+#define HP_TIMING_DIFF(Diff, Start, End)
+#define HP_TIMING_ACCUM(Sum, Diff)
+#define HP_TIMING_ACCUM_NT(Sum, Diff)
+#define HP_TIMING_PRINT(Buf, Len, Val)
+
+#endif	/* hp-timing.h */
diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h
index 87d924821a..8338a93617 100644
--- a/sysdeps/i386/dl-machine.h
+++ b/sysdeps/i386/dl-machine.h
@@ -335,7 +335,7 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
 	       found.  */
 	    break;
 	  if (sym->st_size > refsym->st_size
-	      || (_dl_verbose && sym->st_size < refsym->st_size))
+	      || (sym->st_size < refsym->st_size && _dl_verbose))
 	    {
 	      const char *strtab;
 
diff --git a/sysdeps/i386/i686/Makefile b/sysdeps/i386/i686/Makefile
new file mode 100644
index 0000000000..b4b60d0814
--- /dev/null
+++ b/sysdeps/i386/i686/Makefile
@@ -0,0 +1,3 @@
+ifeq ($(subdir),csu)
+sysdep_routines += hp-timing
+endif
diff --git a/sysdeps/i386/i686/hp-timing.c b/sysdeps/i386/i686/hp-timing.c
new file mode 100644
index 0000000000..3f5fcfe1e5
--- /dev/null
+++ b/sysdeps/i386/i686/hp-timing.c
@@ -0,0 +1,24 @@
+/* Support for high precision, low overhead timing functions.  i686 version.
+   Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+   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 <hp-timing.h>
+
+/* We have to define the variable for the overhead.  */
+hp_timing_t __libc_hp_timing_overhead;
diff --git a/sysdeps/i386/i686/hp-timing.h b/sysdeps/i386/i686/hp-timing.h
new file mode 100644
index 0000000000..ffbeb277e5
--- /dev/null
+++ b/sysdeps/i386/i686/hp-timing.h
@@ -0,0 +1,160 @@
+/* High precision, low overhead timing functions.  i686 version.
+   Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+   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.  */
+
+#ifndef _HP_TIMING_H
+#define _HP_TIMING_H	1
+
+#include <string.h>
+#include <sys/param.h>
+#include <stdio-common/_itoa.h>
+
+/* The macros defined here use the timestamp counter in i586 and up versions
+   of the x86 processors.  They provide a very accurate way to measure the
+   time with very little overhead.  The time values themself have no real
+   meaning, only differences are interesting.
+
+   This version is for the i686 processors.  The difference to the i586
+   version is that the timerstamp register is unconditionally used.  This is
+   not the case for the i586 version where we have to perform runtime test
+   whether the processor really has this capability.  We have to make this
+   distinction since the sysdeps/i386/i586 code is supposed to work on all
+   platforms while the i686 already contains i686-specific code.
+
+   The list of macros we need includes the following:
+
+   - HP_TIMING_AVAIL: test for availability.
+
+   - HP_TIMING_INLINE: this macro is non-zero if the functionality is not
+     implemented using function calls but instead uses some inlined code
+     which might simply consist of a few assembler instructions.  We have to
+     know this since we might want to use the macros here in places where we
+     cannot make function calls.
+
+   - hp_timing_t: This is the type for variables used to store the time
+     values.
+
+   - HP_TIMING_ZERO: clear `hp_timing_t' object.
+
+   - HP_TIMING_NOW: place timestamp for current time in variable given as
+     parameter.
+
+   - HP_TIMING_DIFF_INIT: do whatever is necessary to be able to use the
+     HP_TIMING_DIFF macro.
+
+   - HP_TIMING_DIFF: compute difference between two times and store it
+     in a third.  Source and destination might overlap.
+
+   - HP_TIMING_ACCUM: add time difference to another variable.  This might
+     be a bit more complicated to implement for some platforms as the
+     operation should be thread-safe and 64bit arithmetic on 32bit platforms
+     is not.
+
+   - HP_TIMING_ACCUM_NT: this is the variant for situations where we know
+     there are no threads involved.
+
+   - HP_TIMING_PRINT: write decimal representation of the timing value into
+     the given string.  This operation need not be inline even though
+     HP_TIMING_INLINE is specified.
+
+*/
+
+/* We always assume having the timestamp register.  */
+#define HP_TIMING_AVAIL		(1)
+
+/* We indeed have inlined functions.  */
+#define HP_TIMING_INLINE	(1)
+
+/* We use 64bit values for the times.  */
+typedef unsigned long long int hp_timing_t;
+
+/* Internal variabled used to store the overhead of the measurement
+   opcodes.  */
+extern hp_timing_t __libc_hp_timing_overhead;
+
+/* Set timestamp value to zero.  */
+#define HP_TIMING_ZERO(Var)	(Var) = (0)
+
+/* That's quite simple.  Use the `rdtsc' instruction.  Note that the value
+   might not be 100% accurate since there might be some more instructions
+   running in this moment.  This could be changed by using a barrier like
+   'cpuid' right before the `rdtsc' instruciton.  But we are not interested
+   in accurate clock cycles here so we don't do this.  */
+#define HP_TIMING_NOW(Var)	__asm__ __volatile__ ("rdtsc" : "=A" (Var))
+
+/* Use two 'rdtsc' instructions in a row to find out how long it takes.  */
+#define HP_TIMING_DIFF_INIT() \
+  do {									      \
+    int __cnt = 5;							      \
+    __libc_hp_timing_overhead = ~0ull;					      \
+    do									      \
+      {									      \
+	hp_timing_t __t1, __t2;						      \
+	HP_TIMING_NOW (__t1);						      \
+	HP_TIMING_NOW (__t2);						      \
+	if (__t2 - __t1 < __libc_hp_timing_overhead)			      \
+	  __libc_hp_timing_overhead = __t2 - __t1;			      \
+      }									      \
+    while (--__cnt > 0);						      \
+  } while (0)
+
+/* It's simple arithmetic for us.  */
+#define HP_TIMING_DIFF(Diff, Start, End)	(Diff) = ((End) - (Start))
+
+/* We have to jump through hoops to get this correctly implemented.  */
+#define HP_TIMING_ACCUM(Sum, Diff) \
+  do {									      \
+    char __not_done;							      \
+    hp_timing_t __oldval = (Sum);					      \
+    hp_timing_t __diff = (Diff) - __libc_hp_timing_overhead;		      \
+    do									      \
+      {									      \
+	hp_timing_t __newval = __oldval + __diff;			      \
+	int __temp0, __temp1;						      \
+	__asm__ __volatile__ ("xchgl %4, %%ebx\n\t"			      \
+			      "lock; cmpxchg8b %1\n\t"			      \
+			      "sete %0\n\t"				      \
+			      "movl %4, %%ebx"				      \
+			      : "=q" (__not_done), "=m" (Sum),		      \
+				"=A" (__oldval), "=c" (__temp0),	      \
+				"=SD" (__temp1)				      \
+			      : "1" (Sum), "2" (__oldval),		      \
+				"3" (__newval >> 32),			      \
+				"4" (__newval & 0xffffffff)		      \
+			      : "memory");				      \
+      }									      \
+    while (__not_done);							      \
+  } while (0)
+
+/* No threads, no extra work.  */
+#define HP_TIMING_ACCUM_NT(Sum, Diff)	(Sum) += (Diff)
+
+/* Print the time value.  */
+#define HP_TIMING_PRINT(Buf, Len, Val) \
+  do {									      \
+    char __buf[20];							      \
+    char *__cp = _itoa (Val, __buf + sizeof (__buf), 10, 0);		      \
+    int __len = (Len);							      \
+    char *__dest = (Buf);						      \
+    while (__len-- > 0 && __cp < __buf + sizeof (__buf))		      \
+      *__dest++ = *__cp++;						      \
+    memcpy (__dest, " clock cycles", MIN (__len, sizeof (" clock cycles")));  \
+  } while (0)
+
+#endif	/* hp-timing.h */
diff --git a/sysdeps/unix/sysv/linux/arm/Dist b/sysdeps/unix/sysv/linux/arm/Dist
index 18aa31fa9d..479a4abb08 100644
--- a/sysdeps/unix/sysv/linux/arm/Dist
+++ b/sysdeps/unix/sysv/linux/arm/Dist
@@ -1,7 +1,9 @@
 clone.S
 init-first.h
+ioperm.c
 setresuid.c
 setresgid.c
 setfsuid.c
 setfsgid.c
 bits/armsigctx.h
+sys/io.h