about summary refs log tree commit diff
path: root/sysdeps
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps')
-rw-r--r--sysdeps/generic/dl-sysdep.c153
1 files changed, 101 insertions, 52 deletions
diff --git a/sysdeps/generic/dl-sysdep.c b/sysdeps/generic/dl-sysdep.c
index a113c14c42..25a3dd23cd 100644
--- a/sysdeps/generic/dl-sysdep.c
+++ b/sysdeps/generic/dl-sysdep.c
@@ -18,7 +18,10 @@
    Boston, MA 02111-1307, USA.  */
 
 #include <elf.h>
+#include <errno.h>
 #include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -45,7 +48,8 @@ int __libc_enable_secure;
 int __libc_multiple_libcs;	/* Defining this here avoids the inclusion
 				   of init-first.  */
 static ElfW(auxv_t) *_dl_auxv;
-static unsigned long hwcap;
+static unsigned long int hwcap;
+unsigned long int _dl_hwcap_mask = HWCAP_IMPORTANT;
 
 
 #ifndef DL_FIND_ARG_COMPONENTS
@@ -273,18 +277,21 @@ _dl_next_ld_env_entry (char ***position)
 
 /* Return an array of useful/necessary hardware capability names.  */
 const struct r_strlenpair *
-_dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz)
+_dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
+		      size_t *max_capstrlen)
 {
   /* Determine how many important bits are set.  */
-  unsigned long int important = hwcap & HWCAP_IMPORTANT;
+  unsigned long int mask = _dl_hwcap_mask;
   size_t cnt = platform != NULL;
   size_t n, m;
   size_t total;
   struct r_strlenpair *temp;
   struct r_strlenpair *result;
+  struct r_strlenpair *rp;
+  char *cp;
 
-  for (n = 0; (~((1UL << n) - 1) & important) != 0; ++n)
-    if ((important & (1UL << n)) != 0)
+  for (n = 0; (~((1UL << n) - 1) & mask) != 0; ++n)
+    if ((mask & (1UL << n)) != 0)
       ++cnt;
 
   if (cnt == 0)
@@ -298,22 +305,23 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz)
 	  _dl_signal_error (ENOMEM, NULL, "cannot create capability list");
 	}
 
-      result[0]->str = (char *) result;	/* Does not really matter.  */
-      result[0]->len = 0;
+      result[0].str = (char *) result;	/* Does not really matter.  */
+      result[0].len = 0;
 
       *sz = 1;
-      return &only_base;
+      return result;
     }
 
   /* Create temporary data structure to generate result table.  */
   temp = (struct r_strlenpair *) alloca (cnt * sizeof (*temp));
   m = 0;
-  for (n = 0; (~((1UL << n) - 1) & important) != 0; ++n)
-    if ((important & (1UL << n)) != 0)
+  for (n = 0; mask != 0; ++n)
+    if ((mask & (1UL << n)) != 0)
       {
 	temp[m].str = _dl_hwcap_string (n);
 	temp[m].len = strlen (temp[m].str);
-	++m
+	mask ^= 1UL << n;
+	++m;
       }
   if (platform != NULL)
     {
@@ -322,36 +330,37 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz)
       ++m;
     }
 
+  /* Determine the total size of all strings together.  */
   if (cnt == 1)
+    total = temp[0].len;
+  else
     {
-      result = (struct r_strlenpair *) malloc (2 * sizeof (*result)
-					       + temp[0].len + 1);
-      if (result == NULL)
-	goto no_memory;
-
-      result[0].str = (char *) (result + 1);
-      result[0].len = len;
-      result[1].str = (char *) (result + 1);
-      result[1].len = 0;
-      result[0].str[0] = '/';
-      memcpy (&result[0].str[1], temp[0].str, temp[0].len);
-      *sz = 2;
-
-      return result;
+      total = (1 << (cnt - 2)) * (temp[0].len = temp[cnt - 1].len + 2);
+      for (n = 1; n + 1 < cnt; ++n)
+	total += (1 << (cnt - 3)) * (temp[n].len + 1);
     }
 
