1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-29 11:41:21 +03:00

* 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:
Roland McGrath
1996-06-10 20:19:39 +00:00
parent 567c63af19
commit ba79d61b44
17 changed files with 659 additions and 391 deletions

View File

@ -1,5 +1,89 @@
Mon Jun 10 06:14:03 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu> 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. * elf/link.h: Include elfclass.h to define __ELF_NATIVE_CLASS.
(ElfW, ELFW): Use it. (ElfW, ELFW): Use it.
* elf/Makefile (headers): Add elfclass.h. * elf/Makefile (headers): Add elfclass.h.

View File

@ -496,7 +496,7 @@ LDFLAGS-c.so += -e __libc_print_version
elfobjdir := $(firstword $(objdir) $(..)elf) elfobjdir := $(firstword $(objdir) $(..)elf)
$(common-objpfx)libc.so: $(elfobjdir)/soinit.so \ $(common-objpfx)libc.so: $(elfobjdir)/soinit.so \
$(common-objpfx)libc_pic.a \ $(common-objpfx)libc_pic.a \
$(elfobjdir)/sofini.so $(elfobjdir)/sofini.so $(elfobjdir)/ld.so
$(build-shlib) $(build-shlib)
ifdef libc.so-version ifdef libc.so-version

View File

@ -21,7 +21,8 @@
subdir := elf subdir := elf
headers = elf.h elfclass.h link.h dlfcn.h 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 # The core dynamic linking functions are in libc for the static and
# profiled libraries. # profiled libraries.
@ -54,7 +55,7 @@ install-bin = ldd
# to run programs during the `make others' pass. # to run programs during the `make others' pass.
lib-noranlib: $(objpfx)ld.so $(addprefix $(objpfx),$(extra-objs)) 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 extra-objs += linux-compat.so
install-others += $(slibdir)/ld-linux.so.1 install-others += $(slibdir)/ld-linux.so.1
lib-noranlib: $(objpfx)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. # dynamic linker shared objects below.
$(objpfx)librtld.so: $(objpfx)dl-allobjs.so \ $(objpfx)librtld.so: $(objpfx)dl-allobjs.so \
$(patsubst %,$(common-objpfx)lib%_pic.a,\ $(patsubst %,$(common-objpfx)lib%_pic.a,\
elf c $(LDLIBS-c.so:-l%=%)) c $(LDLIBS-c.so:-l%=%))
$(reloc-link) '-Wl,-(' $^ -lgcc '-Wl,-)' $(reloc-link) '-Wl,-(' $^ -lgcc '-Wl,-)'
$(objpfx)ld.so: $(objpfx)librtld.so $(objpfx)ld.so: $(objpfx)librtld.so

107
elf/dl-close.c Normal file
View 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);
}

View File

@ -62,7 +62,9 @@ _dl_map_object_deps (struct link_map *map)
{ {
/* Map in the needed object. */ /* Map in the needed object. */
struct link_map *dep 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) if (dep->l_reserved)
/* This object is already in the search list we are /* This object is already in the search list we are

View File

@ -63,152 +63,14 @@ int _dl_zerofd = -1;
size_t _dl_pagesize; 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 /* Map in the shared object NAME, actually located in REALNAME, and already
opened on FD. */ opened on FD. */
struct link_map * 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; void *file_mapping = NULL;
size_t mapping_size = 0; size_t mapping_size = 0;
@ -218,7 +80,17 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname)
(void) __close (fd); (void) __close (fd);
if (file_mapping) if (file_mapping)
__munmap (file_mapping, mapping_size); __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, 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))) if (header->e_phentsize != sizeof (ElfW(Phdr)))
LOSE ("ELF file's phentsize not the expected size"); 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) if (_dl_zerofd == -1)
{ {
_dl_zerofd = _dl_sysdep_open_zero_fill (); _dl_zerofd = _dl_sysdep_open_zero_fill ();
if (_dl_zerofd == -1) 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 /* Extract the remaining details we need from the ELF header
and then map in the program header table. */ and then map in the program header table. */
l->l_entry = header->e_entry; 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. */ /* We are done mapping in the file. We no longer need the descriptor. */
__close (fd); __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) if (l->l_ld == 0)
{ {
@ -484,3 +363,142 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname)
return l; 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);
}

View File

