Tue Jun 4 18:57:57 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>

* elf/dladdr.c: Remove #include <setjmp.h>, we don't use it.

	* shlib-versions: Set libdl=2.

	* elf/dl-deps.c (_dl_map_object_deps): Use a linked list of alloca'd
 	elements and then scan it to fill the single malloc'd array, instead
 	of using realloc to grow the array in the first pass.  _dl_map_object
	may do some mallocs that break our stream of reallocs, and the minimal
	realloc can't handle that.

	* elf/dl-init.c (_dl_init_next): Take argument, link_map whose
 	searchlist describes the piece of the DT_NEEDED graph to be
 	initialized.
	* elf/link.h: Update prototype.
	* sysdeps/i386/dl-machine.h (RTLD_START): Pass _dl_loaded as argument
	to _dl_init_next.
	* sysdeps/m68k/dl-machine.h: Likewise.
	* elf/dl-deps.c (_dl_open): Pass new object as arg to _dl_init_next.

	* elf/link.h (struct link_map): Add `l_reserved' member, soaking up
	extra bits in last byte.
	* elf/dl-deps.c (_dl_map_object_deps): Use that for mark bit to avoid
	putting dup elts in search list.

	* elf/dlclose.c: Use MAP->l_searchlist to find deps to close.

	* elf/dlsym.c: Don't tweak linked list.  Scope array given to
	_dl_lookup_symbol does the right thing.
Tue Jun  4 02:25:44 1996  Roland McGrath  <roland@delasyd.gnu.ai.mit.edu>
This commit is contained in:
Roland McGrath 1996-06-04 23:06:02 +00:00
parent 14d898aef6
commit f68b86cc7b
10 changed files with 175 additions and 125 deletions

View File

@ -1,4 +1,33 @@
Tue Jun 4 02:25:44 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
Tue Jun 4 18:57:57 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
* elf/dladdr.c: Remove #include <setjmp.h>, we don't use it.
* shlib-versions: Set libdl=2.
* elf/dl-deps.c (_dl_map_object_deps): Use a linked list of alloca'd
elements and then scan it to fill the single malloc'd array, instead
of using realloc to grow the array in the first pass. _dl_map_object
may do some mallocs that break our stream of reallocs, and the minimal
realloc can't handle that.
* elf/dl-init.c (_dl_init_next): Take argument, link_map whose
searchlist describes the piece of the DT_NEEDED graph to be
initialized.
* elf/link.h: Update prototype.
* sysdeps/i386/dl-machine.h (RTLD_START): Pass _dl_loaded as argument
to _dl_init_next.
* sysdeps/m68k/dl-machine.h: Likewise.
* elf/dl-deps.c (_dl_open): Pass new object as arg to _dl_init_next.
* elf/link.h (struct link_map): Add `l_reserved' member, soaking up
extra bits in last byte.
* elf/dl-deps.c (_dl_map_object_deps): Use that for mark bit to avoid
putting dup elts in search list.
* elf/dlclose.c: Use MAP->l_searchlist to find deps to close.
* elf/dlsym.c: Don't tweak linked list. Scope array given to
_dl_lookup_symbol does the right thing.
* elf/Makefile (subdir_lib): Change this target to lib-noranlib.
(lib-noranlib): Depend on on $(extra-objs).
@ -6,6 +35,8 @@ Tue Jun 4 02:25:44 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
* errno.h: Move __END_DECLS out of #ifdef's so it matches
__BEGIN_DECLS.
Tue Jun 4 02:25:44 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
* stdio-common/vfprintf.c [USE_IN_LIBIO] (size_t): Don't define as
macro. _IO_size_t is just an alias for the real size_t anyway.

View File

