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. * elf/Makefile (subdir_lib): Change this target to lib-noranlib.
(lib-noranlib): Depend on on $(extra-objs). (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 * errno.h: Move __END_DECLS out of #ifdef's so it matches
__BEGIN_DECLS. __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 * 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. 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 void
_dl_map_object_deps (struct link_map *map) _dl_map_object_deps (struct link_map *map)
{ {
unsigned int nlist = 1; struct list
struct link_map **list = malloc (sizeof *list); {
unsigned int done; struct link_map *map;
struct list *next;
};
struct list head, *tailp, *scanp;
unsigned int nlist;
/* Start the search list with one element: MAP itself. */ /* 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 /* Process each element of the search list, loading each of its immediate
dependencies and appending them to the list as we step through it. dependencies and appending them to the list as we step through it.
This produces a flat, ordered list that represents a breadth-first This produces a flat, ordered list that represents a breadth-first
search of the dependency tree. */ 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]) if (l->l_info[DT_NEEDED])
{ {
const char *strtab 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) for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
if (d->d_tag == DT_NEEDED) if (d->d_tag == DT_NEEDED)
{ {
/* Extend the list and put this object on the end. */ /* Map in the needed object. */
struct link_map **n struct link_map *dep
= realloc (list, (nlist + 1) * sizeof *list); = _dl_map_object (l, strtab + d->d_un.d_val);
if (n)
list = n; 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 else
{ {
free (list); /* Append DEP to the search list. */
_dl_signal_error (ENOMEM, map->l_name, tailp->next = alloca (sizeof *tailp);
"finding dependencies"); 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; 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); _dl_relocate_object (l, (mode & RTLD_BINDING_MASK) == RTLD_LAZY);
/* Run the initializer functions of new objects. */ /* Run the initializer functions of new objects. */
while (init = _dl_init_next ()) while (init = _dl_init_next (new))
(*(void (*) (void)) init) (); (*(void (*) (void)) init) ();
return new; return new;

View File

@ -1,5 +1,5 @@
/* Return the next shared object initializer function not yet run. /* 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. 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
@ -21,45 +21,35 @@ Cambridge, MA 02139, USA. */
#include <link.h> #include <link.h>
Elf32_Addr /* Run initializers for MAP and its dependencies, in inverse dependency
_dl_init_next (void) order (that is, leaf nodes first). */
{
struct link_map *l;
Elf32_Addr init;
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) if (l->l_init_called)
/* This object is all done. */ /* This object is all done. */
return 0; continue;
if (l->l_init_running) if (l->l_init_running)
{ {
/* This object's initializer was just running. /* This object's initializer was just running.
Now mark it as having run, so this object Now mark it as having run, so this object
will be skipped in the future. */ will be skipped in the future. */
l->l_init_called = 1;
l->l_init_running = 0; l->l_init_running = 0;
return 0; l->l_init_called = 1;
} continue;
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;
}
} }
if (l->l_info[DT_INIT] && if (l->l_info[DT_INIT] &&
@ -73,17 +63,7 @@ _dl_init_next (void)
/* No initializer for this object. /* No initializer for this object.
Mark it so we will skip it in the future. */ Mark it so we will skip it in the future. */
l->l_init_called = 1; l->l_init_called = 1;
return 0;
} }
/* Look for the first initializer not yet called. */ return 0;
l = _dl_loaded;
do
{
init = next_init (l);
l = l->l_next;
}
while (init == 0 && l);
return init;
} }

View File

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

View File

@ -1,5 +1,5 @@
/* dlclose -- Close a handle opened by `dlopen'. /* 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. 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
@ -32,64 +32,68 @@ dlclose (void *handle)
void doit (void) void doit (void)
{ {
struct link_map *map = handle; struct link_map *map = handle;
struct link_map **list;
unsigned int i;
if (map->l_opencount == 0) if (map->l_opencount == 0)
LOSE ("shared object not open"); LOSE ("shared object not open");
/* Decrement the reference count. */ /* 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 struct link_map *map = list[i];
object. We can unmap it. */ if (map->l_opencount == 0 && map->l_type == lt_loaded)
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])
{ {
/* Also close all the dependencies. */ /* That was the last reference, and this was a dlopen-loaded
const char *strtab object. We can unmap it. */
= (void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr; const Elf32_Phdr *ph;
const Elf32_Dyn *d;
for (d = map->l_ld; d->d_tag != DT_NULL; ++d) if (map->l_info[DT_FINI])
if (d->d_tag == DT_NEEDED) /* 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; Elf32_Addr mapstart = ph->p_vaddr & ~(ph->p_align - 1);
so dlopen will just find us its `struct link_map' Elf32_Addr mapend = ((ph->p_vaddr + ph->p_memsz
and bump its reference count. */ + ph->p_align - 1)
struct link_map *o, *dep & ~(ph->p_align - 1));
= dlopen (strtab + d->d_un.d_val, RTLD_LAZY); munmap ((caddr_t) mapstart, mapend - mapstart);
--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;
} }
/* 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; return _dlerror_run (doit) ? -1 : 0;

View File

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

View File

@ -111,6 +111,7 @@ struct link_map
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. */
}; };
/* Internal functions of the run-time dynamic linker. /* 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. */ 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, int lazy);
/* Return the address of the next initializer function not yet run. /* Return the address of the next initializer function for MAP or one of
When there are no more initializers to be run, this returns zero. its dependencies that has not yet been run. When there are no more
The functions are returned in the order they should be called. */ initializers to be run, this returns zero. The functions are returned
extern Elf32_Addr _dl_init_next (void); 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 /* Call the finalizer functions of all shared objects whose
initializer functions have completed. */ 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. # libhurduser.so.0.0 corresponds to hurd/*.defs as of 7 May 1996.
*-*-gnu* libhurduser=0.0 *-*-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\ 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\
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\ # Call _dl_init_next to return the address of an initializer\n\
# function to run.\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\ # Check for zero return, when out of initializers.\n\
testl %eax,%eax\n\ testl %eax,%eax\n\
jz 1f\n\ jz 1f\n\
# Call the shared object initializer function.\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\ # and the return address pushed by this call;\n\
# the initializer is called with the stack just\n\ # the initializer is called with the stack just\n\
# as it appears on entry, and it is free to move\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 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)
| 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 | Call _dl_init_next to return the address of an initializer
| function to run. | 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. | Check for zero return, when out of initializers.
tst.l %d0 tst.l %d0
jeq 1f jeq 1f
| Call the shared object initializer function. | 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; | and the return address pushed by this call;
| the initializer is called with the stack just | the initializer is called with the stack just
| as it appears on entry, and it is free to move | as it appears on entry, and it is free to move