Browse Source

This patch from Mike Frysinger, extended from an earlier patch from Peter S.
Mazinger implements the changes suggested by me on the uclibc list.

On Tuesday 28 September 2004 02:24 pm, Erik Andersen wrote:
> What I think should be done is
>
> *) Someone that cares about USE_CACHE should fix that option
> up to be sure it works, and give it a proper config entry
> in extra/Configs/Config.in, and rename it to something
> more appropriate such as LDSO_CACHE_SUPPORT.
>
> *) When LDSO_CACHE_SUPPORT=n, UCLIBC_RUNTIME_PREFIX /usr/X11R6/lib
> should be included in the default library search path in
> dl-elf.c, ldd, and ldconfig.
>
> *) When LDSO_CACHE_SUPPORT=y, UCLIBC_RUNTIME_PREFIX /usr/X11R6/lib
> should be excluded from the default library search path in
> dl-elf.c, ldd, and ldconfig, and those wishing to include
> X11 stuff should add that into /etc/ld.so.conf and re-run
> ldconfig.
>
> *) At present, LDSO_CONF and LDSO_CACHE use the same names
> and same structure as glibc. This precludes
> LDSO_CACHE_SUPPORT being uses in any sane fashion on a
> dial glibc and uClibc system. Just as it was necessary
> for use to use a different name for 'libuClibc' rather
> than 'libc', and 'ld-uClibc.so.0' rather than
> 'ld-linux.so.2' it seems that these configuration files
> really ought to be given different names.
>

Eric Andersen 19 years ago
parent
commit
3b8039fd51
11 changed files with 194 additions and 25 deletions
  1. 0 1
      Rules.mak
  2. 25 0
      extra/Configs/Config.in
  3. 5 10
      ldso/include/dl-elf.h
  4. 1 1
      ldso/ldso/Makefile
  5. 5 2
      ldso/ldso/dl-elf.c
  6. 1 1
      ldso/libdl/Makefile
  7. 1 1
      ldso/libdl/libdl.c
  8. 1 1
      utils/Makefile
  9. 34 0
      utils/dl-cache.h
  10. 12 5
      utils/ldconfig.c
  11. 109 3
      utils/ldd.c

+ 0 - 1
Rules.mak

@@ -247,7 +247,6 @@ ifneq ($(DOASSERTS),y)
 endif
 
 ifeq ($(HAVE_SHARED),y)
-    LIBRARY_CACHE:=#-DUSE_CACHE
     ifeq ($(BUILD_UCLIBC_LDSO),y)
 	LDSO:=$(TOPDIR)lib/$(UCLIBC_LDSO)
 	DYNAMIC_LINKER:=$(SHARED_LIB_LOADER_PREFIX)/$(UCLIBC_LDSO)

+ 25 - 0
extra/Configs/Config.in

@@ -200,6 +200,7 @@ config FORCE_SHAREABLE_TEXT_SEGMENTS
 
 config UCLIBC_PIE_SUPPORT
 	bool "Support ET_DYN in shared library loader"
+	depends on BUILD_UCLIBC_LDSO
 	select FORCE_SHAREABLE_TEXT_SEGMENTS
 	default n
 	help
@@ -223,6 +224,30 @@ config LDSO_LDD_SUPPORT
 	  application to function.  Disabling this option will makes uClibc's
 	  shared library loader a little bit smaller.  Most people will answer Y.
 
+config LDSO_CACHE_SUPPORT
+	bool "Enable shared library loader cache"
+	depends on BUILD_UCLIBC_LDSO
+	default y
+	help
+	  Enable this to make use of /etc/ld.so.conf, the shared library loader
+	  cache configuration file to support for non-standard library paths.
+	  After updating this file, it is necessary to run 'ldconfig' to update
+	  the /etc/ld.so.cache shared library loader cache file.
+
+config LDSO_BASE_FILENAME
+	string "Shared library loader cache naming prefix"
+	depends on LDSO_CACHE_SUPPORT
+	default "ld.so"
+	help
+	  If you wish to support both uClibc and glibc on the same system, it
+	  is necessary to set this to something other than "ld.so" to avoid
+	  conflicts with glibc, which also uses "ld.so".  This prevents both
+	  libraries from using the same /etc/ld.so.cache file.  If you wish to
+	  support both uClibc and glibc on the same system then you should set
+	  this to "ld-uClibc.so".
+
+	  Most people will leave this set to the default of "ld.so".
+
 config UCLIBC_CTOR_DTOR
 	bool "Support global constructors and destructors"
 	default y

+ 5 - 10
ldso/include/dl-elf.h

@@ -5,15 +5,10 @@
 #include <elf.h>
 #include <link.h>
 