@ -25,20 +25,33 @@ Cambridge, MA 02139, USA. */
void
_dl_map_object_deps (struct link_map *map)
{
unsigned int nlist = 1;
struct link_map **list = malloc (sizeof *list);
unsigned int done;
struct list
{
struct link_map *map;
struct list *next;
};
struct list head, *tailp, *scanp;
unsigned int nlist;
/* Start the search list with one element: MAP itself. */
list[0] = map;
head.map = map;
head.next = NULL;
nlist = 1;
/* Process each element of the search list, loading each of its immediate
dependencies and appending them to the list as we step through it.
This produces a flat, ordered list that represents a breadth-first
search of the dependency tree. */
for (done = 0; done < nlist; ++done)
for (scanp = tailp = &head; scanp; scanp = scanp->next)
{
struct link_map *l = list[done];
struct link_map *l = scanp->map;
/* We use `l_reserved' as a mark bit to detect objects we have
already put in the search list and avoid adding duplicate elements
later in the list. */
l->l_reserved = 1;
if (l->l_info[DT_NEEDED])
{
const char *strtab
@ -47,24 +60,42 @@ _dl_map_object_deps (struct link_map *map)
for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
if (d->d_tag == DT_NEEDED)
{
/* Extend the list and put this object on the end. */
struct link_map **n
= realloc (list, (nlist + 1) * sizeof *list);
if (n)
list = n;
/* Map in the needed object. */
struct link_map *dep
= _dl_map_object (l, strtab + d->d_un.d_val);
if (dep->l_reserved)
/* This object is already in the search list we are
building. Don't add a duplicate pointer. Release the
reference just added by _dl_map_object. */
--dep->l_opencount;
else
{
free (list);
_dl_signal_error (ENOMEM, map->l_name,
"finding dependencies");
/* Append DEP to the search list. */
tailp->next = alloca (sizeof *tailp);
tailp = tailp->next;
tailp->map = dep;
tailp->next = NULL;
++nlist;
}
list[nlist++] = _dl_map_object (l, strtab + d->d_un.d_val);
}
}
}
map->l_searchlist = list;
/* Store the search list we built in the object. It will be used for
searches in the scope of this object. */
map->l_searchlist = malloc (nlist * sizeof (struct link_map *));
map->l_nsearchlist = nlist;
nlist = 0;
for (scanp = &head; scanp; scanp = scanp->next)
{
map->l_searchlist[nlist++] = scanp->map;
/* Now clear all the mark bits we set in the objects on the search list
to avoid duplicates, so the next call starts fresh. */
scanp->map->l_reserved = 0;
}
}
@ -86,7 +117,7 @@ _dl_open (struct link_map *parent, const char *file, int mode)
_dl_relocate_object (l, (mode & RTLD_BINDING_MASK) == RTLD_LAZY);
/* Run the initializer functions of new objects. */
while (init = _dl_init_next ())
while (init = _dl_init_next (new))
(*(void (*) (void)) init) ();
return new;

View File

@ -1,5 +1,5 @@
/* Return the next shared object initializer function not yet run.
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
@ -21,45 +21,35 @@ Cambridge, MA 02139, USA. */
#include <link.h>
Elf32_Addr
_dl_init_next (void)
{
struct link_map *l;
Elf32_Addr init;
/* Run initializers for MAP and its dependencies, in inverse dependency
order (that is, leaf nodes first). */
Elf32_Addr next_init (struct link_map *l)
Elf32_Addr
_dl_init_next (struct link_map *map)
{
unsigned int i;
/* The search list for symbol lookup is a flat list in top-down
dependency order, so processing that list from back to front gets us
breadth-first leaf-to-root order. */
i = map->l_nsearchlist;
while (i-- > 0)
{
struct link_map *l = map->l_searchlist[i];
if (l->l_init_called)
/* This object is all done. */
return 0;
continue;
if (l->l_init_running)
{
/* This object's initializer was just running.
Now mark it as having run, so this object
will be skipped in the future. */
l->l_init_called = 1;
l->l_init_running = 0;
return 0;
}
if (l->l_info[DT_NEEDED])
{
/* Find each dependency in order, and see if it
needs to run an initializer. */
const char *strtab
= ((void *) l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr);
const Elf32_Dyn *d;
for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
if (d->d_tag == DT_NEEDED)
{
struct link_map *needed
= _dl_map_object (l, strtab + d->d_un.d_val);
Elf32_Addr init;
--needed->l_opencount;
init = next_init (needed); /* Recurse on this dependency. */
if (init != 0)
return init;
}
l->l_init_called = 1;
continue;
}
if (l->l_info[DT_INIT] &&
@ -73,17 +63,7 @@ _dl_init_next (void)
/* No initializer for this object.
Mark it so we will skip it in the future. */
l->l_init_called = 1;
return 0;
}
/* Look for the first initializer not yet called. */
l = _dl_loaded;
do
{
init = next_init (l);
l = l->l_next;
}
while (init == 0 && l);
return init;
return 0;
}

View File

@ -20,7 +20,6 @@ Cambridge, MA 02139, USA. */
#include <stddef.h>
#include <link.h>
#include <dlfcn.h>
#include <setjmp.h>
int
@ -30,7 +29,6 @@ dladdr (void *address, Dl_info *info)
struct link_map *l, *match;
const Elf32_Sym *symtab, *matchsym;
const char *strtab;
Elf32_Word symidx;
/* Find the highest-addressed object that ADDRESS is not below. */
match = NULL;

View File

@ -1,5 +1,5 @@
/* dlclose -- Close a handle opened by `dlopen'.
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
@ -32,64 +32,68 @@ 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. */
--map->l_opencount;
if (--map->l_opencount > 0 || map->l_type != lt_loaded)
/* There are still references to this object. Do nothing more. */
return;
if (map->l_opencount == 0 && map->l_type == lt_loaded)
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)
{
/* That was the last reference, and this was a dlopen-loaded
object. We can unmap it. */
const Elf32_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_info[DT_NEEDED])
struct link_map *map = list[i];
if (map->l_opencount == 0 && map->l_type == lt_loaded)
{
/* Also close all the dependencies. */
const char *strtab
= (void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr;
const Elf32_Dyn *d;
for (d = map->l_ld; d->d_tag != DT_NULL; ++d)
if (d->d_tag == DT_NEEDED)
/* That was the last reference, and this was a dlopen-loaded
object. We can unmap it. */
const Elf32_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)
{
/* It must already be open, since this one needed it;
so dlopen will just find us its `struct link_map'
and bump its reference count. */
struct link_map *o, *dep
= dlopen (strtab + d->d_un.d_val, RTLD_LAZY);
--dep->l_opencount; /* Lose the ref from that dlopen. */
/* Now we have the handle; we can close it for real. */
o = map;
map = dep;
doit ();
map = o;
Elf32_Addr mapstart = ph->p_vaddr & ~(ph->p_align - 1);
Elf32_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);
}
/* Unmap the segments. */
for (ph = map->l_phdr; ph < &map->l_phdr[map->l_phnum]; ++ph)
if (ph->p_type == PT_LOAD)
{
Elf32_Addr mapstart = ph->p_vaddr & ~(ph->p_align - 1);
Elf32_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;
free (map);
}
free (list);
}
return _dlerror_run (doit) ? -1 : 0;