@ -50,7 +50,7 @@ _dl_elf_hash (const char *name)
ElfW(Addr) ElfW(Addr)
_dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref, _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, const char *reference_name,
ElfW(Addr) reloc_addr, ElfW(Addr) reloc_addr,
int noplt) int noplt)
@ -65,69 +65,68 @@ _dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref,
struct link_map **scope, *map; struct link_map **scope, *map;
/* Search the relevant loaded objects for a definition. */ /* Search the relevant loaded objects for a definition. */
for (scope = symbol_scope; scope < &symbol_scope[2]; ++scope) for (scope = symbol_scope; *scope; ++scope)
if (*scope) for (i = 0; i < (*scope)->l_nsearchlist; ++i)
for (i = 0; i < (*scope)->l_nsearchlist; ++i) {
{ const ElfW(Sym) *symtab;
const ElfW(Sym) *symtab; const char *strtab;
const char *strtab; ElfW(Word) symidx;
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); 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); 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 /* Search the appropriate hash bucket in this object's symbol table
for a definition for the same symbol name. */ for a definition for the same symbol name. */
for (symidx = map->l_buckets[hash % map->l_nbuckets]; for (symidx = map->l_buckets[hash % map->l_nbuckets];
symidx != STN_UNDEF; symidx != STN_UNDEF;
symidx = map->l_chain[symidx]) symidx = map->l_chain[symidx])
{ {
const ElfW(Sym) *sym = &symtab[symidx]; const ElfW(Sym) *sym = &symtab[symidx];
if (sym->st_value == 0 || /* No value. */ if (sym->st_value == 0 || /* No value. */
/* Cannot resolve to the location being filled in. */ /* Cannot resolve to the location being filled in. */
reloc_addr == map->l_addr + sym->st_value || reloc_addr == map->l_addr + sym->st_value ||
(noplt && sym->st_shndx == SHN_UNDEF)) /* Reject PLT. */ (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; continue;
}
switch (ELFW(ST_TYPE) (sym->st_info)) if (sym != *ref && strcmp (strtab + sym->st_name, undef_name))
{ /* Not the symbol we are looking for. */
case STT_NOTYPE: continue;
case STT_FUNC:
case STT_OBJECT:
break;
default:
/* Not a code/data definition. */
continue;
}
if (sym != *ref && strcmp (strtab + sym->st_name, undef_name)) switch (ELFW(ST_BIND) (sym->st_info))
/* Not the symbol we are looking for. */ {
continue; case STB_GLOBAL:
/* Global definition. Just what we need. */
switch (ELFW(ST_BIND) (sym->st_info)) *ref = sym;
{ return map->l_addr;
case STB_GLOBAL: case STB_WEAK:
/* Global definition. Just what we need. */ /* Weak definition. Use this value if we don't find
*ref = sym; another. */
return map->l_addr; if (! weak_value.s)
case STB_WEAK: {
/* Weak definition. Use this value if we don't find weak_value.s = sym;
another. */ weak_value.a = map->l_addr;
if (! weak_value.s) }
{ break;
weak_value.s = sym; default:
weak_value.a = map->l_addr; /* Local symbols are ignored. */
} break;
break; }
default: }
/* Local symbols are ignored. */ }
break;
}
}
}
if (weak_value.s == NULL && ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK) if (weak_value.s == NULL && ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
{ {

View File

@ -1,5 +1,5 @@
/* Storage management for the chain of loaded shared objects. /* 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. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
@ -24,11 +24,8 @@ Cambridge, MA 02139, USA. */
#include <errno.h> #include <errno.h>
/* List of objects currently loaded. */ /* List of objects currently loaded is [2] of this, aka _dl_loaded. */
struct link_map *_dl_loaded; struct link_map *_dl_default_scope[5];
/* Tail of that list which were loaded at startup. */
struct link_map *_dl_startup_loaded;
/* Allocate a `struct link_map' for a new object being loaded, /* Allocate a `struct link_map' for a new object being loaded,
and enter it into the _dl_loaded list. */ 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); struct link_map *new = malloc (sizeof *new);
if (! new) if (! new)
_dl_signal_error (ENOMEM, libname, return NULL;
"cannot allocate shared object descriptor");
memset (new, 0, sizeof *new); memset (new, 0, sizeof *new);
new->l_name = realname; new->l_name = realname;

View File

@ -19,6 +19,10 @@ Cambridge, MA 02139, USA. */
#include <link.h> #include <link.h>
#include <dlfcn.h> #include <dlfcn.h>
#include <stdlib.h>
#include <errno.h>
size_t _dl_global_scope_alloc;
struct link_map * struct link_map *
_dl_open (struct link_map *parent, const char *file, int mode) _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; struct link_map *new, *l;
ElfW(Addr) init; ElfW(Addr) init;
/* Load the named object. */ /* 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. */ /* Load that object's dependencies. */
_dl_map_object_deps (new); _dl_map_object_deps (new);
/* Relocate the objects loaded. */
for (l = new; l; l = l->l_next) /* Relocate the objects loaded. We do this in reverse order so that copy
if (! l->l_relocated) relocs of earlier objects overwrite the data written by later objects. */
_dl_relocate_object (l, (mode & RTLD_BINDING_MASK) == RTLD_LAZY);
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. */ /* Run the initializer functions of new objects. */
while (init = _dl_init_next (new)) while (init = _dl_init_next (new))

View File

@ -26,7 +26,7 @@ Cambridge, MA 02139, USA. */
void 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) if (l->l_relocated)
return; 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); = ((void *) l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr);
ElfW(Addr) resolve (const ElfW(Sym) **ref, ElfW(Addr) resolve (const ElfW(Sym) **ref,
ElfW(Addr) reloc_addr, int noplt) 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, return _dl_lookup_symbol (strtab + (*ref)->st_name, ref, scope,
l->l_name, reloc_addr, noplt); 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); ELF_DYNAMIC_RELOCATE (l, lazy, resolve);
} }
/* Set up the PLT so its unrelocated entries will /* Set up the PLT so its unrelocated entries will jump to
jump to _dl_runtime_resolve, which will relocate them. */ _dl_runtime_resolve (dl-runtime.c), which will relocate them. */
elf_machine_runtime_setup (l, lazy); elf_machine_runtime_setup (l, lazy);
/* Mark the object so we know ths work has been done. */
l->l_relocated = 1; l->l_relocated = 1;
if (l->l_info[DT_TEXTREL]) 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"); "can't restore segment prot after reloc");
} }
} }
} }