-#ifdef DEBUG
-#  define LDSO_CONF  "../util/ld.so.conf"
-#  define LDSO_CACHE "../util/ld.so.cache"
-#  define LDSO_PRELOAD "../util/ld.so.preload"
-#else
-#  define LDSO_CONF  UCLIBC_RUNTIME_PREFIX "etc/ld.so.conf"
-#  define LDSO_CACHE UCLIBC_RUNTIME_PREFIX "etc/ld.so.cache"
-#  define LDSO_PRELOAD UCLIBC_RUNTIME_PREFIX "etc/ld.so.preload"
-#endif
+#define LDSO_BASE_PATH UCLIBC_RUNTIME_PREFIX "etc/" __LDSO_BASE_FILENAME__
+#define LDSO_CONF    LDSO_BASE_PATH ".conf"
+#define LDSO_CACHE   LDSO_BASE_PATH ".cache"
+#define LDSO_PRELOAD LDSO_BASE_PATH ".preload"
 
 
 #define LIB_ANY	     -1
@@ -30,7 +25,7 @@ struct elf_resolve;
 
 
 /* Definitions and prototypes for cache stuff */
-#ifdef USE_CACHE
+#ifdef __LDSO_CACHE_SUPPORT__
 extern int _dl_map_cache(void);
 extern int _dl_unmap_cache(void);
 

+ 1 - 1
ldso/ldso/Makefile

@@ -23,7 +23,7 @@ LDSO_FULLNAME=ld-uClibc-$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBLEVEL).so
 
 SSPFLAGS=$(call check_gcc,-fno-stack-protector,)
 
-XXFLAGS=$(XWARNINGS) $(LIBRARY_CACHE) $(SSPFLAGS)
+XXFLAGS=$(XWARNINGS) $(SSPFLAGS)
 ifeq ($(DODEBUG),y)
 # Not really much point in including debugging info, since gdb
 # can't really debug ldso, since gdb requires help from ldso to

+ 5 - 2
ldso/ldso/dl-elf.c

@@ -32,7 +32,7 @@
 
 #include "ldso.h"
 
-#ifdef USE_CACHE
+#ifdef __LDSO_CACHE_SUPPORT__
 
 static caddr_t _dl_cache_addr = NULL;
 static size_t _dl_cache_size = 0;
@@ -317,7 +317,7 @@ struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt,
 	 * ABI, so we have some flexibility here.  For now, search it before
 	 * the hard coded paths that follow (i.e before /lib and /usr/lib).
 	 */
