* 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.
This commit is contained in:
parent
567c63af19
commit
ba79d61b44
84
ChangeLog
84
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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
107
elf/dl-close.c
Normal file
107
elf/dl-close.c
Normal file
@ -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);
|
||||
}
|
@ -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
|
||||
|
314
elf/dl-load.c
314
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);
|
||||
}
|
||||
|
113
elf/dl-lookup.c
113
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;
|
||||
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];
|
||||
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);
|
||||
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];
|
||||
/* 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. */
|
||||
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_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. */
|
||||
continue;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
68
elf/link.h
68
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
|
||||
|
79
elf/rtld.c
79
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);
|
||||
{
|
||||
/* 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). */
|
||||
|
||||
/* 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 ();
|
||||
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);
|
||||
|
||||
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);
|
||||
/* 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 */;
|
||||
|
@ -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\
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user