aboutsummaryrefslogtreecommitdiff
path: root/sysdeps/generic/dl-cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/generic/dl-cache.c')
-rw-r--r--sysdeps/generic/dl-cache.c275
1 files changed, 139 insertions, 136 deletions
diff --git a/sysdeps/generic/dl-cache.c b/sysdeps/generic/dl-cache.c
index 2ab13d8d3f..28fab0b19e 100644
--- a/sysdeps/generic/dl-cache.c
+++ b/sysdeps/generic/dl-cache.c
@@ -22,31 +22,16 @@
#include <sys/mman.h>
#include <dl-cache.h>
+
/* System-dependent function to read a file's whole contents
in the most convenient manner available. */
extern void *_dl_sysdep_read_whole_file (const char *filename,
size_t *filesize_ptr,
int mmap_prot);
-#ifndef LD_SO_CACHE
-# define LD_SO_CACHE "/etc/ld.so.cache"
-#endif
-
-#define CACHEMAGIC "ld.so-1.7.0"
-
-struct cache_file
- {
- char magic[sizeof CACHEMAGIC - 1];
- unsigned int nlibs;
- struct
- {
- int flags; /* This is 1 for an ELF library. */
- unsigned int key, value; /* String table indices. */
- } libs[0];
- };
-
/* This is the starting address and the size of the mmap()ed file. */
static struct cache_file *cache;
+static struct cache_file_new *cache_new;
static size_t cachesize;
/* 1 if cache_data + PTR points into the cache. */
@@ -56,45 +41,100 @@ static size_t cachesize;
binaries. */
int _dl_correct_cache_id = _DL_CACHE_DEFAULT_ID;
-/* Helper function which must match the one in ldconfig, so that
- we rely on the same sort order. */
-static int
-_dl_cache_libcmp (const char *p1, const char *p2)
-{
- while (*p1 != '\0')
- {
- if (*p1 >= '0' && *p1 <= '9')
- {
- if (*p2 >= '0' && *p2 <= '9')
- {
- /* Must compare this numerically. */
- int val1;
- int val2;
-
- val1 = *p1++ - '0';
- val2 = *p2++ - '0';
- while (*p1 >= '0' && *p1 <= '9')
- val1 = val1 * 10 + *p1++ - '0';
- while (*p2 >= '0' && *p2 <= '9')
- val2 = val2 * 10 + *p2++ - '0';
- if (val1 != val2)
- return val1 - val2;
- }
- else
- return 1;
- }
- else if (*p2 >= '0' && *p2 <= '9')
- return -1;
- else if (*p1 != *p2)
- return *p1 - *p2;
- else
- {
- ++p1;
- ++p2;
- }
- }
- return *p1 - *p2;
-}
+#define SEARCH_CACHE(cache) \
+/* We use binary search since the table is sorted in the cache file. \
+ The first matching entry in the table is returned. \
+ It is important to use the same algorithm as used while generating \
+ the cache file. */ \
+do \
+ { \
+ left = 0; \
+ right = cache->nlibs - 1; \
+ middle = (left + right) / 2; \
+ cmpres = 1; \
+ \
+ while (left <= right) \
+ { \
+ /* Make sure string table indices are not bogus before using \
+ them. */ \
+ if (! _dl_cache_verify_ptr (cache->libs[middle].key)) \
+ { \
+ cmpres = 1; \
+ break; \
+ } \
+ \
+ /* Actually compare the entry with the key. */ \
+ cmpres = _dl_cache_libcmp (name, \
+ cache_data + cache->libs[middle].key); \
+ if (cmpres == 0) \
+ /* Found it. */ \
+ break; \
+ \
+ if (cmpres < 0) \
+ left = middle + 1; \
+ else \
+ right = middle - 1; \
+ \
+ middle = (left + right) / 2; \
+ } \
+ \
+ if (cmpres == 0) \
+ { \
+ /* LEFT now marks the last entry for which we know the name is \
+ correct. */ \
+ left = middle; \
+ \
+ /* There might be entries with this name before the one we \
+ found. So we have to find the beginning. */ \
+ while (middle > 0 \
+ /* Make sure string table indices are not bogus before \
+ using them. */ \
+ && _dl_cache_verify_ptr (cache->libs[middle - 1].key) \
+ /* Actually compare the entry. */ \
+ && (_dl_cache_libcmp (name, \
+ cache_data \
+ + cache->libs[middle - 1].key) \
+ == 0)) \
+ --middle; \
+ \
+ do \
+ { \
+ int flags; \
+ \
+ /* Only perform the name test if necessary. */ \
+ if (middle > left \
+ /* We haven't seen this string so far. Test whether the \
+ index is ok and whether the name matches. Otherwise \
+ we are done. */ \
+ && (! _dl_cache_verify_ptr (cache->libs[middle].key) \
+ || (_dl_cache_libcmp (name, \
+ cache_data \
+ + cache->libs[middle].key) \
+ != 0))) \
+ break; \
+ \
+ flags = cache->libs[middle].flags; \
+ if (_dl_cache_check_flags (flags) \
+ && _dl_cache_verify_ptr (cache->libs[middle].value)) \
+ { \
+ if (best == NULL || flags == _dl_correct_cache_id) \
+ { \
+ HWCAP_CHECK; \
+ best = cache_data + cache->libs[middle].value; \
+ \
+ if (flags == _dl_correct_cache_id) \
+ /* We've found an exact match for the shared \
+ object and no general `ELF' release. Stop \
+ searching. */ \
+ break; \
+ } \
+ } \
+ } \
+ while (++middle <= right); \
+ } \
+ } \
+while (0)
+
/* Look up NAME in ld.so.cache and return the file name stored there,
@@ -117,10 +157,38 @@ _dl_load_cache_lookup (const char *name)
/* Read the contents of the file. */
void *file = _dl_sysdep_read_whole_file (LD_SO_CACHE, &cachesize,
PROT_READ);
+
+ /* We can handle three different cache file formats here:
+ - the old libc5/glibc2.0/2.1 format
+ - the old format with the new format in it
+ - only the new format
+ The following checks if the cache contains any of these formats. */
if (file && cachesize > sizeof *cache &&
!memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1))
- /* Looks ok. */
- cache = file;
+ {
+ /* Looks ok. */
+ cache = file;
+
+ /* Check for new version. */
+ cache_new = (struct cache_file_new *) &cache->libs[cache->nlibs];
+ if (cachesize <
+ (sizeof (struct cache_file) + cache->nlibs * sizeof (struct file_entry)
+ + sizeof (struct cache_file_new))
+ || memcmp (cache_new->magic, CACHEMAGIC_NEW,
+ sizeof CACHEMAGIC_NEW - 1)
+ || memcmp (cache_new->version, CACHE_VERSION,
+ sizeof CACHE_VERSION - 1))
+ cache_new = (void *) -1;
+ }
+ else if (file && cachesize > sizeof *cache_new)
+ {
+ cache_new = (struct cache_file_new *) file;
+ if (memcmp (cache_new->magic, CACHEMAGIC_NEW,
+ sizeof CACHEMAGIC_NEW - 1)
+ || memcmp (cache_new->version, CACHE_VERSION,
+ sizeof CACHE_VERSION - 1))
+ cache_new = (void *) -1;
+ }
else
{
if (file)
@@ -139,88 +207,23 @@ _dl_load_cache_lookup (const char *name)
best = NULL;
- /* We use binary search since the table is sorted in the cache file.
- It is important to use the same algorithm as used while generating
- the cache file. */
- left = 0;
- right = cache->nlibs - 1;
- middle = (left + right) / 2;
- cmpres = 1;
-
- while (left <= right)
+ if (cache_new != (void *) -1)
{
- /* Make sure string table indices are not bogus before using them. */
- if (! _dl_cache_verify_ptr (cache->libs[middle].key))
- {
- cmpres = 1;
- break;
- }
+ /* This file ends in static libraries where we don't have a hwcap. */
+ unsigned long int *hwcap;
+ weak_extern (_dl_hwcap);
- /* Actually compare the entry with the key. */
- cmpres = _dl_cache_libcmp (name, cache_data + cache->libs[middle].key);
- if (cmpres == 0)
- /* Found it. */
- break;
+ hwcap = &_dl_hwcap;
- if (cmpres < 0)
- left = middle + 1;
- else
- right = middle - 1;
-
- middle = (left + right) / 2;
- }
-
- if (cmpres == 0)
- {
- /* LEFT now marks the last entry for which we know the name is
- correct. */
- left = middle;
-
- /* There might be entries with this name before the one we
- found. So we have to find the beginning. */
- while (middle > 0
- /* Make sure string table indices are not bogus before
- using them. */
- && _dl_cache_verify_ptr (cache->libs[middle - 1].key)
- /* Actually compare the entry. */
- && (_dl_cache_libcmp (name,
- cache_data + cache->libs[middle - 1].key)
- == 0))
- --middle;
-
- do
- {
- int flags;
-
- /* Only perform the name test if necessary. */
- if (middle > left
- /* We haven't seen this string so far. Test whether the
- index is ok and whether the name matches. Otherwise
- we are done. */
- && (! _dl_cache_verify_ptr (cache->libs[middle].key)
- || (_dl_cache_libcmp (name,
- cache_data + cache->libs[middle].key)
- != 0)))
- break;
-
- flags = cache->libs[middle].flags;
- if (_dl_cache_check_flags (flags)
- && _dl_cache_verify_ptr (cache->libs[middle].value))
- {
- if (best == NULL || flags == _dl_correct_cache_id)
- {
- best = cache_data + cache->libs[middle].value;
-
- if (flags == _dl_correct_cache_id)
- /* We've found an exact match for the shared
- object and no general `ELF' release. Stop
- searching. */
- break;
- }
- }
- }
- while (++middle <= right);
+#define HWCAP_CHECK \
+ if (hwcap && (cache_new->libs[middle].hwcap & *hwcap) > _dl_hwcap) \
+ continue
+ SEARCH_CACHE (cache_new);
}
+ else
+#undef HWCAP_CHECK
+#define HWCAP_CHECK do {} while (0)
+ SEARCH_CACHE (cache);
/* Print our result if wanted. */
if (_dl_debug_libs && best != NULL)