-#ifdef USE_CACHE
+#ifdef __LDSO_CACHE_SUPPORT__
 	if (_dl_cache_addr != NULL && _dl_cache_addr != (caddr_t) - 1) {
 		int i;
 		header_t *header = (header_t *) _dl_cache_addr;
@@ -358,6 +358,9 @@ struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt,
 	if ((tpnt1 = search_for_named_library(libname, secure,
 					UCLIBC_RUNTIME_PREFIX "lib:"
 					UCLIBC_RUNTIME_PREFIX "usr/lib"
+#if !defined (__LDSO_CACHE_SUPPORT__)
+					":" UCLIBC_RUNTIME_PREFIX "usr/X11R6/lib"
+#endif
 					, rpnt)
 		) != NULL)
 	{

+ 1 - 1
ldso/libdl/Makefile

@@ -21,7 +21,7 @@
 TOPDIR=../../
 include $(TOPDIR)Rules.mak
 
-XXFLAGS=$(XWARNINGS) $(LIBRARY_CACHE)
+XXFLAGS=$(XWARNINGS)
 ifeq ($(DODEBUG),y)
 XXFLAGS+=-O0 -g3
 else

+ 1 - 1
ldso/libdl/libdl.c

@@ -54,7 +54,7 @@ extern struct elf_resolve *_dl_loaded_modules __attribute__ ((__weak__));
 extern struct r_debug *_dl_debug_addr __attribute__ ((__weak__));
 extern unsigned long _dl_error_number __attribute__ ((__weak__));
 extern void *(*_dl_malloc_function)(size_t) __attribute__ ((__weak__));
-#ifdef USE_CACHE
+#ifdef __LDSO_CACHE_SUPPORT__
 int _dl_map_cache(void) __attribute__ ((__weak__));
 int _dl_unmap_cache(void) __attribute__ ((__weak__));
 #endif

+ 1 - 1
utils/Makefile

@@ -29,7 +29,7 @@ else
 TARGET_ICONV =
 endif
 
-XXFLAGS=$(LIBRARY_CACHE)
+XXFLAGS=
 ifeq ($(strip $(LDSO_LDD_SUPPORT)),y)
 XXFLAGS+= -D__LDSO_LDD_SUPPORT
 endif

+ 34 - 0
utils/dl-cache.h

@@ -0,0 +1,34 @@
+#define LDSO_BASE_PATH UCLIBC_RUNTIME_PREFIX "etc/" __LDSO_BASE_FILENAME__
+#define LDSO_CONF    LDSO_BASE_PATH ".conf"
+#define LDSO_CACHE   LDSO_BASE_PATH ".cache"
+#define LDSO_PRELOAD LDSO_BASE_PATH ".preload"
+
+#define LIB_ANY	     -1
+#define LIB_DLL       0
+#define LIB_ELF       1
+#define LIB_ELF64     0x80
+#define LIB_ELF_LIBC5 2
+#define LIB_ELF_LIBC6 3
+#define LIB_ELF_LIBC0 4
+
+/* Definitions and prototypes for cache stuff */
+#ifdef __LDSO_CACHE_SUPPORT__
+
+#define LDSO_CACHE_MAGIC "ld.so-"
+#define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
+#define LDSO_CACHE_VER "1.7.0"
+#define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1)
+
+typedef struct {
+	char magic   [LDSO_CACHE_MAGIC_LEN];
+	char version [LDSO_CACHE_VER_LEN];
+	int nlibs;
+} header_t;
+
+typedef struct {
+	int flags;
+	int sooffset;
+	int liboffset;
+} libentry_t;
+
+#endif

+ 12 - 5
utils/ldconfig.c

@@ -503,7 +503,7 @@ void scan_dir(const char *rawname)
     {
 	if (!lp->islink)
 	    link_shlib(name, lp->name, lp->so);
-#ifdef USE_CACHE
+#ifdef __LDSO_CACHE_SUPPORT__
 	if (!nocache)
 	    cache_dolib(name, lp->so, lp->libtype);
 #endif
@@ -553,7 +553,7 @@ char *get_extpath(void)
     return res;
 }
 
-#ifdef USE_CACHE
+#ifdef __LDSO_CACHE_SUPPORT__
 typedef struct liblist
 {
     int flags;
@@ -876,6 +876,9 @@ int main(int argc, char **argv)
 	{
 	    scan_dir(UCLIBC_RUNTIME_PREFIX "lib");
 	    scan_dir(UCLIBC_RUNTIME_PREFIX "usr/lib");
+#if !defined (__LDSO_CACHE_SUPPORT__)
+	    scan_dir(UCLIBC_RUNTIME_PREFIX "usr/X11R6/lib");
+#endif
 
 	    /* I guess the defaults aren't good enough */
 	    if ((extpath = get_extpath()))
@@ -886,8 +889,12 @@ int main(int argc, char **argv)
 			if (len) 
 				while (cp[--len] == '/' && len)
 					cp[len] = 0;
-			if (strcmp(UCLIBC_RUNTIME_PREFIX "lib", cp) == 0 ||
-			    strcmp(UCLIBC_RUNTIME_PREFIX "usr/lib", cp) == 0) {
+			if (strcmp(UCLIBC_RUNTIME_PREFIX "lib", cp) == 0
+			    || strcmp(UCLIBC_RUNTIME_PREFIX "usr/lib", cp) == 0
+#if !defined (__LDSO_CACHE_SUPPORT__)
+			    || strcmp(UCLIBC_RUNTIME_PREFIX "usr/X11R6/lib", cp) == 0
+#endif
+			    ) {
 				if (verbose >= 0)
 					warnx("Path `%s' given more than once\n", cp);
 				continue;
@@ -898,7 +905,7 @@ int main(int argc, char **argv)
 	    }
 	}
 
-#ifdef USE_CACHE
+#ifdef __LDSO_CACHE_SUPPORT__
 	if (!nocache)
 	    cache_write();
 #endif

+ 109 - 3
utils/ldd.c

@@ -45,6 +45,7 @@
 #else
 #include "elf.h"
 #endif
+#include "dl-cache.h"
 
 #ifdef DMALLOC
 #include <dmalloc.h>
@@ -229,6 +230,89 @@ int check_elf_header(Elf32_Ehdr *const ehdr)
 	return 0;
 }
 
+#ifdef __LDSO_CACHE_SUPPORT__
+static caddr_t cache_addr = NULL;
+static size_t cache_size = 0;
+
+int map_cache(void)
+{
+	int fd;
+	struct stat st;
+	header_t *header;
+	libentry_t *libent;
+	int i, strtabsize;
+
+	if (cache_addr == (caddr_t) - 1)
+		return -1;
+	else if (cache_addr != NULL)
+		return 0;
+
+	if (stat(LDSO_CACHE, &st)
+			|| (fd = open(LDSO_CACHE, O_RDONLY, 0)) < 0) {
+		dprintf(2, "ldd: can't open cache '%s'\n", LDSO_CACHE);
+		cache_addr = (caddr_t) - 1;	/* so we won't try again */
+		return -1;
+	}
+
+	cache_size = st.st_size;
+	cache_addr = (caddr_t) mmap(0, cache_size, PROT_READ, MAP_SHARED, fd, 0);
+	close(fd);
+	if (cache_addr == MAP_FAILED) {
+		dprintf(2, "ldd: can't map cache '%s'\n", LDSO_CACHE);
+		return -1;
+	}
+
+	header = (header_t *) cache_addr;
+
+	if (cache_size < sizeof(header_t) ||
+			memcmp(header->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN)
+			|| memcmp(header->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN)
+			|| cache_size <
+			(sizeof(header_t) + header->nlibs * sizeof(libentry_t))
+			|| cache_addr[cache_size - 1] != '\0')
+	{
+		dprintf(2, "ldd: cache '%s' is corrupt\n", LDSO_CACHE);
+		goto fail;
+	}
+
+	strtabsize = cache_size - sizeof(header_t) -
+		header->nlibs * sizeof(libentry_t);
+	libent = (libentry_t *) & header[1];
+
+	for (i = 0; i < header->nlibs; i++) {
+		if (libent[i].sooffset >= strtabsize ||
+				libent[i].liboffset >= strtabsize)
+		{
+			dprintf(2, "ldd: cache '%s' is corrupt\n", LDSO_CACHE);
+			goto fail;
+		}
+	}
+
+	return 0;
+
+fail:
+	munmap(cache_addr, cache_size);
+	cache_addr = (caddr_t) - 1;
+	return -1;
+}
+
+int unmap_cache(void)
+{
+	if (cache_addr == NULL || cache_addr == (caddr_t) - 1)
+		return -1;
+
+#if 1
+	munmap(cache_addr, cache_size);
+	cache_addr = NULL;
+#endif
+
+	return 0;
+}
+#else
+static inline void map_cache(void) { }
+static inline void unmap_cache(void) { }
+#endif
+
 /* This function's behavior must exactly match that
  * in uClibc/ldso/ldso/dl-elf.c */
 static void search_for_named_library(char *name, char *result, const char *path_list)
@@ -320,8 +404,23 @@ void locate_library_file(Elf32_Ehdr* ehdr, Elf32_Dyn* dynamic, int is_suid, stru
 		}
 	}
 
-#ifdef USE_CACHE
-	/* FIXME -- add code to check the Cache here */
+#ifdef __LDSO_CACHE_SUPPORT__
+	if (cache_addr != NULL && cache_addr != (caddr_t) - 1) {
+		int i;
+		header_t *header = (header_t *) cache_addr;
+		libentry_t *libent = (libentry_t *) & header[1];
+		char *strs = (char *) &libent[header->nlibs];
+
+		for (i = 0; i < header->nlibs; i++) {
+			if ((libent[i].flags == LIB_ELF ||
+			    libent[i].flags == LIB_ELF_LIBC0 ||
+			    libent[i].flags == LIB_ELF_LIBC5) &&
+			    strcmp(lib->name, strs + libent[i].sooffset) == 0) {
+				lib->path = strdup(strs + libent[i].liboffset);
+				return;
+			}
+		}
+	}
 #endif
 
 
@@ -339,7 +438,11 @@ void locate_library_file(Elf32_Ehdr* ehdr, Elf32_Dyn* dynamic, int is_suid, stru
 	/* Lastly, search the standard list of paths for the library.
 	   This list must exactly match the list in uClibc/ldso/ldso/dl-elf.c */
 	path =	UCLIBC_RUNTIME_PREFIX "lib:"
-		UCLIBC_RUNTIME_PREFIX "usr/lib";
+		UCLIBC_RUNTIME_PREFIX "usr/lib"
+#if !defined (__LDSO_CACHE_SUPPORT__)
+		":" UCLIBC_RUNTIME_PREFIX "usr/X11R6/lib"
+#endif
+		;
 	search_for_named_library(lib->name, buf, path);
 	if (*buf != '\0') {
 		lib->path = buf;
@@ -644,6 +747,8 @@ int main( int argc, char** argv)
 			printf("%s:\n", *argv);
 		}
 
+		map_cache();
+
 		if (find_dependancies(filename)!=0)
 			continue;
 
@@ -660,6 +765,7 @@ int main( int argc, char** argv)
 			}
 		}
 
+		unmap_cache();
 
 		/* Print the list */
 		got_em_all=0;