View File

@ -20,6 +20,54 @@ Cambridge, MA 02139, USA. */
#include <link.h> #include <link.h>
#include "dynamic-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. */ /* Figure out the right type, Rel or Rela. */
#define elf_machine_rel 1 #define elf_machine_rel 1
#define elf_machine_rela 2 #define elf_machine_rela 2
@ -67,17 +115,21 @@ fixup (
= (const void *) (l->l_addr + l->l_info[DT_JMPREL]->d_un.d_ptr + = (const void *) (l->l_addr + l->l_info[DT_JMPREL]->d_un.d_ptr +
reloc_offset); 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) resolve (const ElfW(Sym) **ref,
ElfW(Addr) reloc_addr, int noplt) ElfW(Addr) reloc_addr, int noplt)
{ {
struct link_map *scope[2] = { _dl_loaded, NULL };
return _dl_lookup_symbol (strtab + (*ref)->st_name, ref, return _dl_lookup_symbol (strtab + (*ref)->st_name, ref,
scope, l->l_name, reloc_addr, noplt); scope, l->l_name, reloc_addr, noplt);
} }
/* Perform the specified relocation. */
elf_machine_relplt (l, reloc, &symtab[ELFW(R_SYM) (reloc->r_info)], resolve); 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); return *(ElfW(Addr) *) (l->l_addr + reloc->r_offset);
} }

View File

