summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1998-03-31 18:24:48 +0000
committerUlrich Drepper <drepper@redhat.com>1998-03-31 18:24:48 +0000
commit12264bd7fa8ba6103463c9ca12109a387eeaba37 (patch)
treef8df531c466d4f20ebc5c8d9ad371ae66bcb0e7e
parent4317f9e1377c92493459f2796c37da27c01bccf7 (diff)
Update.
1998-03-31 18:11 Ulrich Drepper <drepper@cygnus.com> * include/mntent.h: New file. * elf/Makefile (trusted-dirs.h): Append slash to filename. * elf/dl-load.c: Rewrite search path handling. * elf/ldsodefs.h (struct r_search_path_elem): Change for rewrite. * elf/rtld.c (process_envvars): Recognize LD_HWCAP_MASK. * sysdeps/generic/dl-sysdep.h (_dl_important_hwcap): New function. * elf/ldsodefs.h: Add prototype.
-rw-r--r--ChangeLog11
-rw-r--r--elf/Makefile2
-rw-r--r--elf/dl-load.c295
-rw-r--r--elf/ldsodefs.h13
-rw-r--r--elf/link.h4
-rw-r--r--elf/rtld.c6
-rw-r--r--include/mntent.h1
-rw-r--r--sysdeps/generic/dl-sysdep.c153
8 files changed, 245 insertions, 240 deletions
diff --git a/ChangeLog b/ChangeLog
index 7b28c906cb..7bac03b434 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+1998-03-31 18:11 Ulrich Drepper <drepper@cygnus.com>
+
+ * include/mntent.h: New file.
+
+ * elf/Makefile (trusted-dirs.h): Append slash to filename.
+ * elf/dl-load.c: Rewrite search path handling.
+ * elf/ldsodefs.h (struct r_search_path_elem): Change for rewrite.
+ * elf/rtld.c (process_envvars): Recognize LD_HWCAP_MASK.
+ * sysdeps/generic/dl-sysdep.h (_dl_important_hwcap): New function.
+ * elf/ldsodefs.h: Add prototype.
+
1998-03-30 Ulrich Drepper <drepper@cygnus.com>
* nss/nsswitch.c (__nss_lookup): Adjust comment.
diff --git a/elf/Makefile b/elf/Makefile
index 106e8631c2..70b0c6a3e2 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -141,7 +141,7 @@ $(objpfx)trusted-dirs.h: Makefile $(..)Makeconfig
$(make-target-directory)
(for dir in `echo "$(default-rpath) $(user-defined-trusted-dirs)" | \
sed 's/:/ /g'`; do \
- echo " \"$$dir\","; \
+ echo " \"$$dir/\","; \
done;) > $@T
mv -f $@T $@
$(objpfx)rtldtbl.h: Makefile $(..)Makeconfig genrtldtbl.awk
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 212b22307a..7d3ff0cc22 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -100,6 +100,11 @@ extern size_t _dl_platformlen;
binaries. */
static struct r_search_path_elem **fake_path_list;
+/* List of the hardware capabilities we might end up using. */
+static const struct r_strlenpair *capstr;
+static size_t ncapstr;
+static size_t max_capstrlen;
+
/* Local version of `strdup' function. */
static inline char *
@@ -119,6 +124,7 @@ local_strdup (const char *s)
be freed if the shared object already has this name.
Returns false if the object already had this name. */
static int
+internal_function
add_name_to_object (struct link_map *l, char *name)
{
struct libname_list *lnp, *lastp;
@@ -156,9 +162,11 @@ add_name_to_object (struct link_map *l, char *name)
return 1;
}
+/* All known directories in sorted order. */
+static struct r_search_path_elem *all_dirs;
-/* Implement cache for search path lookup. */
-#include "rtldtbl.h"
+/* Standard search directories. */
+static struct r_search_path_elem **rtld_search_dirs;
static size_t max_dirnamelen;
@@ -173,6 +181,11 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
{
struct r_search_path_elem *dirp;
size_t len = strlen (cp);
+
+ /* `strsep' can pass an empty string. */
+ if (len == 0)
+ continue;
+
/* Remove trailing slashes. */
while (len > 1 && cp[len - 1] == '/')
--len;
@@ -187,7 +200,8 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
continue;
while (*trun != NULL
- && (memcmp (*trun, cp, len) != 0 || (*trun)[len] != '\0'))
+ && (memcmp (*trun, cp, len) != 0
+ || ((*trun)[len] != '/' && (*trun)[len + 1] != '\0')))
++trun;
if (*trun == NULL)
@@ -201,12 +215,12 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
/* See if this directory is already known. */
for (dirp = all_dirs; dirp != NULL; dirp = dirp->next)
- if (dirp->dirnamelen == len && strcmp (cp, dirp->dirname) == 0)
+ if (dirp->dirnamelen == len && memcmp (cp, dirp->dirname, len) == 0)
break;
if (dirp != NULL)
{
- /* It is available, see whether it's in our own list. */
+ /* It is available, see whether it's on our own list. */
size_t cnt;
for (cnt = 0; cnt < nelems; ++cnt)
if (result[cnt] == dirp)
@@ -217,57 +231,30 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
}
else
{
+ size_t cnt;
+
/* It's a new directory. Create an entry and add it. */
- dirp = (struct r_search_path_elem *) malloc (sizeof (*dirp));
+ dirp = (struct r_search_path_elem *)
+ malloc (sizeof (*dirp) + ncapstr * sizeof (enum r_dir_status));
if (dirp == NULL)
_dl_signal_error (ENOMEM, NULL,
"cannot create cache for search path");
+ dirp->dirname = cp;
dirp->dirnamelen = len;
+
+ if (len > max_dirnamelen)
+ max_dirnamelen = len;
+
/* We have to make sure all the relative directories are never
ignored. The current directory might change and all our
saved information would be void. */
- dirp->dirstatus = cp[0] != '/' ? existing : unknown;
-
- /* Add the name of the machine dependent directory if a machine
- is defined. */
- if (_dl_platform != NULL)
- {
- char *tmp;
-
- dirp->machdirnamelen = len + _dl_platformlen + 1;
- tmp = (char *) malloc (len + _dl_platformlen + 2);
- if (tmp == NULL)
- _dl_signal_error (ENOMEM, NULL,
- "cannot create cache for search path");
- dirp->dirname = tmp;
- tmp = __mempcpy (tmp, cp, len);
- tmp = __mempcpy (tmp, _dl_platform, _dl_platformlen);
- *tmp++ = '/';
- *tmp = '\0';
-
- dirp->machdirstatus = dirp->dirstatus;
-
- if (max_dirnamelen < dirp->machdirnamelen)
- max_dirnamelen = dirp->machdirnamelen;
- }
+ if (cp[0] != '/')
+ for (cnt = 0; cnt < ncapstr; ++cnt)
+ dirp->status[cnt] = existing;
else
- {
- char *tmp;
-
- dirp->machdirnamelen = len;
- dirp->machdirstatus = nonexisting;
-
- tmp = (char *) malloc (len + 1);
- if (tmp == NULL)
- _dl_signal_error (ENOMEM, NULL,
- "cannot create cache for search path");
- dirp->dirname = tmp;
- *((char *) __mempcpy (tmp, cp, len)) = '\0';
-
- if (max_dirnamelen < dirp->dirnamelen)
- max_dirnamelen = dirp->dirnamelen;
- }
+ for (cnt = 0; cnt < ncapstr; ++cnt)
+ dirp->status[cnt] = unknown;
dirp->what = what;
dirp->where = where;
@@ -288,6 +275,7 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
static struct r_search_path_elem **
+internal_function
decompose_rpath (const char *rpath, size_t additional_room,
const char *what, const char *where)
{
@@ -317,13 +305,14 @@ decompose_rpath (const char *rpath, size_t additional_room,
void
_dl_init_paths (const char *llp)
{
- static const char *trusted_dirs[] =
+ static const char *system_dirs[] =
{
#include "trusted-dirs.h"
NULL
};
-
- struct r_search_path_elem **pelem;
+ const char **strp;
+ struct r_search_path_elem *pelem, **aelem;
+ size_t round_size;
/* We have in `search_path' the information about the RPATH of the
dynamic loader. Now fill in the information about the applications
@@ -331,10 +320,6 @@ _dl_init_paths (const char *llp)
variable. */
struct link_map *l;
- /* Names of important hardware capabilities. */
- char **hwcap_names;
- size_t nhwcap_names;
-
/* Number of elements in the library path. */
size_t nllp;
@@ -352,8 +337,47 @@ _dl_init_paths (const char *llp)
nllp = 0;
/* Get the capabilities. */
- hwcap_names = _dl_important_hwcaps (&nhwcap_names,
- _dl_platform, _dl_platformlen);
+ capstr = _dl_important_hwcaps (_dl_platform, _dl_platformlen,
+ &ncapstr, &max_capstrlen);
+
+ /* First set up the rest of the default search directory entries. */
+ aelem = rtld_search_dirs = (struct r_search_path_elem **)
+ malloc ((ncapstr + 1) * sizeof (struct r_search_path_elem *));
+
+ round_size = ((2 * sizeof (struct r_search_path_elem) - 1
+ + ncapstr * sizeof (enum r_dir_status))
+ / sizeof (struct r_search_path_elem));
+
+ rtld_search_dirs[0] = (struct r_search_path_elem *)
+ malloc ((sizeof (system_dirs) / sizeof (system_dirs[0]) - 1)
+ * round_size * sizeof (struct r_search_path_elem));
+ if (rtld_search_dirs[0] == NULL)
+ _dl_signal_error (ENOMEM, NULL, "cannot create cache for search path");
+
+ pelem = all_dirs= rtld_search_dirs[0];
+ for (strp = system_dirs; *strp != NULL; ++strp, pelem += round_size)
+ {
+ size_t cnt;
+
+ *aelem++ = pelem;
+
+ pelem->next = *(strp + 1) == NULL ? NULL : (pelem + round_size);
+
+ pelem->what = "system search path";
+ pelem->where = NULL;
+
+ pelem->dirnamelen = strlen (pelem->dirname = *strp);
+ if (pelem->dirnamelen > max_dirnamelen)
+ max_dirnamelen = pelem->dirnamelen;
+
+ if (pelem->dirname[0] != '/')
+ for (cnt = 0; cnt < ncapstr; ++cnt)
+ pelem->status[cnt] = existing;
+ else
+ for (cnt = 0; cnt < ncapstr; ++cnt)
+ pelem->status[cnt] = unknown;
+ }
+ *aelem = NULL;
l = _dl_loaded;
if (l != NULL)
@@ -391,7 +415,7 @@ _dl_init_paths (const char *llp)
if (nllp > 0)
{
- char *copy = strdupa (llp);
+ char *copy = local_strdup (llp);
/* Decompose the LD_LIBRARY_PATH and fill in the result.
First search for the next place to enter elements. */
@@ -402,7 +426,7 @@ _dl_init_paths (const char *llp)
/* We need to take care that the LD_LIBRARY_PATH environment
variable can contain a semicolon. */
(void) fillin_rpath (copy, result, ":;",
- __libc_enable_secure ? trusted_dirs : NULL,
+ __libc_enable_secure ? system_dirs : NULL,
"LD_LIBRARY_PATH", NULL);
}
}
@@ -424,50 +448,10 @@ _dl_init_paths (const char *llp)
"cannot create cache for search path");
(void) fillin_rpath (local_strdup (llp), fake_path_list, ":;",
- __libc_enable_secure ? trusted_dirs : NULL,
+ __libc_enable_secure ? system_dirs : NULL,
"LD_LIBRARY_PATH", NULL);
}
}
-
- /* Now set up the rest of the rtld_search_dirs. */
- for (pelem = rtld_search_dirs; *pelem != NULL; ++pelem)
- {
- struct r_search_path_elem *relem = *pelem;
-
- if (_dl_platform != NULL)
- {
- char *tmp, *orig;
-
- relem->machdirnamelen = relem->dirnamelen + _dl_platformlen + 1;
- tmp = (char *) malloc (relem->machdirnamelen + 1);
- if (tmp == NULL)
- _dl_signal_error (ENOMEM, NULL,
- "cannot create cache for search path");
-
- orig = tmp;
- tmp = __mempcpy (tmp, relem->dirname, relem->dirnamelen);
- tmp = __mempcpy (tmp, _dl_platform, _dl_platformlen);
- *tmp++ = '/';
- *tmp = '\0';
- relem->dirname = orig;
-
- relem->machdirstatus = unknown;
-
- if (max_dirnamelen < relem->machdirnamelen)
- max_dirnamelen = relem->machdirnamelen;
- }
- else
- {
- relem->machdirnamelen = relem->dirnamelen;
- relem->machdirstatus = nonexisting;
-
- if (max_dirnamelen < relem->dirnamelen)
- max_dirnamelen = relem->dirnamelen;
- }
-
- relem->what = "system search path";
- relem->where = NULL;
- }
}
@@ -844,26 +828,26 @@ static void
print_search_path (struct r_search_path_elem **list,
const char *what, const char *name)
{
+ char buf[max_dirnamelen + max_capstrlen];
+ char *endp;
int first = 1;
_dl_debug_message (1, " search path=", NULL);
while (*list != NULL && (*list)->what == what) /* Yes, ==. */
{
- char *buf = strdupa ((*list)->dirname);
+ char *endp = __mempcpy (buf, (*list)->dirname, (*list)->dirnamelen);
+ size_t cnt;
+
+ for (cnt = 0; cnt < ncapstr; ++cnt)
+ if ((*list)->status[cnt] != nonexisting)
+ {
+ char *cp = __mempcpy (endp, capstr[cnt].str, capstr[cnt].len);
+ cp[-1] = '\0';
+ _dl_debug_message (0, first ? "" : ":", buf, NULL);
+ first = 0;
+ }
- if ((*list)->machdirstatus != nonexisting)
- {
- buf[(*list)->machdirnamelen - 1] = '\0';
- _dl_debug_message (0, first ? "" : ":", buf, NULL);
- first = 0;
- }
- if ((*list)->dirstatus != nonexisting)
- {
- buf[(*list)->dirnamelen - 1] = '\0';
- _dl_debug_message (0, first ? "" : ":", buf, NULL);
- first = 0;
- }
++list;
}
@@ -893,11 +877,12 @@ open_path (const char *name, size_t namelen, int preloaded,
return -1;
}
- buf = __alloca (max_dirnamelen + namelen);
+ buf = __alloca (max_dirnamelen + max_capstrlen + namelen + 1);
do
{
struct r_search_path_elem *this_dir = *dirs;
size_t buflen = 0;
+ size_t cnt;
/* If we are debugging the search for libraries print the path
now if it hasn't happened now. */
@@ -907,95 +892,43 @@ open_path (const char *name, size_t namelen, int preloaded,
print_search_path (dirs, current_what, this_dir->where);
}
- if (this_dir->machdirstatus != nonexisting)
+ for (cnt = 0; fd == -1 && cnt < ncapstr; ++cnt)
{
- /* Construct the pathname to try. */
- buflen = ((char *) __mempcpy (__mempcpy (buf, this_dir->dirname,
- this_dir->machdirnamelen),
- name, namelen)
- - buf);
+ /* Skip this directory if we know it does not exist. */
+ if (this_dir->status[cnt] == nonexisting)
+ continue;
- /* Print name we try if this is wanted. */
+ buflen =
+ ((char *) __mempcpy (__mempcpy (__mempcpy (buf, this_dir->dirname,
+ this_dir->dirnamelen),
+ capstr[cnt].str, capstr[cnt].len),
+ name, namelen)
+ - buf);
+
+ /* Print name we try if this is wanted. */
if (_dl_debug_libs)
_dl_debug_message (1, " trying file=", buf, "\n", NULL);
fd = __open (buf, O_RDONLY);
- if (this_dir->machdirstatus == unknown)
+ if (this_dir->status[cnt] == unknown)
if (fd != -1)
- this_dir->machdirstatus = existing;
+ this_dir->status[cnt] = existing;
else
{
/* We failed to open machine dependent library. Let's
test whether there is any directory at all. */
struct stat st;
- buf[this_dir->machdirnamelen - 1] = '\0';
+ buf[this_dir->dirnamelen + capstr[cnt].len] = '\0';
if (__xstat (_STAT_VER, buf, &st) != 0
|| ! S_ISDIR (st.st_mode))
/* The directory does not exist ot it is no directory. */
- this_dir->machdirstatus = nonexisting;
+ this_dir->status[cnt] = nonexisting;
else
- this_dir->machdirstatus = existing;
+ this_dir->status[cnt] = existing;
}
- if (fd != -1 && preloaded && __libc_enable_secure)
- {
- /* This is an extra security effort to make sure nobody can
- preload broken shared objects which are in the trusted
- directories and so exploit the bugs. */
- struct stat st;
-
- if (__fxstat (_STAT_VER, fd, &st) != 0
- || (st.st_mode & S_ISUID) == 0)
- {
- /* The shared object cannot be tested for being SUID
- or this bit is not set. In this case we must not
- use this object. */
- __close (fd);
- fd = -1;
- /* We simply ignore the file, signal this by setting
- the error value which would have been set by `open'. */
- errno = ENOENT;
- }
- }
- }
- else
- errno = ENOENT;
- if (fd == -1 && errno == ENOENT && this_dir->dirstatus != nonexisting)
- {
- /* Construct the pathname to try. */
- buflen = ((char *) __mempcpy (__mempcpy (buf, this_dir->dirname,
- this_dir->dirnamelen),
- name, namelen)
- - buf);
-
- /* Print name we try if this is wanted. */
- if (_dl_debug_libs)
- _dl_debug_message (1, " trying file=", buf, "\n", NULL);
-
- fd = __open (buf, O_RDONLY);
- if (this_dir->dirstatus == unknown)
- if (fd != -1)
- this_dir->dirstatus = existing;
- else
- /* We failed to open library. Let's test whether there
- is any directory at all. */
- if (this_dir->dirnamelen <= 1)
- this_dir->dirstatus = existing;
- else
- {
- struct stat st;
-
- buf[this_dir->dirnamelen - 1] = '\0';
-
- if (__xstat (_STAT_VER, buf, &st) != 0
- || ! S_ISDIR (st.st_mode))
- /* The directory does not exist ot it is no directory. */
- this_dir->dirstatus = nonexisting;
- else
- this_dir->dirstatus = existing;
- }
if (fd != -1 && preloaded && __libc_enable_secure)
{
/* This is an extra security effort to make sure nobody can
diff --git a/elf/ldsodefs.h b/elf/ldsodefs.h
index 578e085d75..86f23bfb8d 100644
--- a/elf/ldsodefs.h
+++ b/elf/ldsodefs.h
@@ -60,9 +60,12 @@ struct r_search_path_elem
const char *what;
const char *where;
+ /* Basename for this search path element. The string must end with
+ a slash character. */
const char *dirname;
+ size_t dirnamelen;
- enum r_dir_status exists[0];
+ enum r_dir_status status[0];
};
struct r_strlenpair
@@ -137,6 +140,9 @@ extern int _dl_debug_files;
/* Expect cache ID. */
extern int _dl_correct_cache_id;
+/* Mask for important hardware capabilities we honour. */
+extern unsigned long int _dl_hwcap_mask;
+
/* File deccriptor to write debug messages to. */
extern int _dl_debug_fd;
@@ -386,7 +392,10 @@ extern void _dl_show_auxv (void);
extern char *_dl_next_ld_env_entry (char ***position);
/* Return an array with the names of the important hardware capabilities. */
-extern char **_dl_important_hwcap (size_t *sz);
+extern const struct r_strlenpair *_dl_important_hwcaps (const char *platform,
+ size_t paltform_len,
+ size_t *sz,
+ size_t *max_capstrlen);
__END_DECLS
diff --git a/elf/link.h b/elf/link.h
index edf1303595..30efa0ed25 100644
--- a/elf/link.h
+++ b/elf/link.h
@@ -156,10 +156,6 @@ struct link_map
/* Collected information about own RPATH directories. */
struct r_search_path_elem **l_rpath_dirs;
- /* Directory names composed from capability names. */
- struct r_strlenpair *l_capstrs;
- size_t l_ncapstrs;
-
/* Collected results of relocation while profiling. */
ElfW(Addr) *l_reloc_result;
diff --git a/elf/rtld.c b/elf/rtld.c
index dae396ac2d..b07a076b69 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1112,6 +1112,12 @@ process_envvars (enum mode *modep, int *lazyp)
_dl_show_auxv ();
break;
+ case 10:
+ /* mask for the important hardware capabilities. */
+ if (memcmp (&envline[3], "HWCAP_MASK", 10) == 0)
+ _dl_hwcap_mask = strtoul (&envline[14], NULL, 0);
+ break;
+
case 12:
/* Where to place the profiling data file. */
if (memcmp (&envline[3], "DEBUG_OUTPUT", 12) == 0)
diff --git a/include/mntent.h b/include/mntent.h
new file mode 100644
index 0000000000..87a6fb9f2c
--- /dev/null
+++ b/include/mntent.h
@@ -0,0 +1 @@
+#include <misc/mntent.h>
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;
}