From 0a54e4010fe0085cd36deaff9442a7e88de3270d Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Sat, 26 Jul 1997 02:33:30 +0000 Subject: Update. 1997-07-26 04:14 Ulrich Drepper * elf/Makefile (distribute): Add genrtldtbl.awk. (before-compile): Add rtldtbl.h. (GAWK): New variable. (generated): Add trusted-dirs.h and rtldtbl.h. ($(objpfx)rtldtbl.h): New rule. File is needed by dl-load.c. * elf/dl-load.c: Rewrite. Now use cache and look for shared objects in machine dependent directories. * elf/dl-object.c (_dl_new_object): Initialize l_rpath_dirs member. * elf/dl-support.c: Rename function to non_dynamic_init and add initialization for _dl_platform, _dl_platformlen, _dl_pagesize and call to initializer for search path. * elf/elf.h: Add AT_PLATFORM and AT_HWCAP. * elf/genrtldtbl.awk: New file. * elf/link.h: Add type definitions and declarations for search path cache. * elf/rtld.c: Add definitions of variables used for search path cache. * sysdeps/generic/dl-sysdep.c: Let auxiliary vector initialize _dl_platform. Initialize _dl_pagesize early and use this value. * sysdeps/i386/dl-machine.h: Add code for _dl_platform handling. * sysdeps/mach/hurd/dl-sysdep.c: Initialize _dl_pagesize. * sysdeps/unix/sysv/linux/dl-sysdep.c: Use _dl_pagesize instead of calling getpagesize. * elf/dl-error.c (_dl_signal_error): Make message nicer. * nss/libnss_files.map: Fix typo. Reported by Thorsten Kukuk . * sysdeps/generic/strsep.c: Optimize case where separator set contains only one character. * sysdeps/libm-ieee754/s_ccosh.c: Correct sign of result for real == +-Inf. * sysdeps/libm-ieee754/s_ccoshf.c: Likewise. * sysdeps/libm-ieee754/s_ccoshl.c: Likewise. 1997-07-25 09:15 H.J. Lu * sysdeps/sparc/udiv_qrnnd.S: Check PIC instead of __PIC__. * sysdeps/unix/sysv/linux/sparc/__sigtrampoline.S: Likewise. * sysdeps/unix/mips/sysdep.S: Likewise. * sysdeps/unix/sysv/linux/mips/clone.S: Likewise. * sysdeps/mips/bsd-_setjmp.S: Remove __PIC__ comment. * sysdeps/mips/bsd-setjmp.S: Likewise. * sysdeps/mips/dl-machine.h: Remove extra stuff. * sysdeps/mips/mips64/dl-machine.h: Likewise. 1997-07-25 18:55 Philip Blundell * sysdeps/standalone/arm/sysdep.c: New file. 1997-07-25 13:25 Philip Blundell * aout/Makefile: New file. * Makeconfig (binfmt-subdir): Assume a.out when not ELF. * sysdeps/generic/machine-gmon.h: Add warning about limitations of __builtin_return_address(). * sysdeps/arm/machine-gmon.h: New file, use assembly to avoid above problem. 1997-07-25 16:24 H.J. Lu * elf/dl-deps.c (_dl_map_object_deps): Fix a typo. 1997-07-22 Andreas Schwab * math/libm-test.c (ccos_test, ccosh_test): Fix sign in some tests. 1997-07-24 Andreas Schwab * sunrpc/clnt_udp.c (clntudp_call): Rename cu_wait from timeout to not shadow the variable in the outer scope. --- elf/Makefile | 13 +- elf/dl-deps.c | 9 +- elf/dl-error.c | 2 +- elf/dl-load.c | 465 ++++++++++++++++++++++++++++++++++++++++++----------- elf/dl-object.c | 1 + elf/dl-support.c | 31 +++- elf/elf.h | 5 + elf/genrtldtbl.awk | 28 ++++ elf/link.h | 26 +++ elf/rtld.c | 7 + 10 files changed, 482 insertions(+), 105 deletions(-) create mode 100644 elf/genrtldtbl.awk (limited to 'elf') diff --git a/elf/Makefile b/elf/Makefile index 269a872969..e44711471b 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -35,15 +35,18 @@ elide-routines.so = $(dl-routines) dl-support enbl-secure # interpreter and operating independent of libc. rtld-routines := rtld $(dl-routines) dl-sysdep dl-minimal distribute = $(rtld-routines:=.c) dynamic-link.h do-rel.h dl-machine.h \ - dl-hash.h soinit.c sofini.c ldd.sh.in ldd.bash.in eval.c + dl-hash.h soinit.c sofini.c ldd.sh.in ldd.bash.in eval.c \ + genrtldtbl.awk extra-libs = libdl extra-libs-others = $(extra-libs) libdl-routines := dlopen dlclose dlsym dlvsym dlerror dladdr libdl-map := libdl.map -before-compile = $(objpfx)trusted-dirs.h +before-compile = $(objpfx)trusted-dirs.h $(objpfx)rtldtbl.h +# We need GNU awk for the genrtldtbl.awk script. +GAWK = gawk all: # Make this the default target; it will be defined in Rules. @@ -51,7 +54,7 @@ include ../Makeconfig ifeq (yes,$(build-shared)) extra-objs = $(rtld-routines:=.so) soinit.so sofini.so eval.so -generated = librtld.so dl-allobjs.so +generated = librtld.so dl-allobjs.so trusted-dirs.h rtldtbl.h install-others = $(inst_slibdir)/$(rtld-installed-name) install-bin = ldd endif @@ -143,6 +146,10 @@ $(objpfx)trusted-dirs.h: Makefile echo " \"$$dir\","; \ done;) > $@T mv -f $@T $@ +$(objpfx)rtldtbl.h: Makefile + $(make-target-directory) + echo "$(default-rpath)" | $(GAWK) -f genrtldtbl.awk > $@T + mv -f $@T $@ CPPFLAGS-dl-load.c = -I$(objdir)/$(subdir) CFLAGS-dl-load.c += -Wno-uninitialized diff --git a/elf/dl-deps.c b/elf/dl-deps.c index 36f5ee0606..e990d6965b 100644 --- a/elf/dl-deps.c +++ b/elf/dl-deps.c @@ -57,12 +57,9 @@ openaux (void *a) -/* We use a very special kind of list to track the three kinds paths +/* We use a very special kind of list to track the two kinds paths through the list of loaded shared objects. We have to - - go through all objects in the correct order, which includes the - possible recursive loading of auxiliary objects and dependencies - - produce a flat list with unique members of all involved objects - produce a flat list of all shared objects. @@ -141,7 +138,7 @@ _dl_map_object_deps (struct link_map *map, { struct link_map *l = runp->map; - if (runp->done == 0 && (l->l_info[AUXTAG] || l->l_info[DT_NEEDED])) + if (l->l_info[AUXTAG] || l->l_info[DT_NEEDED]) { const char *strtab = ((void *) l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr); @@ -371,6 +368,6 @@ _dl_map_object_deps (struct link_map *map, "cannot allocate symbol search list"); for (nlist = 0, runp = head; runp; runp = runp->dup) - map->l_searchlist[nlist++] = runp->map; + map->l_dupsearchlist[nlist++] = runp->map; } } diff --git a/elf/dl-error.c b/elf/dl-error.c index e2565bb348..7ee803ad9b 100644 --- a/elf/dl-error.c +++ b/elf/dl-error.c @@ -75,7 +75,7 @@ _dl_signal_error (int errcode, /* Lossage while resolving the program's own symbols is always fatal. */ extern char **_dl_argv; /* Set in rtld.c at startup. */ _dl_sysdep_fatal (_dl_argv[0] ?: "", - ": error in loading shared libraries\n", + ": error in loading shared libraries", objname ?: "", objname ? ": " : "", errstring, errcode ? ": " : "", errcode ? strerror (errcode) : "", "\n", NULL); diff --git a/elf/dl-load.c b/elf/dl-load.c index 87859219f1..1301e73996 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -1,4 +1,4 @@ -/* _dl_map_object -- Map in a shared object's segments from the file. +/* Map in a shared object's segments from the file. Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -17,14 +17,15 @@ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include +#include #include -#include -#include +#include #include -#include #include -#include -#include +#include +#include +#include #include "dynamic-link.h" @@ -90,6 +91,8 @@ ELF_PREFERRED_ADDRESS_DATA; size_t _dl_pagesize; +extern const char *_dl_platform; +extern size_t _dl_platformlen; /* Local version of `strdup' function. */ static inline char * @@ -105,6 +108,292 @@ local_strdup (const char *s) } +/* Implement cache for search path lookup. */ +#if 0 +/* This is how generated should look like. I'll remove this once I'm + sure everything works correctly. */ +static struct r_search_path_elem rtld_search_dir1 = + { "/lib/", 5, unknown, 0, unknown, NULL }; +static struct r_search_path_elem rtld_search_dir2 = + { "/usr/lib/", 9, unknown, 0, unknown, &r ld_search_dir1 }; + +static struct r_search_path_elem *rtld_search_dirs[] = +{ + &rtld_search_dir1, + &rtld_search_dir2, + NULL +}; + +static struct r_search_path_elem *all_dirs = &rtld_search_dir2; +#else +# include "rtldtbl.h" +#endif + +static size_t max_dirnamelen; + +static inline struct r_search_path_elem ** +fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep, + const char **trusted) +{ + char *cp; + size_t nelems = 0; + + while ((cp = __strsep (&rpath, sep)) != NULL) + { + struct r_search_path_elem *dirp; + size_t len = strlen (cp); + /* Remove trailing slashes. */ + while (len > 1 && cp[len - 1] == '/') + --len; + + /* Make sure we don't use untrusted directories if we run SUID. */ + if (trusted != NULL) + { + const char **trun = trusted; + + /* All trusted directory must be complete name. */ + if (cp[0] != '/') + continue; + + while (*trun != NULL + && (memcmp (*trun, cp, len) != 0 || (*trun)[len] != '\0')) + ++trun; + + if (*trun == NULL) + /* It's no trusted directory, skip it. */ + continue; + } + + /* Now add one. */ + if (len > 0) + cp[len++] = '/'; + + /* 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) + break; + + if (dirp != NULL) + { + /* It is available, see whether it's in our own list. */ + size_t cnt; + for (cnt = 0; cnt < nelems; ++cnt) + if (result[cnt] == dirp) + break; + + if (cnt == nelems) + result[nelems++] = dirp; + } + else + { + /* It's a new directory. Create an entry and add it. */ + dirp = (struct r_search_path_elem *) malloc (sizeof (*dirp)); + if (dirp == NULL) + _dl_signal_error (ENOMEM, NULL, + "cannot create cache for search path"); + + dirp->dirnamelen = len; + dirp->dirstatus = 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"); + memcpy (tmp, cp, len); + memcpy (tmp + len, _dl_platform, _dl_platformlen); + tmp[len + _dl_platformlen] = '/'; + tmp[len + _dl_platformlen + 1] = '\0'; + + dirp->dirname = tmp; + dirp->machdirstatus = unknown; + + if (max_dirnamelen < dirp->machdirnamelen) + max_dirnamelen = dirp->machdirnamelen; + } + 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"); + memcpy (tmp, cp, len); + tmp[len] = '\0'; + + if (max_dirnamelen < dirp->dirnamelen) + max_dirnamelen = dirp->dirnamelen; + + dirp->dirname = tmp; + } + + dirp->next = all_dirs; + all_dirs = dirp; + + /* Put it in the result array. */ + result[nelems++] = dirp; + } + } + + /* Terminate the array. */ + result[nelems] = NULL; + + return result; +} + + +static struct r_search_path_elem ** +decompose_rpath (const char *rpath, size_t additional_room) +{ + /* Make a copy we can work with. */ + char *copy = strdupa (rpath); + char *cp; + struct r_search_path_elem **result; + /* First count the number of necessary elements in the result array. */ + size_t nelems = 0; + + for (cp = copy; *cp != '\0'; ++cp) + if (*cp == ':') + ++nelems; + + /* Allocate room for the result. NELEMS + 1 + ADDITIONAL_ROOM is an upper + limit for the number of necessary entries. */ + result = (struct r_search_path_elem **) malloc ((nelems + 1 + + additional_room + 1) + * sizeof (*result)); + if (result == NULL) + _dl_signal_error (ENOMEM, NULL, "cannot create cache for search path"); + + return fillin_rpath (copy, result, ":", NULL); +} + + +void +_dl_init_paths (void) +{ + struct r_search_path_elem **pelem; + + /* We have in `search_path' the information about the RPATH of the + dynamic loader. Now fill in the information about the applications + RPATH and the directories addressed by the LD_LIBRARY_PATH environment + variable. */ + struct link_map *l; + + /* First determine how many elements the LD_LIBRARY_PATH contents has. */ + const char *llp = getenv ("LD_LIBRARY_PATH"); + size_t nllp; + + if (llp != NULL && *llp != '\0') + { + /* Simply count the number of colons. */ + const char *cp = llp; + nllp = 1; + while (*cp) + if (*cp++ == ':') + ++nllp; + } + else + nllp = 0; + + l = _dl_loaded; + if (l && l->l_type != lt_loaded && l->l_info[DT_RPATH]) + { + /* Allocate room for the search path and fill in information from + RPATH. */ + l->l_rpath_dirs = + decompose_rpath ((const char *) (l->l_addr + + l->l_info[DT_STRTAB]->d_un.d_ptr + + l->l_info[DT_RPATH]->d_un.d_val), + nllp); + } + else + { + /* If we have no LD_LIBRARY_PATH and no RPATH we must tell this + somehow to prevent we look this up again and again. */ + if (nllp == 0) + l->l_rpath_dirs = (struct r_search_path_elem **) -1l; + else + { + l->l_rpath_dirs = + (struct r_search_path_elem **) malloc ((nllp + 1) + * sizeof (*l->l_rpath_dirs)); + if (l->l_rpath_dirs == NULL) + _dl_signal_error (ENOMEM, NULL, + "cannot create cache for search path"); + l->l_rpath_dirs[0] = NULL; + } + } + + if (nllp > 0) + { + static const char *trusted_dirs[] = + { +#include "trusted-dirs.h" + NULL + }; + char *copy = strdupa (llp); + + /* Decompose the LD_LIBRARY_PATH and fill in the result. + First search for the next place to enter elements. */ + struct r_search_path_elem **result = l->l_rpath_dirs; + while (*result != NULL) + ++result; + + /* We need to take care that the LD_LIBRARY_PATH environement + variable can contain a semicolon. */ + (void) fillin_rpath (copy, result, ":;", + __libc_enable_secure ? trusted_dirs : 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; + + 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"); + + memcpy (tmp, relem->dirname, relem->dirnamelen); + memcpy (tmp + relem->dirnamelen, _dl_platform, _dl_platformlen); + tmp[relem->dirnamelen + _dl_platformlen] = '/'; + tmp[relem->dirnamelen + _dl_platformlen + 1] = '\0'; + + relem->dirname = tmp; + + 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; + } + } +} + + /* Map in the shared object NAME, actually located in REALNAME, and already opened on FD. */ @@ -131,7 +420,7 @@ _dl_map_object_from_fd (char *name, int fd, char *realname, l->l_next->l_prev = l->l_prev; free (l); } - free (name); + free (name); /* XXX Can this be correct? --drepper */ free (realname); _dl_signal_error (code, name, msg); } @@ -207,9 +496,6 @@ _dl_map_object_from_fd (char *name, int fd, char *realname, return l; } - if (_dl_pagesize == 0) - _dl_pagesize = __getpagesize (); - /* Map in the first page to read the header. */ header = map (0, sizeof *header); @@ -458,83 +744,87 @@ _dl_map_object_from_fd (char *name, int fd, char *realname, return l; } -/* Try to open NAME in one of the directories in DIRPATH. +/* Try to open NAME in one of the directories in DIRS. Return the fd, or -1. If successful, fill in *REALNAME with the malloc'd full directory name. */ static int open_path (const char *name, size_t namelen, - const char *dirpath, - char **realname, - const char *trusted_dirs[]) + struct r_search_path_elem **dirs, + char **realname) { char *buf; - const char *p; - int fd; + int fd = -1; - p = dirpath; - if (p == NULL || *p == '\0') + if (dirs == NULL || *dirs == NULL) { __set_errno (ENOENT); return -1; } - buf = __alloca (strlen (dirpath) + 1 + namelen); + buf = __alloca (max_dirnamelen + namelen); do { - size_t buflen; - size_t this_len; + struct r_search_path_elem *this_dir = *dirs; + size_t buflen = 0; - dirpath = p; - p = strpbrk (dirpath, ":;"); - if (p == NULL) - p = strchr (dirpath, '\0'); - - this_len = p - dirpath; - - /* When we run a setuid program we do not accept any directory. */ - if (__libc_enable_secure) + if (this_dir->machdirstatus != nonexisting) { - /* All trusted directory must be complete name. */ - if (dirpath[0] != '/') - continue; + /* Construct the pathname to try. */ + (void) memcpy (buf, this_dir->dirname, this_dir->machdirnamelen); + (void) memcpy (buf + this_dir->machdirnamelen, name, namelen); + buflen = this_dir->machdirnamelen + namelen; + + fd = __open (buf, O_RDONLY); + if (this_dir->machdirstatus == unknown) + if (fd != -1) + this_dir->machdirstatus = existing; + else + { + /* We failed to open machine dependent library. Let's + test whether there is any directory at all. */ + struct stat st; - /* If we got a list of trusted directories only accept one - of these. */ - if (trusted_dirs != NULL) - { - const char **trust = trusted_dirs; + buf[this_dir->machdirnamelen - 1] = '\0'; - while (*trust != NULL) - if (memcmp (dirpath, *trust, this_len) == 0 - && (*trust)[this_len] == '\0') - break; + if (stat (buf, &st) != 0 || ! S_ISDIR (st.st_mode)) + /* The directory does not exist ot it is no directory. */ + this_dir->machdirstatus = nonexisting; else - ++trust; - - /* If directory is not trusted, ignore this directory. */ - if (*trust == NULL) - continue; - } + this_dir->machdirstatus = existing; + } } - if (this_len == 0) - { - /* Two adjacent colons, or a colon at the beginning or the end of - the path means to search the current directory. */ - (void) memcpy (buf, name, namelen); - buflen = namelen; - } - else + if (fd == -1 && this_dir->dirstatus != nonexisting) { /* Construct the pathname to try. */ - (void) memcpy (buf, dirpath, this_len); - buf[this_len] = '/'; - (void) memcpy (&buf[this_len + 1], name, namelen); - buflen = this_len + 1 + namelen; + (void) memcpy (buf, this_dir->dirname, this_dir->dirnamelen); + (void) memcpy (buf + this_dir->dirnamelen, name, namelen); + buflen = this_dir->dirnamelen + namelen; + + 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 (stat (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; + } } - fd = __open (buf, O_RDONLY); if (fd != -1) { *realname = malloc (buflen); @@ -555,7 +845,7 @@ open_path (const char *name, size_t namelen, /* The file exists and is readable, but something went wrong. */ return -1; } - while (*p++ != '\0'); + while (*++dirs != NULL); return -1; } @@ -593,39 +883,34 @@ _dl_map_object (struct link_map *loader, const char *name, int type, size_t namelen = strlen (name) + 1; - inline void trypath (const char *dirpath, const char *trusted[]) - { - fd = open_path (name, namelen, dirpath, &realname, trusted); - } - fd = -1; /* First try the DT_RPATH of the dependent object that caused NAME to be loaded. Then that object's dependent, and on up. */ for (l = loader; fd == -1 && l; l = l->l_loader) if (l && l->l_info[DT_RPATH]) - trypath ((const char *) (l->l_addr + - l->l_info[DT_STRTAB]->d_un.d_ptr + - l->l_info[DT_RPATH]->d_un.d_val), NULL); - /* If dynamically linked, try the DT_RPATH of the executable itself. */ - l = _dl_loaded; - if (fd == -1 && l && l->l_type != lt_loaded && l->l_info[DT_RPATH]) - trypath ((const char *) (l->l_addr + - l->l_info[DT_STRTAB]->d_un.d_ptr + - l->l_info[DT_RPATH]->d_un.d_val), NULL); - /* Try an environment variable (unless setuid). */ - if (fd == -1) - { - static const char *trusted_dirs[] = { -#include "trusted-dirs.h" - NULL - }; - const char *ld_library_path = getenv ("LD_LIBRARY_PATH"); + /* Make sure the cache information is available. */ + if (l->l_rpath_dirs == NULL) + { + size_t ptrval = (l->l_addr + + l->l_info[DT_STRTAB]->d_un.d_ptr + + l->l_info[DT_RPATH]->d_un.d_val); + l->l_rpath_dirs = + decompose_rpath ((const char *) ptrval, 0); + } + + if (l->l_rpath_dirs != (struct r_search_path_elem **) -1l) + fd = open_path (name, namelen, l->l_rpath_dirs, &realname); + } + + /* If dynamically linked, try the DT_RPATH of the executable itself + and the LD_LIBRARY_PATH environment variable. */ + l = _dl_loaded; + if (fd == -1 && l && l->l_type != lt_loaded + && l->l_rpath_dirs != (struct r_search_path_elem **) -1l) + fd = open_path (name, namelen, l->l_rpath_dirs, &realname); - if (ld_library_path != NULL && *ld_library_path != '\0') - trypath (ld_library_path, trusted_dirs); - } if (fd == -1) { /* Check the list of libraries in the file /etc/ld.so.cache, @@ -646,12 +931,10 @@ _dl_map_object (struct link_map *loader, const char *name, int type, } } } + /* Finally, try the default path. */ if (fd == -1) - { - extern const char *_dl_rpath; /* Set in rtld.c. */ - trypath (_dl_rpath, NULL); - } + fd = open_path (name, namelen, rtld_search_dirs, &realname); } else { diff --git a/elf/dl-object.c b/elf/dl-object.c index 941bfa34cc..65f80d1a7e 100644 --- a/elf/dl-object.c +++ b/elf/dl-object.c @@ -44,6 +44,7 @@ _dl_new_object (char *realname, const char *libname, int type) newname->next = NULL; new->l_libname = newname; new->l_type = type; + new->l_rpath_dirs = NULL; if (_dl_loaded == NULL) { diff --git a/elf/dl-support.c b/elf/dl-support.c index 21cd13e5cf..3333bf10fb 100644 --- a/elf/dl-support.c +++ b/elf/dl-support.c @@ -20,8 +20,10 @@ /* This file defines some things that for the dynamic linker are defined in rtld.c and dl-sysdep.c in ways appropriate to bootstrap dynamic linking. */ +#include #include - +#include +#include extern char *__progname; char **_dl_argv = &__progname; /* This is checked for some error messages. */ @@ -30,15 +32,36 @@ char **_dl_argv = &__progname; /* This is checked for some error messages. */ For the dynamic linker it is set by -rpath when linking. */ const char *_dl_rpath = DEFAULT_RPATH; +/* Name of the architecture. */ +const char *_dl_platform; +size_t _dl_platformlen; + /* If nonzero print warnings about problematic situations. */ int _dl_verbose; +/* Structure to store information about search paths. */ +struct r_search_path *_dl_search_paths; -static void init_verbose (void) __attribute__ ((unused)); + +static void non_dynamic_init (void) __attribute__ ((unused)); static void -init_verbose (void) +non_dynamic_init (void) { _dl_verbose = *(getenv ("LD_WARN") ?: "") == '\0' ? 0 : 1; + + /* Initialize the data structures for the search paths for shared + objects. */ + _dl_init_paths (); + +#ifdef DL_PLATFORM_INIT + DL_PLATFORM_INIT; +#endif + + /* Now determine the length of the platform string. */ + if (_dl_platform != NULL) + _dl_platformlen = strlen (_dl_platform); + + _dl_pagesize = __getpagesize (); } -text_set_element (__libc_subinit, init_verbose); +text_set_element (__libc_subinit, non_dynamic_init); diff --git a/elf/elf.h b/elf/elf.h index d01bc90c90..02d092ffac 100644 --- a/elf/elf.h +++ b/elf/elf.h @@ -654,6 +654,11 @@ typedef struct #define AT_GID 13 /* Real gid */ #define AT_EGID 14 /* Effective gid */ +/* Some more special a_type values describing the hardware. */ +#define AT_PLATFORM 15 /* String identifying platform. */ +#define AT_HWCAP 16 /* Machine dependent hints about + processor capabilities. */ + /* Motorola 68k specific definitions. */ /* m68k relocs. */ diff --git a/elf/genrtldtbl.awk b/elf/genrtldtbl.awk new file mode 100644 index 0000000000..50f81c8c34 --- /dev/null +++ b/elf/genrtldtbl.awk @@ -0,0 +1,28 @@ +#! /usr/bin/awk +BEGIN { + FS=":"; + count=0; +} +{ + for (i = 1; i <= NF; ++i) { + dir[count++] = gensub(/((.*)[^/])?[/]*/, "\\1", "", $i); + } +} +END { + for (i = 0; i < count; ++i) { + printf ("static struct r_search_path_elem rtld_search_dir%d =\n", i+1); + printf (" { \"%s/\", %d, unknown, 0, unknown, ", + dir[i], length (dir[i]) + 1); + if (i== 0) + printf ("NULL };\n"); + else + printf ("&rtld_search_dir%d };\n", i); + } + printf ("\nstatic struct r_search_path_elem *rtld_search_dirs[] =\n{\n"); + for (i = 0; i < count; ++i) { + printf (" &rtld_search_dir%d,\n", i + 1); + } + printf (" NULL\n};\n\n"); + printf ("static struct r_search_path_elem *all_dirs = &rtld_search_dir%d;\n", + count); +} diff --git a/elf/link.h b/elf/link.h index f457174df5..e0fccd0fca 100644 --- a/elf/link.h +++ b/elf/link.h @@ -91,6 +91,25 @@ struct r_found_version const char *filename; }; +/* We want to cache information about the searches for shared objects. */ + +enum r_dir_status { unknown, nonexisting, existing }; + +struct r_search_path_elem + { + const char *dirname; + + size_t dirnamelen; + enum r_dir_status dirstatus; + + size_t machdirnamelen; + enum r_dir_status machdirstatus; + + /* This link is only used in the `all_dirs' member of `r_search_path'. */ + struct r_search_path_elem *next; + }; + + /* Structure describing a loaded shared object. The `l_next' and `l_prev' members form a chain of all the shared objects loaded at startup. @@ -163,6 +182,9 @@ struct link_map /* Array with version names. */ unsigned int l_nversions; struct r_found_version *l_versions; + + /* Collected information about own RPATH directories. */ + struct r_search_path_elem **l_rpath_dirs; }; @@ -407,6 +429,10 @@ extern void _dl_debug_state (void); in the `r_ldbase' member. Returns the address of the structure. */ extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase); +/* Initialize the basic data structure for the search paths. */ +void _dl_init_paths (void); + + __END_DECLS #endif /* link.h */ diff --git a/elf/rtld.c b/elf/rtld.c index a025757e05..7189ca6b2b 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -58,6 +58,9 @@ int _dl_argc; char **_dl_argv; const char *_dl_rpath; int _dl_verbose; +const char *_dl_platform; +size_t _dl_platformlen; +struct r_search_path *_dl_search_paths; /* Set nonzero during loading and initialization of executable and libraries, cleared before the executable's entry point runs. This @@ -526,6 +529,10 @@ of this helper program; chances are you did not intend to run this program.\n", assert (i == npreloads); } + /* Initialize the data structures for the search paths for shared + objects. */ + _dl_init_paths (); + /* 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. */ -- cgit v1.2.3