View File

@ -27,21 +27,13 @@ void *
dlsym (void *handle, const char *name)
{
struct link_map *map = handle;
struct link_map *real_next;
Elf32_Addr loadbase;
const Elf32_Sym *ref = NULL;
int lose;
void doit (void)
{
struct link_map *scope[2] = { map, NULL };
loadbase = _dl_lookup_symbol (name, &ref, scope, map->l_name, 0, 0);
}
/* Confine the symbol scope to just this map. */
real_next = map->l_next;
map->l_next = NULL;
lose = _dlerror_run (doit);
map->l_next = real_next;
return lose ? NULL : (void *) (loadbase + ref->st_value);
return _dlerror_run (doit) ? NULL : (void *) (loadbase + ref->st_value);
}

View File

@ -111,6 +111,7 @@ struct link_map
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. */
};
/* Internal functions of the run-time dynamic linker.
@ -231,10 +232,11 @@ extern struct link_map *_dl_new_object (char *realname, const char *libname,
If LAZY is nonzero, don't relocate its PLT. */
extern void _dl_relocate_object (struct link_map *map, int lazy);
/* Return the address of the next initializer function not yet run.
When there are no more initializers to be run, this returns zero.
The functions are returned in the order they should be called. */
extern Elf32_Addr _dl_init_next (void);
/* 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
initializers to be run, this returns zero. The functions are returned
in the order they should be called. */
extern Elf32_Addr _dl_init_next (struct link_map *map);
/* Call the finalizer functions of all shared objects whose
initializer functions have completed. */

View File

@ -21,3 +21,6 @@ m68k-*-linux* libc=6
# libhurduser.so.0.0 corresponds to hurd/*.defs as of 7 May 1996.
*-*-gnu* libhurduser=0.0
# The -ldl interface (see <dlfcn.h>) is the same on all platforms.
*-*-* libdl=2

View File

@ -225,14 +225,19 @@ _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\
0: pushl %esi\n\
# Call _dl_init_next to return the address of an initializer\n\
# function to run.\n\
0: call _dl_init_next@PLT\n\
call _dl_init_next@PLT\n\
addl $4, %esp # Pop argument.\n\
# Check for zero return, when out of initializers.\n\
testl %eax,%eax\n\
jz 1f\n\
# Call the shared object initializer function.\n\
# NOTE: We depend only on the registers (%ebx and %edi)\n\
# NOTE: We depend only on the registers (%ebx, %esi and %edi)\n\
# and the return address pushed by this call;\n\
# the initializer is called with the stack just\n\
# as it appears on entry, and it is free to move\n\

View File

@ -250,14 +250,18 @@ _dl_start_user:
lea (%sp, %d0*4), %sp
| Push back the modified argument count.
move.l %d1, -(%sp)
| Push _dl_loaded as argument in _dl_init_next call below.
move.l ([_dl_loaded@GOT, %a5]), %d2
0: move.l %d2, -(%sp)
| Call _dl_init_next to return the address of an initializer
| function to run.
0: bsr.l _dl_init_next@PLTPC
bsr.l _dl_init_next@PLTPC
add.l #4, %sp | Pop argument.
| Check for zero return, when out of initializers.
tst.l %d0
jeq 1f
| Call the shared object initializer function.
| NOTE: We depend only on the registers (%a4 and %a5)
| NOTE: We depend only on the registers (%d2, %a4 and %a5)
| and the return address pushed by this call;
| the initializer is called with the stack just
| as it appears on entry, and it is free to move