@ -19,81 +19,13 @@ Cambridge, MA 02139, USA. */
#include <link.h> #include <link.h>
#include <dlfcn.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 int
dlclose (void *handle) dlclose (void *handle)
{ {
void doit (void) void doit (void)
{ {
struct link_map *map = handle; _dl_close (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);
} }
return _dlerror_run (doit) ? -1 : 0; return _dlerror_run (doit) ? -1 : 0;

View File

@ -28,7 +28,7 @@ dlopen (const char *file, int mode)
void doit (void) void doit (void)
{ {
new = _dl_open (_dl_loaded, file, mode); new = _dl_open (_dl_loaded, file ?: "", mode);
} }
return _dlerror_run (doit) ? NULL : new; return _dlerror_run (doit) ? NULL : new;

View File

@ -106,6 +106,9 @@ struct link_map
struct link_map **l_searchlist; struct link_map **l_searchlist;
unsigned int l_nsearchlist; unsigned int l_nsearchlist;
/* Dependent object that first caused this object to be loaded. */
struct link_map *l_loader;
/* Symbol hash table. */ /* Symbol hash table. */
ElfW(Word) l_nbuckets; ElfW(Word) l_nbuckets;
const ElfW(Word) *l_buckets, *l_chain; const ElfW(Word) *l_buckets, *l_chain;
@ -114,14 +117,14 @@ struct link_map
enum /* Where this object came from. */ enum /* Where this object came from. */
{ {
lt_executable, /* The main executable program. */ lt_executable, /* The main executable program. */
lt_interpreter, /* The interpreter: the dynamic linker. */
lt_library, /* Library needed by main executable. */ lt_library, /* Library needed by main executable. */
lt_loaded, /* Extra run-time loaded shared object. */ lt_loaded, /* Extra run-time loaded shared object. */
} l_type:2; } l_type:2;
unsigned int l_relocated:1; /* Nonzero if object's relocations done. */ 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_called:1; /* Nonzero if DT_INIT function called. */
unsigned int l_init_running:1; /* Nonzero while DT_INIT function runs. */ 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. /* 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. LOADER's DT_RPATH is used in searching for NAME.
If the object is already opened, returns its existing map. */ If the object is already opened, returns its existing map. */
extern struct link_map *_dl_map_object (struct link_map *loader, extern struct link_map *_dl_map_object (struct link_map *loader,
const char *name); const char *name, int type);
/* 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);
/* Call _dl_map_object on the dependencies of MAP, and /* Call _dl_map_object on the dependencies of MAP, and
set up MAP->l_searchlist. */ 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, extern struct link_map *_dl_open (struct link_map *loader,
const char *name, int mode); 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 /* Search loaded objects' symbol tables for a definition of the symbol
referred to by UNDEF. *SYM is the symbol table entry containing the referred to by UNDEF. *SYM is the symbol table entry containing the
reference; it is replaced with the defining symbol, and the base load 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 address of the defining object is returned. SYMBOL_SCOPE is a
SYMBOL_SCOPE[1] that is not null and their dependencies are searched to null-terminated list of object scopes to search; each object's
resolve the name. REFERENCE_NAME should name the object containing the l_searchlist (i.e. the segment of the dependency tree starting at that
reference; it is used in error messages. RELOC_ADDR is the address object) is searched in turn. REFERENCE_NAME should name the object
being fixed up and the chosen symbol cannot be one with this value. If containing the reference; it is used in error messages. RELOC_ADDR is
NOPLT is nonzero, then the reference must not be resolved to a PLT the address being fixed up and the chosen symbol cannot be one with this
entry. */ 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, extern ElfW(Addr) _dl_lookup_symbol (const char *undef,
const ElfW(Sym) **sym, const ElfW(Sym) **sym,
struct link_map *symbol_scope[2], struct link_map *symbol_scope[],
const char *reference_name, const char *reference_name,
ElfW(Addr) reloc_addr, ElfW(Addr) reloc_addr,
int noplt); 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. */ /* Structure describing the dynamic linker itself. */
extern struct link_map _dl_rtld_map; extern struct link_map _dl_rtld_map;
/* List of objects currently loaded. */ /* The list of objects currently loaded is the third element of the
extern struct link_map *_dl_loaded; `_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, /* Allocate a `struct link_map' for a new object being loaded,
and enter it into the _dl_loaded list. */ 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); int type);
/* Relocate the given object (if it hasn't already been). /* 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. */ 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 /* 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 its dependencies that has not yet been run. When there are no more

View File

@ -75,13 +75,6 @@ _dl_start (void *arg)
/* Relocate ourselves so we can do normal function calls and /* Relocate ourselves so we can do normal function calls and
data access using the global offset table. */ 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); 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_argc;
++_dl_argv; ++_dl_argv;
l = _dl_map_object (NULL, _dl_argv[0]); l = _dl_map_object (NULL, _dl_argv[0], lt_library);
phdr = l->l_phdr; phdr = l->l_phdr;
phent = l->l_phnum; phent = l->l_phnum;
l->l_name = (char *) ""; 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. /* Create a link_map for the executable itself.
This will be what dlopen on "" returns. */ 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_phdr = phdr;
l->l_phnum = phent; l->l_phnum = phent;
interpreter_name = 0; 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 /* Put the link_map for ourselves on the chain so it can be found by
name. */ name. */
_dl_rtld_map.l_name = (char *) _dl_rtld_map.l_libname = interpreter_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) while (l->l_next)
l = l->l_next; l = l->l_next;
l->l_next = &_dl_rtld_map; 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) for (i = 1; i < _dl_argc; ++i)
{ {
const ElfW(Sym) *ref = NULL; const ElfW(Sym) *ref = NULL;
struct link_map *scope[2] ={ _dl_loaded, NULL }; ElfW(Addr) loadbase = _dl_lookup_symbol (_dl_argv[i], &ref,
ElfW(Addr) loadbase &_dl_default_scope[2],
= _dl_lookup_symbol (_dl_argv[i], &ref, scope, "argument", 0, 0); "argument", 0, 0);
char buf[20], *bp; char buf[20], *bp;
buf[sizeof buf - 1] = '\0'; buf[sizeof buf - 1] = '\0';
bp = _itoa (ref->st_value, &buf[sizeof buf - 1], 16, 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'; 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 /* Now we have all the objects loaded. Relocate them all except for
copy relocs of earlier objects overwrite the data written by later the dynamic linker itself. We do this in reverse order so that copy
objects. We do not re-relocate the dynamic linker itself in this relocs of earlier objects overwrite the data written by later
loop because that could result in the GOT entries for functions we objects. We do not re-relocate the dynamic linker itself in this
call being changed, and that would break us. It is safe to loop because that could result in the GOT entries for functions we
relocate the dynamic linker out of order because it has no copy call being changed, and that would break us. It is safe to relocate
relocs (we know that because it is self-contained). */ the dynamic linker out of order because it has no copy relocs (we
l = _dl_loaded; know that because it is self-contained). */
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. l = _dl_loaded;
We do these now so that no calls are made after rtld re-relocation while (l->l_next)
which might be resolved to different functions than we expect. l = l->l_next;
We cannot do this before relocating the other objects because do
_dl_relocate_object might need to call `mprotect' for DT_TEXTREL. */ {
_dl_sysdep_start_cleanup (); 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) /* Do any necessary cleanups for the startup OS interface code.
/* There was an explicit ref to the dynamic linker as a shared lib. We do these now so that no calls are made after rtld re-relocation
Re-relocate ourselves with user-controlled symbol definitions. */ which might be resolved to different functions than we expect.
_dl_relocate_object (&_dl_rtld_map, lazy); 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. */ /* Tell the debugger where to find the map of loaded objects. */
_dl_r_debug.r_version = 1 /* R_DEBUG_VERSION XXX */; _dl_r_debug.r_version = 1 /* R_DEBUG_VERSION XXX */;

View File

@ -100,7 +100,7 @@ elf_machine_rel (struct link_map *map,
*reloc_addr = sym ? (loadbase + sym->st_value) : 0; *reloc_addr = sym ? (loadbase + sym->st_value) : 0;
break; break;
case R_386_32: 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 /* Undo the relocation done here during bootstrapping. Now we will
relocate it anew, possibly using a binding found in the user 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; *reloc_addr += sym ? (loadbase + sym->st_value) : 0;
break; break;
case R_386_RELATIVE: 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; *reloc_addr += map->l_addr;
break; break;
case R_386_PC32: case R_386_PC32:
@ -229,9 +229,9 @@ _dl_start_user:\n\
leal (%esp,%eax,4), %esp\n\ leal (%esp,%eax,4), %esp\n\
# Push back the modified argument count.\n\ # Push back the modified argument count.\n\
pushl %ecx\n\ pushl %ecx\n\
# Push _dl_loaded as argument in _dl_init_next call below.\n\ # Push _dl_default_scope[2] as argument in _dl_init_next call below.\n\
movl _dl_loaded@GOT(%ebx), %eax\n\ movl _dl_default_scope@GOT(%ebx), %eax\n\
movl (%eax), %esi\n\ movl 8(%eax), %esi\n\
0: pushl %esi\n\ 0: pushl %esi\n\
# Call _dl_init_next to return the address of an initializer\n\ # Call _dl_init_next to return the address of an initializer\n\
# function to run.\n\ # function to run.\n\

View File

@ -252,9 +252,9 @@ _dl_start_user:
lea (%sp, %d0*4), %sp lea (%sp, %d0*4), %sp
| Push back the modified argument count. | Push back the modified argument count.
move.l %d1, -(%sp) move.l %d1, -(%sp)
0: | Push _dl_loaded as argument in _dl_init_next call below. 0: | Push _dl_default_scope[2] as argument in _dl_init_next call below.
move.l ([_dl_loaded@GOT, %a5]), %d2 move.l ([_dl_default_scope@GOT, %a5]), %d2
0: move.l %d2, -(%sp) 0: move.l (%d2, 8), -(%sp)
| Call _dl_init_next to return the address of an initializer | Call _dl_init_next to return the address of an initializer
| function to run. | function to run.
bsr.l _dl_init_next@PLTPC bsr.l _dl_init_next@PLTPC