-  /* Determine the total size of all strings together.  */
-  total = cnt * (temp[0].len + temp[cnt - 1].len + 2);
-  for (n = 1; n + 1 < cnt; ++n)
-    total += 2 * (temp[n].len + 1);
-
   /* The result structure: we use a very compressed way to store the
      various combinations of capability names.  */
-  result = (struct r_strlenpair *) malloc (1 << (cnt - 2) * sizeof (*result)
-					   + total);
+  *sz = 1 << cnt;
+  result = (struct r_strlenpair *) malloc (*sz * sizeof (*result) + total);
   if (result == NULL)
     goto no_memory;
 
+  if (cnt == 1)
+    {
+      result[0].str = (char *) (result + *sz);
+      result[0].len = temp[0].len + 1;
+      result[1].str = (char *) (result + *sz);
+      result[1].len = 0;
+      cp = __mempcpy ((char *) (result + *sz), temp[0].str, temp[0].len);
+      *cp = '/';
+      *sz = 2;
+      *max_capstrlen = result[0].len;
+
+      return result;
+    }
+
   /* Fill in the information.  This follows the following scheme
      (indeces from TEMP for four strings):
 	entry #0: 0, 1, 2, 3	binary: 1111
@@ -360,35 +369,75 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz)
 	      #3: 0, 3		        1001
      This allows to represent all possible combinations of capability
      names in the string.  First generate the strings.  */
-  n = 1 << cnt;
-  cp = result[0].str = (char *) (result + 1 << (cnt - 2));
-  do
-    {
+  result[1].str = result[0].str = cp = (char *) (result + *sz);
 #define add(idx) \
-      cp = __mempcpy (__mempcpy (cp, "/", 1), temp[idx].str, temp[idx].len)
+      cp = __mempcpy (__mempcpy (cp, temp[idx].str, temp[idx].len), "/", 1);
+  if (cnt == 2)
+    {
+      add (1);
+      add (0);
+    }
+  else
+    {
+      n = 1 << cnt;
+      do
+	{
+	  n -= 2;
 
-      n -= 2;
+	  /* We always add the last string.  */
+	  add (cnt - 1);
 
-      /* We always add the last string.  */
-      add (cnt - 1);
+	  /* Add the strings which have the bit set in N.  */
+	  for (m = cnt - 2; m > 0; --m)
+	    if ((n & (1 << m)) != 0)
+	      add (m);
 
-      /* Add the strings which have the bit set in N.  */
-      for (m = cnt - 2; cnt > 0; --cnt)
-	if ((n & (1 << m)) != 0)
-	  add (m);
+	  /* Always add the first string.  */
+	  add (0);
+	}
+      while (n != 0);
+    }
+#undef add
 
-      /* Always add the first string.  */
-      add (0);
+  /* Now we are ready to install the string pointers and length.  */
+  for (n = 0; n < (1 << cnt); ++n)
+    result[n].len = 0;
+  n = cnt;
+  do
+    {
+      size_t mask = 1 << --n;
+
+      rp = result;
+      for (m = 1 << cnt; m > 0; ++rp)
+	if ((--m & mask) != 0)
+	  rp->len += temp[n].len + 1;
     }
   while (n != 0);
 
-  /* Now we are ready to install the string pointers and length.
-     The first string contains all strings.  */
-  result[0].len = 0;
-  for (n = 0; n < cnt; ++n)
-    result[0].len += temp[n].len;
+  /* The first half of the strings all include the first string.  */
+  n = (1 << cnt) - 2;
+  rp = &result[2];
+  while (n != (1 << (cnt - 1)))
+    {
+      if ((n & 1) != 0)
+	rp[0].str = rp[-2].str + rp[-2].len;
+      else
+	rp[0].str = rp[-1].str;
+      ++rp;
+      --n;
+    }
+
+  /* The second have starts right after the first part of the string of
+     corresponding entry in the first half.  */
+  do
+    {
+      rp[0].str = rp[-(1 << (cnt - 1))].str + temp[cnt - 1].len + 1;
+      ++rp;
+    }
+  while (--n != 0);
 
-  I KNOW THIS DOES NOT YET WORK --drepper
+  /* The maximum string length.  */
+  *max_capstrlen = result[0].len;
 
   return result;
 }