aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>1996-06-10 20:19:39 +0000
committerRoland McGrath <roland@gnu.org>1996-06-10 20:19:39 +0000
commitba79d61b44be92bb81cba28076792a856585c4a0 (patch)
tree1ece0cbcd4568069643327ffe5da7511394e3ff8
parent567c63af19d2f03836d14856596b4ae6259c03a8 (diff)
downloadglibc-ba79d61b44be92bb81cba28076792a856585c4a0.tar
glibc-ba79d61b44be92bb81cba28076792a856585c4a0.tar.gz
glibc-ba79d61b44be92bb81cba28076792a856585c4a0.tar.bz2
glibc-ba79d61b44be92bb81cba28076792a856585c4a0.zip
* Makerules ($(common-objpfx)libc.so): Depend on $(elfobjdir)/ld.so.cvs/libc-960611
* elf/dl-close.c: New file. * elf/link.h: Declare _dl_close. * elf/Makefile (routines): Add dl-close. * elf/dlclose.c (dlclose): Use _dl_close. * elf/Makefile ($(objpfx)librtld.so): Remove libelf from deps. * elf/dl-runtime.c (_dl_global_scope): New variable. (_dl_object_relocation_scope): New function. (fixup): Use it. * elf/rtld.c (dl_main): Use it. * elf/dl-open.c (_dl_open): Use it. If (MODE & RTLD_GLOBAL), set the l_global bit and append the new map to _dl_global_scope. * elf/link.h: Declare _dl_global_scope, _dl_global_scope_alloc, and _dl_object_relocation_scope. * elf/link.h (struct link_map): Add l_loader member. Remove _dl_map_object_from_fd decl. * elf/dl-load.c (_dl_map_object): Pass LOADER to ... (_dl_map_object_from_fd): Take new arg LOADER and set l_loader member. (_dl_map_object): Try DT_RPATH from all loaders up the chain. * elf/dl-object.c (_dl_loaded): Variable removed. (_dl_default_scope): New variable replaces it. * elf/link.h (_dl_loaded): Remove variable decl; instead define as macro for _dl_default_scope[2]. (_dl_default_scope): Declare it. * sysdeps/i386/dl-machine.h (RTLD_START): Use _dl_default_scope[2] instead of _dl_loaded. * sysdeps/m68k/dl-machine.h (RTLD_START): Likewise. * elf/rtld.c (dl_main): Use _dl_default_scope for symbol lookups. * elf/dl-reloc.c (_dl_relocate_object): Remove check for _dl_rtld_map. * elf/rtld.c (dl_main): Pass 0 for LAZY flag when re-relocating self. * elf/link.h (struct link_map.l_type): Remove lt_interpreter. (struct link_map): Add new flag member l_global. * elf/dl-reloc.c (_dl_relocate_object): Check for _dl_rtld_map directly instead of looking for lt_interpreter. * sysdeps/i386/dl-machine.h (elf_machine_rel): Likewise. * elf/rtld.c (_dl_start): Don't bother setting BOOTSTRAP_MAP.l_type. (dl_main): Set _dl_rtld_map.l_type to lt_library. * elf/dl-deps.c (_dl_map_object_deps): Propagate MAP->l_type to dependencies loaded, downgrading lt_executable -> lt_library. * elf/dl-load.c (_dl_map_object_from_fd): Take new arg TYPE and set l_type from that, translating lt_library->lt_executable based on the file's ELF type. (_dl_map_object): Likewise. * elf/link.h: Update prototypes. * elf/dl-open.c: Pass type lt_loaded. * elf/rtld.c: Pass type lt_library. * elf/dl-load.c (_dl_map_object_from_fd): Handle null return from _dl_new_object. (_dl_map_object_from_fd: lose): Unchain and free L if it's not null. Free REALNAME, and just use NAME in error message. * elf/dl-object.c (_dl_new_object): If malloc fails, return null instead of calling _dl_signal_error. * elf/dl-load.c (_dl_map_object_from_fd): Close FD before signalling error for _dl_zerofd setup failure. * elf/dl-object.c (_dl_startup_loaded): Variable removed. * elf/link.h: Remove its decl. * elf/dl-reloc.c (_dl_relocate_object): Take new SCOPE arg and pass it through to _dl_lookup_symbol. * elf/link.h (_dl_relocate_object): Update comment and prototype. * elf/rtld.c (dl_main): Pass scope vector to _dl_relocate_object. * elf/dl-lookup.c (_dl_lookup_symbol): Arg SYMBOL_SCOPE is now a null-terminated vector of pointers, no longer a vector of exactly two. * elf/link.h (_dl_lookup_symbol): Update comment and prototype. * elf/dl-runtime.c (fixup): Set up scope for symbol lookup properly as done in _dl_relocate_object. * elf/dlopen.c: Pass "" to _dl_open when FILE is null.
-rw-r--r--ChangeLog84
-rw-r--r--Makerules2
-rw-r--r--elf/Makefile7
-rw-r--r--elf/dl-close.c107
-rw-r--r--elf/dl-deps.c4
-rw-r--r--elf/dl-load.c314
-rw-r--r--elf/dl-lookup.c125
-rw-r--r--elf/dl-object.c12
-rw-r--r--elf/dl-open.c81
-rw-r--r--elf/dl-reloc.c33
-rw-r--r--elf/dl-runtime.c58
-rw-r--r--elf/dlclose.c70
-rw-r--r--elf/dlopen.c2
-rw-r--r--elf/link.h68
-rw-r--r--elf/rtld.c83
-rw-r--r--sysdeps/i386/dl-machine.h10
-rw-r--r--sysdeps/m68k/dl-machine.h6
17 files changed, 667 insertions, 399 deletions
diff --git a/ChangeLog b/ChangeLog
index 231facf905..02a94226e3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,89 @@
Mon Jun 10 06:14:03 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
+ * Makerules ($(common-objpfx)libc.so): Depend on $(elfobjdir)/ld.so.
+
+ * elf/dl-close.c: New file.
+ * elf/link.h: Declare _dl_close.
+ * elf/Makefile (routines): Add dl-close.
+ * elf/dlclose.c (dlclose): Use _dl_close.
+
+ * elf/Makefile ($(objpfx)librtld.so): Remove libelf from deps.
+
+ * elf/dl-runtime.c (_dl_global_scope): New variable.
+ (_dl_object_relocation_scope): New function.
+ (fixup): Use it.
+ * elf/rtld.c (dl_main): Use it.
+ * elf/dl-open.c (_dl_open): Use it. If (MODE & RTLD_GLOBAL), set the
+ l_global bit and append the new map to _dl_global_scope.
+ * elf/link.h: Declare _dl_global_scope, _dl_global_scope_alloc,
+ and _dl_object_relocation_scope.
+
+ * elf/link.h (struct link_map): Add l_loader member.
+ Remove _dl_map_object_from_fd decl.
+ * elf/dl-load.c (_dl_map_object): Pass LOADER to ...
+ (_dl_map_object_from_fd): Take new arg LOADER and set l_loader member.
+ (_dl_map_object): Try DT_RPATH from all loaders up the chain.
+
+ * elf/dl-object.c (_dl_loaded): Variable removed.
+ (_dl_default_scope): New variable replaces it.
+ * elf/link.h (_dl_loaded): Remove variable decl; instead define as
+ macro for _dl_default_scope[2].
+ (_dl_default_scope): Declare it.
+ * sysdeps/i386/dl-machine.h (RTLD_START): Use _dl_default_scope[2]
+ instead of _dl_loaded.
+ * sysdeps/m68k/dl-machine.h (RTLD_START): Likewise.
+ * elf/rtld.c (dl_main): Use _dl_default_scope for symbol lookups.
+
+ * elf/dl-reloc.c (_dl_relocate_object): Remove check for _dl_rtld_map.
+ * elf/rtld.c (dl_main): Pass 0 for LAZY flag when re-relocating self.
+
+ * elf/link.h (struct link_map.l_type): Remove lt_interpreter.
+ (struct link_map): Add new flag member l_global.
+
+ * elf/dl-reloc.c (_dl_relocate_object): Check for _dl_rtld_map
+ directly instead of looking for lt_interpreter.
+ * sysdeps/i386/dl-machine.h (elf_machine_rel): Likewise.
+ * elf/rtld.c (_dl_start): Don't bother setting BOOTSTRAP_MAP.l_type.
+ (dl_main): Set _dl_rtld_map.l_type to lt_library.
+
+ * elf/dl-deps.c (_dl_map_object_deps): Propagate MAP->l_type to
+ dependencies loaded, downgrading lt_executable -> lt_library.
+
+ * elf/dl-load.c (_dl_map_object_from_fd): Take new arg TYPE and set
+ l_type from that, translating lt_library->lt_executable based on the
+ file's ELF type.
+ (_dl_map_object): Likewise.
+ * elf/link.h: Update prototypes.
+ * elf/dl-open.c: Pass type lt_loaded.
+ * elf/rtld.c: Pass type lt_library.
+
+ * elf/dl-load.c (_dl_map_object_from_fd): Handle null return from
+ _dl_new_object.
+ (_dl_map_object_from_fd: lose): Unchain and free L if it's not null.
+ Free REALNAME, and just use NAME in error message.
+ * elf/dl-object.c (_dl_new_object): If malloc fails, return null
+ instead of calling _dl_signal_error.
+
+ * elf/dl-load.c (_dl_map_object_from_fd): Close FD before signalling
+ error for _dl_zerofd setup failure.
+
+ * elf/dl-object.c (_dl_startup_loaded): Variable removed.
+ * elf/link.h: Remove its decl.
+
+ * elf/dl-reloc.c (_dl_relocate_object): Take new SCOPE arg and pass it
+ through to _dl_lookup_symbol.
+ * elf/link.h (_dl_relocate_object): Update comment and prototype.
+ * elf/rtld.c (dl_main): Pass scope vector to _dl_relocate_object.
+
+ * elf/dl-lookup.c (_dl_lookup_symbol): Arg SYMBOL_SCOPE is now a
+ null-terminated vector of pointers, no longer a vector of exactly two.
+ * elf/link.h (_dl_lookup_symbol): Update comment and prototype.
+
+ * elf/dl-runtime.c (fixup): Set up scope for symbol lookup properly as
+ done in _dl_relocate_object.
+
+ * elf/dlopen.c: Pass "" to _dl_open when FILE is null.
+
* elf/link.h: Include elfclass.h to define __ELF_NATIVE_CLASS.
(ElfW, ELFW): Use it.
* elf/Makefile (headers): Add elfclass.h.
diff --git a/Makerules b/Makerules
index d74e5be97a..0310b000c4 100644
--- a/Makerules
+++ b/Makerules
@@ -496,7 +496,7 @@ LDFLAGS-c.so += -e __libc_print_version
elfobjdir := $(firstword $(objdir) $(..)elf)
$(common-objpfx)libc.so: $(elfobjdir)/soinit.so \
$(common-objpfx)libc_pic.a \
- $(elfobjdir)/sofini.so
+ $(elfobjdir)/sofini.so $(elfobjdir)/ld.so
$(build-shlib)
ifdef libc.so-version
diff --git a/elf/Makefile b/elf/Makefile
index 06aeb7590a..c2c8f7c5b2 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -21,7 +21,8 @@
subdir := elf
headers = elf.h elfclass.h link.h dlfcn.h
-routines = init-first $(dl-routines) dl-open dl-symbol dl-support
+routines = init-first $(dl-routines) \
+ dl-open dl-close dl-symbol dl-support
# The core dynamic linking functions are in libc for the static and
# profiled libraries.
@@ -54,7 +55,7 @@ install-bin = ldd
# to run programs during the `make others' pass.
lib-noranlib: $(objpfx)ld.so $(addprefix $(objpfx),$(extra-objs))
-ifneq (,$(filter linux%,$(config-os)))
+ifneq (,$(filter linux% linux,$(config-os)))
extra-objs += linux-compat.so
install-others += $(slibdir)/ld-linux.so.1
lib-noranlib: $(objpfx)ld-linux.so.1
@@ -75,7 +76,7 @@ $(objpfx)dl-allobjs.so: $(rtld-routines:%=$(objpfx)%.so)
# dynamic linker shared objects below.
$(objpfx)librtld.so: $(objpfx)dl-allobjs.so \
$(patsubst %,$(common-objpfx)lib%_pic.a,\
- elf c $(LDLIBS-c.so:-l%=%))
+ c $(LDLIBS-c.so:-l%=%))
$(reloc-link) '-Wl,-(' $^ -lgcc '-Wl,-)'
$(objpfx)ld.so: $(objpfx)librtld.so
diff --git a/elf/dl-close.c b/elf/dl-close.c
new file mode 100644
index 0000000000..69fdefac95
--- /dev/null
+++ b/elf/dl-close.c
@@ -0,0 +1,107 @@
+/* _dl_close -- Close a shared object opened by `_dl_open'.
+Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include <link.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+
+#define LOSE(s) _dl_signal_error (0, map->l_name, s)
+
+void
+_dl_close (struct link_map *map)
+{
+ struct link_map **list;
+ unsigned int i;
+
+ if (map->l_opencount == 0)
+ LOSE ("shared object not open");
+
+ /* Decrement the reference count. */
+ if (--map->l_opencount > 0 || map->l_type != lt_loaded)
+ /* There are still references to this object. Do nothing more. */
+ return;
+
+ list = map->l_searchlist;
+
+ /* The search list contains a counted reference to each object it
+ points to, the 0th elt being MAP itself. Decrement the reference
+ counts on all the objects MAP depends on. */
+ for (i = 1; i < map->l_nsearchlist; ++i)
+ --list[i]->l_opencount;
+
+ /* Clear the search list so it doesn't get freed while we are still
+ using it. We have cached it in LIST and will free it when
+ finished. */
+ map->l_searchlist = NULL;
+
+ /* Check each element of the search list to see if all references to
+ it are gone. */
+ for (i = 0; i < map->l_nsearchlist; ++i)
+ {
+ struct link_map *map = list[i];
+ if (map->l_opencount == 0 && map->l_type == lt_loaded)
+ {
+ /* That was the last reference, and this was a dlopen-loaded
+ object. We can unmap it. */
+ const ElfW(Phdr) *ph;
+
+ if (map->l_info[DT_FINI])
+ /* Call its termination function. */
+ (*(void (*) (void)) ((void *) map->l_addr +
+ map->l_info[DT_FINI]->d_un.d_ptr)) ();
+
+ if (map->l_global)
+ {
+ /* This object is in the global scope list. Remove it. */
+ struct link_map **tail = _dl_global_scope_end;
+ do
+ --tail;
+ while (*tail != map);
+ --_dl_global_scope_end;
+ memcpy (tail, tail + 1, _dl_global_scope_end - tail);
+ _dl_global_scope_end[0] = NULL;
+ _dl_global_scope_end[1] = NULL;
+ }
+
+ /* Unmap the segments. */
+ for (ph = map->l_phdr; ph < &map->l_phdr[map->l_phnum]; ++ph)
+ if (ph->p_type == PT_LOAD)
+ {
+ ElfW(Addr) mapstart = ph->p_vaddr & ~(ph->p_align - 1);
+ ElfW(Addr) mapend = ((ph->p_vaddr + ph->p_memsz
+ + ph->p_align - 1)
+ & ~(ph->p_align - 1));
+ __munmap ((caddr_t) mapstart, mapend - mapstart);
+ }
+
+ /* Finally, unlink the data structure and free it. */
+ map->l_prev->l_next = map->l_next;
+ if (map->l_next)
+ map->l_next->l_prev = map->l_prev;
+ if (map->l_searchlist)
+ free (map->l_searchlist);
+ free (map);
+ }
+ }
+
+ free (list);
+}
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
index 7e3b259362..3e49fcfe01 100644
--- a/elf/dl-deps.c
+++ b/elf/dl-deps.c
@@ -62,7 +62,9 @@ _dl_map_object_deps (struct link_map *map)
{
/* Map in the needed object. */
struct link_map *dep
- = _dl_map_object (l, strtab + d->d_un.d_val);
+ = _dl_map_object (l, strtab + d->d_un.d_val,
+ l->l_type == lt_executable ? lt_library :
+ l->l_type);
if (dep->l_reserved)
/* This object is already in the search list we are
diff --git a/elf/dl-load.c b/elf/dl-load.c
index c6acc8c222..b9f4aa184b 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -63,152 +63,14 @@ int _dl_zerofd = -1;
size_t _dl_pagesize;
-/* Try to open NAME in one of the directories in DIRPATH.
- 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)
-{
- char *buf;
- const char *p;
- int fd;
-
- p = dirpath;
- if (p == NULL || *p == '\0')
- {
- errno = ENOENT;
- return -1;
- }
-
- buf = __alloca (strlen (dirpath) + 1 + namelen);
- do
- {
- size_t buflen;
-
- dirpath = p;
- p = strpbrk (dirpath, ":;");
- if (p == NULL)
- p = strchr (dirpath, '\0');
-
- if (p == dirpath)
- {
- /* 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
- {
- /* Construct the pathname to try. */
- (void) memcpy (buf, dirpath, p - dirpath);
- buf[p - dirpath] = '/';
- (void) memcpy (&buf[(p - dirpath) + 1], name, namelen);
- buflen = p - dirpath + 1 + namelen;
- }
-
- fd = __open (buf, O_RDONLY);
- if (fd != -1)
- {
- *realname = malloc (buflen);
- if (*realname)
- {
- memcpy (*realname, buf, buflen);
- return fd;
- }
- else
- {
- /* No memory for the name, we certainly won't be able
- to load and link it. */
- __close (fd);
- return -1;
- }
- }
- if (errno != ENOENT && errno != EACCES)
- /* The file exists and is readable, but something went wrong. */
- return -1;
- }
- while (*p++ != '\0');
-
- return -1;
-}
-
-/* Map in the shared object file NAME. */
-
-struct link_map *
-_dl_map_object (struct link_map *loader, const char *name)
-{
- int fd;
- char *realname;
- struct link_map *l;
-
- /* Look for this name among those already loaded. */
- for (l = _dl_loaded; l; l = l->l_next)
- if (! strcmp (name, l->l_libname))
- {
- /* The object is already loaded.
- Just bump its reference count and return it. */
- ++l->l_opencount;
- return l;
- }
-
- if (strchr (name, '/') == NULL)
- {
- /* Search for NAME in several places. */
-
- size_t namelen = strlen (name) + 1;
-
- inline void trypath (const char *dirpath)
- {
- fd = open_path (name, namelen, dirpath, &realname);
- }
-
- fd = -1;
- if (loader && loader->l_info[DT_RPATH])
- trypath ((const char *) (loader->l_addr +
- loader->l_info[DT_STRTAB]->d_un.d_ptr +
- loader->l_info[DT_RPATH]->d_un.d_val));
- if (fd == -1 && ! _dl_secure)
- trypath (getenv ("LD_LIBRARY_PATH"));
- if (fd == -1)
- {
- extern const char *_dl_rpath; /* Set in rtld.c. */
- trypath (_dl_rpath);
- }
- }
- else
- {
- fd = __open (name, O_RDONLY);
- if (fd != -1)
- {
- size_t len = strlen (name) + 1;
- realname = malloc (len);
- if (realname)
- memcpy (realname, name, len);
- else
- {
- __close (fd);
- fd = -1;
- }
- }
- }
-
- if (fd == -1)
- _dl_signal_error (errno, name, "cannot open shared object file");
-
- return _dl_map_object_from_fd (name, fd, realname);
-}
-
-
/* Map in the shared object NAME, actually located in REALNAME, and already
opened on FD. */
struct link_map *
-_dl_map_object_from_fd (const char *name, int fd, char *realname)
+_dl_map_object_from_fd (const char *name, int fd, char *realname,
+ struct link_map *loader, int l_type)
{
- struct link_map *l = NULL;
+ struct link_map *l;
void *file_mapping = NULL;
size_t mapping_size = 0;
@@ -218,7 +80,17 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname)
(void) __close (fd);
if (file_mapping)
__munmap (file_mapping, mapping_size);
- _dl_signal_error (code, l ? l->l_name : name, msg);
+ if (l)
+ {
+ /* Remove the stillborn object from the list and free it. */
+ if (l->l_prev)
+ l->l_prev->l_next = l->l_next;
+ if (l->l_next)
+ l->l_next->l_prev = l->l_prev;
+ free (l);
+ }
+ free (realname);
+ _dl_signal_error (code, name, msg);
}
inline caddr_t map_segment (ElfW(Addr) mapstart, size_t len,
@@ -304,17 +176,23 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname)
if (header->e_phentsize != sizeof (ElfW(Phdr)))
LOSE ("ELF file's phentsize not the expected size");
- /* Enter the new object in the list of loaded objects. */
- l = _dl_new_object (realname, name, lt_loaded);
- l->l_opencount = 1;
-
if (_dl_zerofd == -1)
{
_dl_zerofd = _dl_sysdep_open_zero_fill ();
if (_dl_zerofd == -1)
- _dl_signal_error (errno, NULL, "cannot open zero fill device");
+ {
+ __close (fd);
+ _dl_signal_error (errno, NULL, "cannot open zero fill device");
+ }
}
+ /* Enter the new object in the list of loaded objects. */
+ l = _dl_new_object (realname, name, l_type);
+ if (! l)
+ lose (ENOMEM, "cannot create shared object descriptor");
+ l->l_opencount = 1;
+ l->l_loader = loader;
+
/* Extract the remaining details we need from the ELF header
and then map in the program header table. */
l->l_entry = header->e_entry;
@@ -464,7 +342,8 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname)
/* We are done mapping in the file. We no longer need the descriptor. */
__close (fd);
- l->l_type = type == ET_EXEC ? lt_executable : lt_library;
+ if (l->l_type == lt_library && type == ET_EXEC)
+ l->l_type = lt_executable;
if (l->l_ld == 0)
{
@@ -484,3 +363,142 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname)
return l;
}
+
+/* Try to open NAME in one of the directories in DIRPATH.
+ 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)
+{
+ char *buf;
+ const char *p;
+ int fd;
+
+ p = dirpath;
+ if (p == NULL || *p == '\0')
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ buf = __alloca (strlen (dirpath) + 1 + namelen);
+ do
+ {
+ size_t buflen;
+
+ dirpath = p;
+ p = strpbrk (dirpath, ":;");
+ if (p == NULL)
+ p = strchr (dirpath, '\0');
+
+ if (p == dirpath)
+ {
+ /* 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
+ {
+ /* Construct the pathname to try. */
+ (void) memcpy (buf, dirpath, p - dirpath);
+ buf[p - dirpath] = '/';
+ (void) memcpy (&buf[(p - dirpath) + 1], name, namelen);
+ buflen = p - dirpath + 1 + namelen;
+ }
+
+ fd = __open (buf, O_RDONLY);
+ if (fd != -1)
+ {
+ *realname = malloc (buflen);
+ if (*realname)
+ {
+ memcpy (*realname, buf, buflen);
+ return fd;
+ }
+ else
+ {
+ /* No memory for the name, we certainly won't be able
+ to load and link it. */
+ __close (fd);
+ return -1;
+ }
+ }
+ if (errno != ENOENT && errno != EACCES)
+ /* The file exists and is readable, but something went wrong. */
+ return -1;
+ }
+ while (*p++ != '\0');
+
+ return -1;
+}
+
+/* Map in the shared object file NAME. */
+
+struct link_map *
+_dl_map_object (struct link_map *loader, const char *name, int type)
+{
+ int fd;
+ char *realname;
+ struct link_map *l;
+
+ /* Look for this name among those already loaded. */
+ for (l = _dl_loaded; l; l = l->l_next)
+ if (! strcmp (name, l->l_libname))
+ {
+ /* The object is already loaded.
+ Just bump its reference count and return it. */
+ ++l->l_opencount;
+ return l;
+ }
+
+ if (strchr (name, '/') == NULL)
+ {
+ /* Search for NAME in several places. */
+
+ size_t namelen = strlen (name) + 1;
+
+ inline void trypath (const char *dirpath)
+ {
+ fd = open_path (name, namelen, dirpath, &realname);
+ }
+
+ fd = -1;
+ for (l = loader; 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));
+ if (fd == -1 && ! _dl_secure)
+ trypath (getenv ("LD_LIBRARY_PATH"));
+ if (fd == -1)
+ {
+ extern const char *_dl_rpath; /* Set in rtld.c. */
+ trypath (_dl_rpath);
+ }
+ }
+ else
+ {
+ fd = __open (name, O_RDONLY);
+ if (fd != -1)
+ {
+ size_t len = strlen (name) + 1;
+ realname = malloc (len);
+ if (realname)
+ memcpy (realname, name, len);
+ else
+ {
+ __close (fd);
+ fd = -1;
+ }
+ }
+ }
+
+ if (fd == -1)
+ _dl_signal_error (errno, name, "cannot open shared object file");
+
+ return _dl_map_object_from_fd (name, fd, realname, loader, type);
+}
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index 0674253041..5f1e6d03d9 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -50,7 +50,7 @@ _dl_elf_hash (const char *name)
ElfW(Addr)
_dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref,
- struct link_map *symbol_scope[2],
+ struct link_map *symbol_scope[],
const char *reference_name,
ElfW(Addr) reloc_addr,
int noplt)
@@ -65,69 +65,68 @@ _dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref,
struct link_map **scope, *map;
/* Search the relevant loaded objects for a definition. */
- for (scope = symbol_scope; scope < &symbol_scope[2]; ++scope)
- if (*scope)
- for (i = 0; i < (*scope)->l_nsearchlist; ++i)
- {
- const ElfW(Sym) *symtab;
- const char *strtab;
- ElfW(Word) symidx;
-
- map = (*scope)->l_searchlist[i];
-
- symtab = ((void *) map->l_addr + map->l_info[DT_SYMTAB]->d_un.d_ptr);
- strtab = ((void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr);
-
- /* Search the appropriate hash bucket in this object's symbol table
- for a definition for the same symbol name. */
- for (symidx = map->l_buckets[hash % map->l_nbuckets];
- symidx != STN_UNDEF;
- symidx = map->l_chain[symidx])
- {
- const ElfW(Sym) *sym = &symtab[symidx];
-
- if (sym->st_value == 0 || /* No value. */
- /* Cannot resolve to the location being filled in. */
- reloc_addr == map->l_addr + sym->st_value ||
- (noplt && sym->st_shndx == SHN_UNDEF)) /* Reject PLT. */
- continue;
-
- switch (ELFW(ST_TYPE) (sym->st_info))
- {
- case STT_NOTYPE:
- case STT_FUNC:
- case STT_OBJECT:
- break;
- default:
- /* Not a code/data definition. */
- continue;
- }
-
- if (sym != *ref && strcmp (strtab + sym->st_name, undef_name))
- /* Not the symbol we are looking for. */
+ for (scope = symbol_scope; *scope; ++scope)
+ for (i = 0; i < (*scope)->l_nsearchlist; ++i)
+ {
+ const ElfW(Sym) *symtab;
+ const char *strtab;
+ ElfW(Word) symidx;
+
+ map = (*scope)->l_searchlist[i];
+
+ symtab = ((void *) map->l_addr + map->l_info[DT_SYMTAB]->d_un.d_ptr);
+ strtab = ((void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr);
+
+ /* Search the appropriate hash bucket in this object's symbol table
+ for a definition for the same symbol name. */
+ for (symidx = map->l_buckets[hash % map->l_nbuckets];
+ symidx != STN_UNDEF;
+ symidx = map->l_chain[symidx])
+ {
+ const ElfW(Sym) *sym = &symtab[symidx];
+
+ if (sym->st_value == 0 || /* No value. */
+ /* Cannot resolve to the location being filled in. */
+ reloc_addr == map->l_addr + sym->st_value ||
+ (noplt && sym->st_shndx == SHN_UNDEF)) /* Reject PLT. */
+ continue;
+
+ switch (ELFW(ST_TYPE) (sym->st_info))
+ {
+ case STT_NOTYPE:
+ case STT_FUNC:
+ case STT_OBJECT:
+ break;
+ default:
+ /* Not a code/data definition. */
continue;
-
- switch (ELFW(ST_BIND) (sym->st_info))
- {
- case STB_GLOBAL:
- /* Global definition. Just what we need. */
- *ref = sym;
- return map->l_addr;
- case STB_WEAK:
- /* Weak definition. Use this value if we don't find
- another. */
- if (! weak_value.s)
- {
- weak_value.s = sym;
- weak_value.a = map->l_addr;
- }
- break;
- default:
- /* Local symbols are ignored. */
- break;
- }
- }
- }
+ }
+
+ if (sym != *ref && strcmp (strtab + sym->st_name, undef_name))
+ /* Not the symbol we are looking for. */
+ continue;
+
+ switch (ELFW(ST_BIND) (sym->st_info))
+ {
+ case STB_GLOBAL:
+ /* Global definition. Just what we need. */
+ *ref = sym;
+ return map->l_addr;
+ case STB_WEAK:
+ /* Weak definition. Use this value if we don't find
+ another. */
+ if (! weak_value.s)
+ {
+ weak_value.s = sym;
+ weak_value.a = map->l_addr;
+ }
+ break;
+ default:
+ /* Local symbols are ignored. */
+ break;
+ }
+ }
+ }
if (weak_value.s == NULL && ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
{
diff --git a/elf/dl-object.c b/elf/dl-object.c
index 11e9e082d2..851d133df3 100644
--- a/elf/dl-object.c
+++ b/elf/dl-object.c
@@ -1,5 +1,5 @@
/* Storage management for the chain of loaded shared objects.
-Copyright (C) 1995 Free Software Foundation, Inc.
+Copyright (C) 1995, 1996 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -24,11 +24,8 @@ Cambridge, MA 02139, USA. */
#include <errno.h>
-/* List of objects currently loaded. */
-struct link_map *_dl_loaded;
-
-/* Tail of that list which were loaded at startup. */
-struct link_map *_dl_startup_loaded;
+/* List of objects currently loaded is [2] of this, aka _dl_loaded. */
+struct link_map *_dl_default_scope[5];
/* Allocate a `struct link_map' for a new object being loaded,
and enter it into the _dl_loaded list. */
@@ -38,8 +35,7 @@ _dl_new_object (char *realname, const char *libname, int type)
{
struct link_map *new = malloc (sizeof *new);
if (! new)
- _dl_signal_error (ENOMEM, libname,
- "cannot allocate shared object descriptor");
+ return NULL;
memset (new, 0, sizeof *new);
new->l_name = realname;
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 221abbd35e..9389303b90 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -19,6 +19,10 @@ Cambridge, MA 02139, USA. */
#include <link.h>
#include <dlfcn.h>
+#include <stdlib.h>
+#include <errno.h>
+
+size_t _dl_global_scope_alloc;
struct link_map *
_dl_open (struct link_map *parent, const char *file, int mode)
@@ -26,16 +30,83 @@ _dl_open (struct link_map *parent, const char *file, int mode)
struct link_map *new, *l;
ElfW(Addr) init;
+
/* Load the named object. */
- new = _dl_map_object (parent, file);
+ new = _dl_map_object (parent, file, lt_loaded);
+ if (new->l_searchlist)
+ /* It was already open. */
+ return new;
/* Load that object's dependencies. */
_dl_map_object_deps (new);
- /* Relocate the objects loaded. */
- for (l = new; l; l = l->l_next)
- if (! l->l_relocated)
- _dl_relocate_object (l, (mode & RTLD_BINDING_MASK) == RTLD_LAZY);
+
+ /* Relocate the objects loaded. We do this in reverse order so that copy
+ relocs of earlier objects overwrite the data written by later objects. */
+
+ l = new;
+ while (l->l_next)
+ l = l->l_next;
+ do
+ {
+ if (! l->l_relocated)
+ {
+ _dl_relocate_object (l, _dl_object_relocation_scope (l),
+ (mode & RTLD_BINDING_MASK) == RTLD_LAZY);
+ *_dl_global_scope_end = NULL;
+ }
+
+ l = l->l_prev;
+ } while (l != new);
+
+ new->l_global = (mode & RTLD_GLOBAL);
+ if (new->l_global)
+ {
+ /* The symbols of the new object and its dependencies are to be
+ introduced into the global scope that will be used to resolve
+ references from other dynamically-loaded objects. */
+
+ if (_dl_global_scope_alloc == 0)
+ {
+ /* This is the first dynamic object given global scope. */
+ _dl_global_scope_alloc = 8;
+ _dl_global_scope = malloc (8 * sizeof (struct link_map *));
+ if (! _dl_global_scope)
+ {
+ _dl_global_scope = _dl_default_scope;
+ nomem:
+ _dl_close (new);
+ _dl_signal_error (ENOMEM, file, "cannot extend global scope");
+ }
+ _dl_global_scope[2] = _dl_default_scope[2];
+ _dl_global_scope[3] = new;
+ _dl_global_scope[4] = NULL;
+ _dl_global_scope[5] = NULL;
+ }
+ else
+ {
+ if (_dl_global_scope_alloc <
+ _dl_global_scope_end - _dl_global_scope + 2)
+ {
+ /* Must extend the list. */
+ struct link_map **new = realloc (_dl_global_scope,
+ _dl_global_scope_alloc * 2);
+ if (! new)
+ goto nomem;
+ _dl_global_scope_end = new + (_dl_global_scope_end -
+ _dl_global_scope);
+ _dl_global_scope = new;
+ _dl_global_scope_alloc *= 2;
+ }
+
+ /* Append the new object and re-terminate the list. */
+ *_dl_global_scope_end++ = new;
+ /* We keep the list double-terminated so the last element
+ can be filled in for symbol lookups. */
+ _dl_global_scope_end[0] = NULL;
+ _dl_global_scope_end[1] = NULL;
+ }
+ }
/* Run the initializer functions of new objects. */
while (init = _dl_init_next (new))
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index 5da8575da5..e6778e7de3 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -26,7 +26,7 @@ Cambridge, MA 02139, USA. */
void
-_dl_relocate_object (struct link_map *l, int lazy)
+_dl_relocate_object (struct link_map *l, struct link_map *scope[], int lazy)
{
if (l->l_relocated)
return;
@@ -52,44 +52,26 @@ _dl_relocate_object (struct link_map *l, int lazy)
}
{
- struct link_map *scope[2];
+ /* Do the actual relocation of the object's GOT and other data. */
- const char *strtab
+ const char *strtab /* String table object symbols. */
= ((void *) l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr);
-
ElfW(Addr) resolve (const ElfW(Sym) **ref,
ElfW(Addr) reloc_addr, int noplt)
{
+ /* Look up the referenced symbol in the specified scope. */
return _dl_lookup_symbol (strtab + (*ref)->st_name, ref, scope,
l->l_name, reloc_addr, noplt);
}
- if (l->l_info[DT_SYMBOLIC])
- {
- scope[0] = l;
- scope[1] = _dl_loaded;
- }
- else
- {
- scope[0] = _dl_loaded;
- scope[1] = l;
- }
-
- if (l->l_type == lt_interpreter)
- /* We cannot be lazy when relocating the dynamic linker itself. It
- was previously relocated eagerly (allowing us to be running now),
- and needs always to be fully relocated so it can run without the
- aid of run-time fixups (because it's the one to do them), so we
- must always re-relocate its PLT eagerly. */
- lazy = 0;
-
ELF_DYNAMIC_RELOCATE (l, lazy, resolve);
}
- /* Set up the PLT so its unrelocated entries will
- jump to _dl_runtime_resolve, which will relocate them. */
+ /* Set up the PLT so its unrelocated entries will jump to
+ _dl_runtime_resolve (dl-runtime.c), which will relocate them. */
elf_machine_runtime_setup (l, lazy);
+ /* Mark the object so we know ths work has been done. */
l->l_relocated = 1;
if (l->l_info[DT_TEXTREL])
@@ -114,5 +96,4 @@ _dl_relocate_object (struct link_map *l, int lazy)
"can't restore segment prot after reloc");
}
}
-
}
diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c
index c306543155..8ad2c0ffa4 100644
--- a/elf/dl-runtime.c
+++ b/elf/dl-runtime.c
@@ -20,6 +20,54 @@ Cambridge, MA 02139, USA. */
#include <link.h>
#include "dynamic-link.h"
+
+/* The global scope we will use for symbol lookups.
+ This will be modified by _dl_open if RTLD_GLOBAL is used. */
+struct link_map **_dl_global_scope = _dl_default_scope;
+struct link_map **_dl_global_scope_end = &_dl_default_scope[3];
+
+
+/* Hack _dl_global_scope[0] and [1] as necessary, and return a pointer into
+ _dl_global_scope that should be passed to _dl_lookup_symbol for symbol
+ references made in the object L's relocations. */
+inline struct link_map **
+_dl_object_relocation_scope (struct link_map *l)
+{
+ if (l->l_info[DT_SYMBOLIC])
+ {
+ /* This object's global references are to be resolved first
+ in the object itself, and only secondarily in more global
+ scopes. */
+
+ if (! l->l_searchlist)
+ /* We must construct the searchlist for this object. */
+ _dl_map_object_deps (l);
+
+ /* The primary scope is this object itself and its
+ dependencies. */
+ _dl_global_scope[0] = l;
+
+ /* Secondary is the dependency tree that reached L; the object
+ requested directly by the user is at the root of that tree. */
+ while (l->l_loader)
+ l = l->l_loader;
+ _dl_global_scope[1] = l;
+
+ /* Finally, the global scope follows. */
+
+ return _dl_global_scope;
+ }
+ else
+ {
+ /* Use first the global scope, and then the scope of the root of the
+ dependency tree that first caused this object to be loaded. */
+ while (l->l_loader)
+ l = l->l_loader;
+ *_dl_global_scope_end = l;
+ return &_dl_global_scope[2];
+ }
+}
+
/* Figure out the right type, Rel or Rela. */
#define elf_machine_rel 1
#define elf_machine_rela 2
@@ -67,17 +115,21 @@ fixup (
= (const void *) (l->l_addr + l->l_info[DT_JMPREL]->d_un.d_ptr +
reloc_offset);
+ /* Set up the scope to find symbols referenced by this object. */
+ struct link_map **scope = _dl_object_relocation_scope (l);
+
+ /* Perform the specified relocation. */
ElfW(Addr) resolve (const ElfW(Sym) **ref,
ElfW(Addr) reloc_addr, int noplt)
{
- struct link_map *scope[2] = { _dl_loaded, NULL };
return _dl_lookup_symbol (strtab + (*ref)->st_name, ref,
scope, l->l_name, reloc_addr, noplt);
}
-
- /* Perform the specified relocation. */
elf_machine_relplt (l, reloc, &symtab[ELFW(R_SYM) (reloc->r_info)], resolve);
+ *_dl_global_scope_end = NULL;
+
+ /* Return the address that was written by the relocation. */
return *(ElfW(Addr) *) (l->l_addr + reloc->r_offset);
}
diff --git a/elf/dlclose.c b/elf/dlclose.c
index 0d2689e01c..a5c8e7c17e 100644
--- a/elf/dlclose.c
+++ b/elf/dlclose.c
@@ -19,81 +19,13 @@ Cambridge, MA 02139, USA. */
#include <link.h>
#include <dlfcn.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-
-
-#define LOSE(s) _dl_signal_error (0, map->l_name, s)
int
dlclose (void *handle)
{
void doit (void)
{
- struct link_map *map = handle;
- struct link_map **list;
- unsigned int i;
-
- if (map->l_opencount == 0)
- LOSE ("shared object not open");
-
- /* Decrement the reference count. */
- if (--map->l_opencount > 0 || map->l_type != lt_loaded)
- /* There are still references to this object. Do nothing more. */
- return;
-
- list = map->l_searchlist;
-
- /* The search list contains a counted reference to each object it
- points to, the 0th elt being MAP itself. Decrement the reference
- counts on all the objects MAP depends on. */
- for (i = 1; i < map->l_nsearchlist; ++i)
- --list[i]->l_opencount;
-
- /* Clear the search list so it doesn't get freed while we are still
- using it. We have cached it in LIST and will free it when
- finished. */
- map->l_searchlist = NULL;
-
- /* Check each element of the search list to see if all references to
- it are gone. */
- for (i = 0; i < map->l_nsearchlist; ++i)
- {
- struct link_map *map = list[i];
- if (map->l_opencount == 0 && map->l_type == lt_loaded)
- {
- /* That was the last reference, and this was a dlopen-loaded
- object. We can unmap it. */
- const ElfW(Phdr) *ph;
-
- if (map->l_info[DT_FINI])
- /* Call its termination function. */
- (*(void (*) (void)) ((void *) map->l_addr +
- map->l_info[DT_FINI]->d_un.d_ptr)) ();
-
- /* Unmap the segments. */
- for (ph = map->l_phdr; ph < &map->l_phdr[map->l_phnum]; ++ph)
- if (ph->p_type == PT_LOAD)
- {
- ElfW(Addr) mapstart = ph->p_vaddr & ~(ph->p_align - 1);
- ElfW(Addr) mapend = ((ph->p_vaddr + ph->p_memsz
- + ph->p_align - 1)
- & ~(ph->p_align - 1));
- munmap ((caddr_t) mapstart, mapend - mapstart);
- }
-
- /* Finally, unlink the data structure and free it. */
- map->l_prev->l_next = map->l_next;
- if (map->l_next)
- map->l_next->l_prev = map->l_prev;
- if (map->l_searchlist)
- free (map->l_searchlist);
- free (map);
- }
- }
-
- free (list);
+ _dl_close (handle);
}
return _dlerror_run (doit) ? -1 : 0;
diff --git a/elf/dlopen.c b/elf/dlopen.c
index 74ab8bb715..e261fcadd9 100644
--- a/elf/dlopen.c
+++ b/elf/dlopen.c
@@ -28,7 +28,7 @@ dlopen (const char *file, int mode)
void doit (void)
{
- new = _dl_open (_dl_loaded, file, mode);
+ new = _dl_open (_dl_loaded, file ?: "", mode);
}
return _dlerror_run (doit) ? NULL : new;
diff --git a/elf/link.h b/elf/link.h
index 6d284cbbde..89dfa2087f 100644
--- a/elf/link.h
+++ b/elf/link.h
@@ -106,6 +106,9 @@ struct link_map
struct link_map **l_searchlist;
unsigned int l_nsearchlist;
+ /* Dependent object that first caused this object to be loaded. */
+ struct link_map *l_loader;
+
/* Symbol hash table. */
ElfW(Word) l_nbuckets;
const ElfW(Word) *l_buckets, *l_chain;
@@ -114,14 +117,14 @@ struct link_map
enum /* Where this object came from. */
{
lt_executable, /* The main executable program. */
- lt_interpreter, /* The interpreter: the dynamic linker. */
lt_library, /* Library needed by main executable. */
lt_loaded, /* Extra run-time loaded shared object. */
} l_type:2;
unsigned int l_relocated:1; /* Nonzero if object's relocations done. */
unsigned int l_init_called:1; /* Nonzero if DT_INIT function called. */
unsigned int l_init_running:1; /* Nonzero while DT_INIT function runs. */
- unsigned int l_reserved:3; /* Reserved for internal use. */
+ unsigned int l_global:1; /* Nonzero if object in _dl_global_scope. */
+ unsigned int l_reserved:2; /* Reserved for internal use. */
};
/* Internal functions of the run-time dynamic linker.
@@ -188,12 +191,7 @@ extern int _dlerror_run (void (*operate) (void));
LOADER's DT_RPATH is used in searching for NAME.
If the object is already opened, returns its existing map. */
extern struct link_map *_dl_map_object (struct link_map *loader,
- const char *name);
-
-/* Similar, but file found at REALNAME and opened on FD.
- REALNAME must malloc'd storage and is used in internal data structures. */
-extern struct link_map *_dl_map_object_from_fd (const char *name,
- int fd, char *realname);
+ const char *name, int type);
/* Call _dl_map_object on the dependencies of MAP, and
set up MAP->l_searchlist. */
@@ -210,21 +208,24 @@ extern void _dl_setup_hash (struct link_map *map);
extern struct link_map *_dl_open (struct link_map *loader,
const char *name, int mode);
+/* Close an object previously opened by _dl_open. */
+extern void _dl_close (struct link_map *map);
/* Search loaded objects' symbol tables for a definition of the symbol
referred to by UNDEF. *SYM is the symbol table entry containing the
reference; it is replaced with the defining symbol, and the base load
- address of the defining object is returned. Each of SYMBOL_SCOPE[0] and
- SYMBOL_SCOPE[1] that is not null and their dependencies are searched to
- resolve the name. REFERENCE_NAME should name the object containing the
- reference; it is used in error messages. RELOC_ADDR is the address
- being fixed up and the chosen symbol cannot be one with this value. If
- NOPLT is nonzero, then the reference must not be resolved to a PLT
- entry. */
+ address of the defining object is returned. SYMBOL_SCOPE is a
+ null-terminated list of object scopes to search; each object's
+ l_searchlist (i.e. the segment of the dependency tree starting at that
+ object) is searched in turn. REFERENCE_NAME should name the object
+ containing the reference; it is used in error messages. RELOC_ADDR is
+ the address being fixed up and the chosen symbol cannot be one with this
+ value. If NOPLT is nonzero, then the reference must not be resolved to
+ a PLT entry. */
extern ElfW(Addr) _dl_lookup_symbol (const char *undef,
const ElfW(Sym) **sym,
- struct link_map *symbol_scope[2],
+ struct link_map *symbol_scope[],
const char *reference_name,
ElfW(Addr) reloc_addr,
int noplt);
@@ -236,11 +237,33 @@ extern ElfW(Addr) _dl_symbol_value (struct link_map *map, const char *name);
/* Structure describing the dynamic linker itself. */
extern struct link_map _dl_rtld_map;
-/* List of objects currently loaded. */
-extern struct link_map *_dl_loaded;
+/* The list of objects currently loaded is the third element of the
+ `_dl_default_scope' array, and the fourth element is always null.
+ This leaves two slots before it that are used when resolving
+ DT_SYMBOLIC objects' references one after it for normal references
+ (see below). */
+#define _dl_loaded (_dl_default_scope[2])
+extern struct link_map *_dl_default_scope[5];
+
+/* Null-terminated list of objects in the dynamic `global scope'. The
+ list starts at [2]; i.e. &_dl_global_scope[2] is the argument
+ passed to _dl_lookup_symbol to search the global scope. To search
+ a specific object and its dependencies in preference to the global
+ scope, fill in the [1] slot and pass its address; for two specific
+ object scopes, fill [0] and [1]. The list is double-terminated; to
+ search the global scope and then a specific object and its
+ dependencies, set *_dl_global_scope_end. This variable initially
+ points to _dl_default_scope, and _dl_loaded is always kept in [2]
+ of this list. A new list is malloc'd when new objects are loaded
+ with RTLD_GLOBAL. */
+extern struct link_map **_dl_global_scope, **_dl_global_scope_end;
+extern size_t _dl_global_scope_alloc; /* Number of slots malloc'd. */
+
+/* Hack _dl_global_scope[0] and [1] as necessary, and return a pointer into
+ _dl_global_scope that should be passed to _dl_lookup_symbol for symbol
+ references made in the object MAP's relocations. */
+extern struct link_map **_dl_object_relocation_scope (struct link_map *map);
-/* Tail of that list which were loaded at startup. */
-extern struct link_map *_dl_startup_loaded;
/* Allocate a `struct link_map' for a new object being loaded,
and enter it into the _dl_loaded list. */
@@ -248,8 +271,11 @@ extern struct link_map *_dl_new_object (char *realname, const char *libname,
int type);
/* Relocate the given object (if it hasn't already been).
+ SCOPE is passed to _dl_lookup_symbol in symbol lookups.
If LAZY is nonzero, don't relocate its PLT. */
-extern void _dl_relocate_object (struct link_map *map, int lazy);
+extern void _dl_relocate_object (struct link_map *map,
+ struct link_map *scope[],
+ int lazy);
/* Return the address of the next initializer function for MAP or one of
its dependencies that has not yet been run. When there are no more
diff --git a/elf/rtld.c b/elf/rtld.c
index bc1f71bd4e..66477274e5 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -75,13 +75,6 @@ _dl_start (void *arg)
/* Relocate ourselves so we can do normal function calls and
data access using the global offset table. */
- /* We must initialize `l_type' to make sure it is not `lt_interpreter'.
- That is the type to describe us, but not during bootstrapping--it
- indicates to elf_machine_rel{,a} that we were already relocated during
- bootstrapping, so it must anti-perform each bootstrapping relocation
- before applying the final relocation when ld.so is linked in as
- normal a shared library. */
- bootstrap_map.l_type = lt_library;
ELF_DYNAMIC_RELOCATE (&bootstrap_map, 0, NULL);
@@ -178,7 +171,7 @@ of this helper program; chances are you did not intend to run this program.\n",
--_dl_argc;
++_dl_argv;
- l = _dl_map_object (NULL, _dl_argv[0]);
+ l = _dl_map_object (NULL, _dl_argv[0], lt_library);
phdr = l->l_phdr;
phent = l->l_phnum;
l->l_name = (char *) "";
@@ -188,7 +181,7 @@ of this helper program; chances are you did not intend to run this program.\n",
{
/* Create a link_map for the executable itself.
This will be what dlopen on "" returns. */
- l = _dl_new_object ((char *) "", "", lt_executable);
+ l = _dl_new_object ((char *) "", "", lt_library);
l->l_phdr = phdr;
l->l_phnum = phent;
interpreter_name = 0;
@@ -245,7 +238,7 @@ of this helper program; chances are you did not intend to run this program.\n",
/* Put the link_map for ourselves on the chain so it can be found by
name. */
_dl_rtld_map.l_name = (char *) _dl_rtld_map.l_libname = interpreter_name;
- _dl_rtld_map.l_type = lt_interpreter;
+ _dl_rtld_map.l_type = lt_library;
while (l->l_next)
l = l->l_next;
l->l_next = &_dl_rtld_map;
@@ -293,9 +286,9 @@ of this helper program; chances are you did not intend to run this program.\n",
for (i = 1; i < _dl_argc; ++i)
{
const ElfW(Sym) *ref = NULL;
- struct link_map *scope[2] ={ _dl_loaded, NULL };
- ElfW(Addr) loadbase
- = _dl_lookup_symbol (_dl_argv[i], &ref, scope, "argument", 0, 0);
+ ElfW(Addr) loadbase = _dl_lookup_symbol (_dl_argv[i], &ref,
+ &_dl_default_scope[2],
+ "argument", 0, 0);
char buf[20], *bp;
buf[sizeof buf - 1] = '\0';
bp = _itoa (ref->st_value, &buf[sizeof buf - 1], 16, 0);
@@ -314,35 +307,41 @@ of this helper program; chances are you did not intend to run this program.\n",
lazy = !_dl_secure && *(getenv ("LD_BIND_NOW") ?: "") == '\0';
- /* Now we have all the objects loaded. Relocate them all except for
- the dynamic linker itself. We do this in reverse order so that
- copy relocs of earlier objects overwrite the data written by later
- objects. We do not re-relocate the dynamic linker itself in this
- loop because that could result in the GOT entries for functions we
- call being changed, and that would break us. It is safe to
- relocate the dynamic linker out of order because it has no copy
- relocs (we know that because it is self-contained). */
- l = _dl_loaded;
- while (l->l_next)
- l = l->l_next;
- do
- {
- if (l != &_dl_rtld_map)
- _dl_relocate_object (l, lazy);
- l = l->l_prev;
- } while (l);
-
- /* Do any necessary cleanups for the startup OS interface code.
- We do these now so that no calls are made after rtld re-relocation
- which might be resolved to different functions than we expect.
- We cannot do this before relocating the other objects because
- _dl_relocate_object might need to call `mprotect' for DT_TEXTREL. */
- _dl_sysdep_start_cleanup ();
-
- if (_dl_rtld_map.l_opencount > 0)
- /* There was an explicit ref to the dynamic linker as a shared lib.
- Re-relocate ourselves with user-controlled symbol definitions. */
- _dl_relocate_object (&_dl_rtld_map, lazy);
+ {
+ /* Now we have all the objects loaded. Relocate them all except for
+ the dynamic linker itself. We do this in reverse order so that copy
+ relocs of earlier objects overwrite the data written by later
+ objects. We do not re-relocate the dynamic linker itself in this
+ loop because that could result in the GOT entries for functions we
+ call being changed, and that would break us. It is safe to relocate
+ the dynamic linker out of order because it has no copy relocs (we
+ know that because it is self-contained). */
+
+ l = _dl_loaded;
+ while (l->l_next)
+ l = l->l_next;
+ do
+ {
+ if (l != &_dl_rtld_map)
+ {
+ _dl_relocate_object (l, _dl_object_relocation_scope (l), lazy);
+ *_dl_global_scope_end = NULL;
+ }
+ l = l->l_prev;
+ } while (l);
+
+ /* Do any necessary cleanups for the startup OS interface code.
+ We do these now so that no calls are made after rtld re-relocation
+ which might be resolved to different functions than we expect.
+ We cannot do this before relocating the other objects because
+ _dl_relocate_object might need to call `mprotect' for DT_TEXTREL. */
+ _dl_sysdep_start_cleanup ();
+
+ if (_dl_rtld_map.l_opencount > 0)
+ /* There was an explicit ref to the dynamic linker as a shared lib.
+ Re-relocate ourselves with user-controlled symbol definitions. */
+ _dl_relocate_object (&_dl_rtld_map, &_dl_default_scope[2], 0);
+ }
/* Tell the debugger where to find the map of loaded objects. */
_dl_r_debug.r_version = 1 /* R_DEBUG_VERSION XXX */;
diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h
index b52e604d4a..bcd388fd20 100644
--- a/sysdeps/i386/dl-machine.h
+++ b/sysdeps/i386/dl-machine.h
@@ -100,7 +100,7 @@ elf_machine_rel (struct link_map *map,
*reloc_addr = sym ? (loadbase + sym->st_value) : 0;
break;
case R_386_32:
- if (map->l_type == lt_interpreter)
+ if (resolve && map == &_dl_rtld_map)
{
/* Undo the relocation done here during bootstrapping. Now we will
relocate it anew, possibly using a binding found in the user
@@ -117,7 +117,7 @@ elf_machine_rel (struct link_map *map,
*reloc_addr += sym ? (loadbase + sym->st_value) : 0;
break;
case R_386_RELATIVE:
- if (map->l_type != lt_interpreter) /* Already done in dynamic linker. */
+ if (!resolve || map != &_dl_rtld_map) /* Already done in rtld itself. */
*reloc_addr += map->l_addr;
break;
case R_386_PC32:
@@ -229,9 +229,9 @@ _dl_start_user:\n\
leal (%esp,%eax,4), %esp\n\
# Push back the modified argument count.\n\
pushl %ecx\n\
- # Push _dl_loaded as argument in _dl_init_next call below.\n\
- movl _dl_loaded@GOT(%ebx), %eax\n\
- movl (%eax), %esi\n\
+ # Push _dl_default_scope[2] as argument in _dl_init_next call below.\n\
+ movl _dl_default_scope@GOT(%ebx), %eax\n\
+ movl 8(%eax), %esi\n\
0: pushl %esi\n\
# Call _dl_init_next to return the address of an initializer\n\
# function to run.\n\
diff --git a/sysdeps/m68k/dl-machine.h b/sysdeps/m68k/dl-machine.h
index 74e88749e6..415216b14a 100644
--- a/sysdeps/m68k/dl-machine.h
+++ b/sysdeps/m68k/dl-machine.h
@@ -252,9 +252,9 @@ _dl_start_user:
lea (%sp, %d0*4), %sp
| Push back the modified argument count.
move.l %d1, -(%sp)
-0: | Push _dl_loaded as argument in _dl_init_next call below.
- move.l ([_dl_loaded@GOT, %a5]), %d2
-0: move.l %d2, -(%sp)
+0: | Push _dl_default_scope[2] as argument in _dl_init_next call below.
+ move.l ([_dl_default_scope@GOT, %a5]), %d2
+0: move.l (%d2, 8), -(%sp)
| Call _dl_init_next to return the address of an initializer
| function to run.
bsr.l _dl_init_next@PLTPC