2000-04-02  Ulrich Drepper  <drepper@redhat.com>

	* elf/dl-fini.c (_dl_fini): Increment j counter after swapping in
	element at this position.

	* elf/Versions [ld.so] (GLIBC_2.2): Export _dl_load_lock.
	* elf/link.h (struct link_map): Add l_reldepsmax, l_reldepsact, and
	l_reldeps elements.
	* elf/dl-lookup.c (add_dependency): New function.
	(_dl_lookup_symbol): Use it whenever symbol was found in a global,
	dynamically loaded object.
	(_dl_lookup_symbol_skip): Likewise.
	(_dl_lookup_versioned_symbol): Likewise.
	(_dl_lookup_versioned_symbol_skip): Likewise.
	* elf/dl-open.c: Don't define _dl_load_lock here...
	* elf/rtld.c: ...but here...
	* elf/dl-support.c: ...and here.
	* elf/dl-close.c (_dl_close): Close also dependent objects introduce
	through relocation.
	* elf/dl-fini.c (_dl_fini): Also take dependencies introduced through
	relocations.
	* dlfcn/Makefile (glrefmain.out): Test is not expected to fail
	anymore.
	* dlfcn/glrefmain.c: Add one more debug message.

	* Makeconfig (preprocess-versions): Don't add $(CPPFLAGS) to compiler
	command line.
	* Makerules (sysd-versions): Use ( ) instead of { }.

	* elf/dl-load.c: Use __builtin_expect to signal that compiler should
	optimize for the non-debugging case.
	* elf/dl-lookup.c: Likewise.
	* sysdeps/generic/libc-start.c: Likewise.
This commit is contained in:
Ulrich Drepper 2000-04-03 03:51:04 +00:00
parent ec79422d9e
commit cf197e41e7
14 changed files with 348 additions and 34 deletions

View File

@ -1,3 +1,37 @@
2000-04-02 Ulrich Drepper <drepper@redhat.com>
* elf/dl-fini.c (_dl_fini): Increment j counter after swapping in
element at this position.
* elf/Versions [ld.so] (GLIBC_2.2): Export _dl_load_lock.
* elf/link.h (struct link_map): Add l_reldepsmax, l_reldepsact, and
l_reldeps elements.
* elf/dl-lookup.c (add_dependency): New function.
(_dl_lookup_symbol): Use it whenever symbol was found in a global,
dynamically loaded object.
(_dl_lookup_symbol_skip): Likewise.
(_dl_lookup_versioned_symbol): Likewise.
(_dl_lookup_versioned_symbol_skip): Likewise.
* elf/dl-open.c: Don't define _dl_load_lock here...
* elf/rtld.c: ...but here...
* elf/dl-support.c: ...and here.
* elf/dl-close.c (_dl_close): Close also dependent objects introduce
through relocation.
* elf/dl-fini.c (_dl_fini): Also take dependencies introduced through
relocations.
* dlfcn/Makefile (glrefmain.out): Test is not expected to fail
anymore.
* dlfcn/glrefmain.c: Add one more debug message.
* Makeconfig (preprocess-versions): Don't add $(CPPFLAGS) to compiler
command line.
* Makerules (sysd-versions): Use ( ) instead of { }.
* elf/dl-load.c: Use __builtin_expect to signal that compiler should
optimize for the non-debugging case.
* elf/dl-lookup.c: Likewise.
* sysdeps/generic/libc-start.c: Likewise.
2000-04-02 Roland McGrath <roland@baalperazim.frob.com>
* sysdeps/mach/hurd/i386/init-first.c: Replace PIC #ifdefs with SHARED.

View File

@ -674,7 +674,7 @@ ifeq (yes, $(build-shared))
# %ifdef et al based on config.h settings or other %include'd files.
define preprocess-versions
sed 's/#.*$$//;s/^[ ]*%/#/' \
| $(CC) $(CPPFLAGS) -E -undef -include $(common-objpfx)config.h -x c - \
| $(CC) -E -undef -include $(common-objpfx)config.h -x c - \
| sed 's/#.*$$//;/^[ ]*$$/d'
endef

View File

@ -306,13 +306,13 @@ $(common-objpfx)sysd-versions: $(common-objpfx)Versions.all \
$(wildcard $(all-subdirs:%=$(..)%/Versions)) \
$(wildcard $(sysdirs:%=%/Versions)) \
$(sysd-versions-force)
{ echo 'sysd-versions-subdirs = $(all-subdirs) $(config-sysdirs)' ; \
( echo 'sysd-versions-subdirs = $(all-subdirs) $(config-sysdirs)' ; \
cat $(filter-out $< $(word 2,$^) $(sysd-versions-force),$^) \
| $(preprocess-versions) \
| LC_ALL=C $(AWK) -v buildroot=$(common-objpfx) -v defsfile=$< \
-v move_if_change='$(move-if-change)' \
-f $(word 2,$^); \
} > $@T
) > $@T
mv -f $@T $@
endif # avoid-generated
endif # $(versioning) = yes

View File

@ -70,6 +70,9 @@ do_test (void)
dlclose (d2);
puts ("glreflib2 also closed");
fflush (stdout);
return 0;
}

View File

@ -52,7 +52,7 @@ ld.so {
_dl_dst_count; _dl_dst_substitute;
}
GLIBC_2.2 {
_dl_init;
_dl_init; _dl_load_lock;
# this is defined in ld.so and overridden by libc
_dl_init_first;

View File

@ -43,8 +43,10 @@ internal_function
_dl_close (void *_map)
{
struct link_map **list;
struct link_map **rellist;
struct link_map *map = _map;
unsigned nsearchlist;
unsigned int nsearchlist;
unsigned int nrellist;
unsigned int i;
if (map->l_opencount == 0)
@ -65,6 +67,9 @@ _dl_close (void *_map)
list = map->l_searchlist.r_list;
nsearchlist = map->l_searchlist.r_nlist;
rellist = map->l_reldeps;
nrellist = map->l_reldepsact;
/* Call all termination functions at once. */
for (i = 0; i < nsearchlist; ++i)
{
@ -192,6 +197,16 @@ _dl_close (void *_map)
}
}
/* Now we can perhaps also remove the modules for which we had
dependencies because of symbol lookup. */
if (rellist != NULL)
{
while (nrellist-- > 0)
_dl_close (rellist[nrellist]);
free (rellist);
}
free (list);
if (_dl_global_scope_alloc != 0

View File

@ -87,18 +87,41 @@ _dl_fini (void)
memmove (&maps[j] + 1,
&maps[j],
(k - j) * sizeof (struct link_map *));
maps[j] = here;
maps[j++] = here;
break;
}
else
++runp;
}
if (__builtin_expect (maps[k]->l_reldeps != NULL, 0))
{
unsigned int m = maps[k]->l_reldepsact;
struct link_map **relmaps = maps[k]->l_reldeps;
while (m-- > 0)
{
if (relmaps[m] == l)
{
struct link_map *here = maps[k];
/* Move it now. */
memmove (&maps[j] + 1,
&maps[j],
(k - j) * sizeof (struct link_map *));
maps[j] = here;
break;
}
}
}
}
}
/* `maps' now contains the objects in the right order. Now call the
destructors. We have the process this array from the front. */
destructors. We have to process this array from the front. */
for (i = 0; i < nloaded; ++i)
{
l = maps[i];

View File

@ -748,7 +748,7 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
}
/* Print debugging message. */
if (_dl_debug_files)
if (__builtin_expect (_dl_debug_files, 0))
_dl_debug_message (1, "file=", name, "; generating link map\n", NULL);
/* Read the header directly. */
@ -1046,7 +1046,7 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
l->l_entry += l->l_addr;
if (_dl_debug_files)
if (__builtin_expect (_dl_debug_files, 0))
{
const size_t nibbles = sizeof (void *) * 2;
char buf1[nibbles + 1];
@ -1182,7 +1182,8 @@ open_path (const char *name, size_t namelen, int preloaded,
/* If we are debugging the search for libraries print the path
now if it hasn't happened now. */
if (_dl_debug_libs && current_what != this_dir->what)
if (__builtin_expect (_dl_debug_libs, 0)
&& current_what != this_dir->what)
{
current_what = this_dir->what;
print_search_path (dirs, current_what, this_dir->where);
@ -1202,7 +1203,7 @@ open_path (const char *name, size_t namelen, int preloaded,
- buf);
/* Print name we try if this is wanted. */
if (_dl_debug_libs)
if (__builtin_expect (_dl_debug_libs, 0))
_dl_debug_message (1, " trying file=", buf, "\n", NULL);
fd = __open (buf, O_RDONLY);
@ -1316,7 +1317,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
}
/* Display information if we are debugging. */
if (_dl_debug_files && loader != NULL)
if (__builtin_expect (_dl_debug_files, 0) && loader != NULL)
_dl_debug_message (1, "\nfile=", name, "; needed by ",
loader->l_name[0] ? loader->l_name : _dl_argv[0],
"\n", NULL);
@ -1327,7 +1328,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
size_t namelen = strlen (name) + 1;
if (_dl_debug_libs)
if (__builtin_expect (_dl_debug_libs, 0))
_dl_debug_message (1, "find library=", name, "; searching\n", NULL);
fd = -1;
@ -1411,7 +1412,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
fd = open_path (name, namelen, preloaded, rtld_search_dirs, &realname);
/* Add another newline when we a tracing the library loading. */
if (_dl_debug_libs)
if (__builtin_expect (_dl_debug_libs, 0))
_dl_debug_message (1, "\n", NULL);
}
else

View File

@ -18,11 +18,13 @@
Boston, MA 02111-1307, USA. */
#include <alloca.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ldsodefs.h>
#include "dl-hash.h"
#include <dl-machine.h>
#include <bits/libc-lock.h>
#include <assert.h>
@ -59,6 +61,15 @@ struct sym_val
/* Statistics function. */
unsigned long int _dl_num_relocations;
/* During the program run we must not modify the global data of
loaded shared object simultanously in two threads. Therefore we
protect `_dl_open' and `_dl_close' in dl-close.c.
This must be a recursive lock since the initializer function of
the loaded object might as well require a call to this function.
At this time it is not anymore a problem to modify the tables. */
__libc_lock_define (extern, _dl_load_lock)
/* We have two different situations when looking up a simple: with or
without versioning. gcc is not able to optimize a single function
@ -70,6 +81,105 @@ unsigned long int _dl_num_relocations;
#include "do-lookup.h"
/* Add extra dependency on MAP to UNDEF_MAP. */
static int
add_dependency (struct link_map *undef_map, struct link_map *map)
{
struct link_map **list;
unsigned act;
unsigned int i;
int result = 0;
/* Make sure nobody can unload the object while we are at it. */
__libc_lock_lock (_dl_load_lock);
/* Determine whether UNDEF_MAP already has a reference to MAP. First
look in the normal dependencies. */
list = undef_map->l_searchlist.r_list;
act = undef_map->l_searchlist.r_nlist;
for (i = 0; i < act; ++i)
if (list[i] == map)
break;
if (__builtin_expect (i, act) == act)
{
/* No normal dependency. See whether we already had to add it
to the special list of dynamic dependencies. */
list = undef_map->l_reldeps;
act = undef_map->l_reldepsact;
for (i = 0; i < act; ++i)
if (list[i] == map)
break;
if (i == act)
{
/* The object is not yet in the dependency list. Before we add
it make sure just one more time the object we are about to
reference is still available. There is a brief period in
which the object could have been removed since we found the
definition. */
struct link_map *runp = _dl_loaded;
while (runp != NULL && runp != map)
runp = runp->l_next;
if (runp != NULL)
{
/* The object is still available. Add the reference now. */
if (act >= undef_map->l_reldepsmax)
{
/* Allocate more memory for the dependency list. Since
this can never happen during the startup phase we can
use `realloc'. */
void *newp;
undef_map->l_reldepsmax += 5;
newp = realloc (undef_map->l_reldeps,
undef_map->l_reldepsmax);
if (__builtin_expect (newp != NULL, 1))
undef_map->l_reldeps = (struct link_map **) newp;
else
/* Correct the addition. */
undef_map->l_reldepsmax -= 5;
}
/* If we didn't manage to allocate memory for the list this
is no fatal mistake. We simply increment the use counter
of the referenced object and don't record the dependencies.
This means this increment can never be reverted and the
object will never be unloaded. This is semantically the
correct behaviour. */
if (act < undef_map->l_reldepsmax)
undef_map->l_reldeps[undef_map->l_reldepsact++] = map;
/* And increment the counter in the referenced object. */
++map->l_opencount;
/* Display information if we are debugging. */
if (__builtin_expect (_dl_debug_files, 0))
_dl_debug_message (1, "\nfile=",
map->l_name[0] ? map->l_name : _dl_argv[0],
"; needed by ",
undef_map->l_name[0]
? undef_map->l_name : _dl_argv[0],
" (relocation dependency)\n\n", NULL);
}
else
/* Whoa, that was bad luck. We have to search again. */
result = -1;
}
}
/* Release the lock. */
__libc_lock_unlock (_dl_load_lock);
return result;
}
/* Search loaded objects' symbol tables for a definition of the symbol
UNDEF_NAME. */
@ -90,7 +200,24 @@ _dl_lookup_symbol (const char *undef_name, struct link_map *undef_map,
for (scope = symbol_scope; *scope; ++scope)
if (do_lookup (undef_name, undef_map, hash, *ref, &current_value,
*scope, 0, NULL, reloc_type))
break;
{
/* We have to check whether this would bind UNDEF_MAP to an object
in the global scope which was dynamically loaded. In this case
we have to prevent the latter from being unloaded unless the
UNDEF_MAP object is also unloaded. */
if (current_value.m->l_global
&& (__builtin_expect (current_value.m->l_type, lt_library)
== lt_loaded)
&& undef_map != current_value.m
/* Add UNDEF_MAP to the dependencies. */
&& add_dependency (undef_map, current_value.m) < 0)
/* Something went wrong. Perhaps the object we tried to reference
was just removed. Try finding another definition. */
return _dl_lookup_symbol (undef_name, undef_map, ref, symbol_scope,
reloc_type);
break;
}
if (current_value.s == NULL)
{
@ -104,7 +231,7 @@ _dl_lookup_symbol (const char *undef_name, struct link_map *undef_map,
return 0;
}
if (_dl_debug_bindings)
if (__builtin_expect (_dl_debug_bindings, 0))
_dl_debug_message (1, "binding file ",
(reference_name && reference_name[0]
? reference_name
@ -143,13 +270,47 @@ _dl_lookup_symbol_skip (const char *undef_name,
for (i = 0; (*scope)->r_duplist[i] != skip_map; ++i)
assert (i < (*scope)->r_nduplist);
if (i >= (*scope)->r_nlist
|| ! do_lookup (undef_name, undef_map, hash, *ref, &current_value,
*scope, i, skip_map, 0))
if (i < (*scope)->r_nlist
&& do_lookup (undef_name, undef_map, hash, *ref, &current_value,
*scope, i, skip_map, 0))
{
/* We have to check whether this would bind UNDEF_MAP to an object
in the global scope which was dynamically loaded. In this case
we have to prevent the latter from being unloaded unless the
UNDEF_MAP object is also unloaded. */
if (current_value.m->l_global
&& (__builtin_expect (current_value.m->l_type, lt_library)
== lt_loaded)
&& undef_map != current_value.m
/* Add UNDEF_MAP to the dependencies. */
&& add_dependency (undef_map, current_value.m) < 0)
/* Something went wrong. Perhaps the object we tried to reference
was just removed. Try finding another definition. */
return _dl_lookup_symbol_skip (undef_name, undef_map, ref,
symbol_scope, skip_map);
}
else
while (*++scope)
if (do_lookup (undef_name, undef_map, hash, *ref, &current_value,
*scope, 0, skip_map, 0))
break;
{
/* We have to check whether this would bind UNDEF_MAP to an object
in the global scope which was dynamically loaded. In this case
we have to prevent the latter from being unloaded unless the
UNDEF_MAP object is also unloaded. */
if (current_value.m->l_global
&& (__builtin_expect (current_value.m->l_type, lt_library)
== lt_loaded)
&& undef_map != current_value.m
/* Add UNDEF_MAP to the dependencies. */
&& add_dependency (undef_map, current_value.m) < 0)
/* Something went wrong. Perhaps the object we tried to reference
was just removed. Try finding another definition. */
return _dl_lookup_symbol_skip (undef_name, undef_map, ref,
symbol_scope, skip_map);
break;
}
if (current_value.s == NULL)
{
@ -157,7 +318,7 @@ _dl_lookup_symbol_skip (const char *undef_name,
return 0;
}
if (_dl_debug_bindings)
if (__builtin_expect (_dl_debug_bindings, 0))
_dl_debug_message (1, "binding file ",
(reference_name && reference_name[0]
? reference_name
@ -198,7 +359,25 @@ _dl_lookup_versioned_symbol (const char *undef_name,
&current_value, *scope, 0, version, NULL,
reloc_type);
if (res > 0)
break;
{
/* We have to check whether this would bind UNDEF_MAP to an object
in the global scope which was dynamically loaded. In this case
we have to prevent the latter from being unloaded unless the
UNDEF_MAP object is also unloaded. */
if (current_value.m->l_global
&& (__builtin_expect (current_value.m->l_type, lt_library)
== lt_loaded)
&& undef_map != current_value.m
/* Add UNDEF_MAP to the dependencies. */
&& add_dependency (undef_map, current_value.m) < 0)
/* Something went wrong. Perhaps the object we tried to reference
was just removed. Try finding another definition. */
return _dl_lookup_versioned_symbol (undef_name, undef_map, ref,
symbol_scope, version,
reloc_type);
break;
}
if (res < 0)
{
@ -232,7 +411,7 @@ _dl_lookup_versioned_symbol (const char *undef_name,
return 0;
}
if (_dl_debug_bindings)
if (__builtin_expect (_dl_debug_bindings, 0))
_dl_debug_message (1, "binding file ",
(reference_name && reference_name[0]
? reference_name
@ -271,15 +450,49 @@ _dl_lookup_versioned_symbol_skip (const char *undef_name,
for (i = 0; (*scope)->r_duplist[i] != skip_map; ++i)
assert (i < (*scope)->r_nduplist);
if (i >= (*scope)->r_nlist
|| ! do_lookup_versioned (undef_name, undef_map, hash, *ref,
&current_value, *scope, i, version, skip_map,
0))
if (i < (*scope)->r_nlist
&& do_lookup_versioned (undef_name, undef_map, hash, *ref,
&current_value, *scope, i, version, skip_map, 0))
{
/* We have to check whether this would bind UNDEF_MAP to an object
in the global scope which was dynamically loaded. In this case
we have to prevent the latter from being unloaded unless the
UNDEF_MAP object is also unloaded. */
if (current_value.m->l_global
&& (__builtin_expect (current_value.m->l_type, lt_library)
== lt_loaded)
&& undef_map != current_value.m
/* Add UNDEF_MAP to the dependencies. */
&& add_dependency (undef_map, current_value.m) < 0)
/* Something went wrong. Perhaps the object we tried to reference
was just removed. Try finding another definition. */
return _dl_lookup_versioned_symbol_skip (undef_name, undef_map, ref,
symbol_scope, version,
skip_map);
}
else
while (*++scope)
if (do_lookup_versioned (undef_name, undef_map, hash, *ref,
&current_value, *scope, 0, version, skip_map,
0))
break;
{
/* We have to check whether this would bind UNDEF_MAP to an object
in the global scope which was dynamically loaded. In this case
we have to prevent the latter from being unloaded unless the
UNDEF_MAP object is also unloaded. */
if (current_value.m->l_global
&& (__builtin_expect (current_value.m->l_type, lt_library)
== lt_loaded)
&& undef_map != current_value.m
/* Add UNDEF_MAP to the dependencies. */
&& add_dependency (undef_map, current_value.m) < 0)
/* Something went wrong. Perhaps the object we tried to reference
was just removed. Try finding another definition. */
return _dl_lookup_versioned_symbol_skip (undef_name, undef_map,
ref, symbol_scope,
version, skip_map);
break;
}
if (current_value.s == NULL)
{
@ -298,7 +511,7 @@ _dl_lookup_versioned_symbol_skip (const char *undef_name,
return 0;
}
if (_dl_debug_bindings)
if (__builtin_expect (_dl_debug_bindings, 0))
_dl_debug_message (1, "binding file ",
(reference_name && reference_name[0]
? reference_name

View File

@ -63,7 +63,7 @@ static void show_scope (struct link_map *new);
This must be a recursive lock since the initializer function of
the loaded object might as well require a call to this function.
At this time it is not anymore a problem to modify the tables. */
__libc_lock_define_initialized_recursive (, _dl_load_lock)
__libc_lock_define (extern, _dl_load_lock)
extern size_t _dl_platformlen;

View File

@ -25,6 +25,7 @@
#include <unistd.h>
#include <ldsodefs.h>
#include <dl-machine.h>
#include <bits/libc-lock.h>
extern char *__progname;
char **_dl_argv = &__progname; /* This is checked for some error messages. */
@ -81,6 +82,15 @@ struct r_scope_elem *_dl_main_searchlist = &_dl_initial_searchlist;
/* Nonzero during startup. */
int _dl_starting_up = 1;
/* During the program run we must not modify the global data of
loaded shared object simultanously in two threads. Therefore we
protect `_dl_open' and `_dl_close' in dl-close.c.
This must be a recursive lock since the initializer function of
the loaded object might as well require a call to this function.
At this time it is not anymore a problem to modify the tables. */
__libc_lock_define_initialized_recursive (, _dl_load_lock)
static void non_dynamic_init (void) __attribute__ ((unused));

View File

@ -208,6 +208,11 @@ struct link_map
/* List of object in order of the init and fini calls. */
struct link_map **l_initfini;
/* List of the dependencies introduced through symbol binding. */
unsigned int l_reldepsmax;
unsigned int l_reldepsact;
struct link_map **l_reldeps;
};
#endif /* link.h */

View File

@ -27,6 +27,7 @@
#include <entry.h>
#include <fpu_control.h>
#include <hp-timing.h>
#include <bits/libc-lock.h>
#include "dynamic-link.h"
#include "dl-librecon.h"
@ -105,6 +106,15 @@ struct r_scope_elem _dl_initial_searchlist;
/* Array which is used when looking up in the global scope. */
struct r_scope_elem *_dl_global_scope[2];
/* During the program run we must not modify the global data of
loaded shared object simultanously in two threads. Therefore we
protect `_dl_open' and `_dl_close' in dl-close.c.
This must be a recursive lock since the initializer function of
the loaded object might as well require a call to this function.
At this time it is not anymore a problem to modify the tables. */
__libc_lock_define_initialized_recursive (, _dl_load_lock)
/* Set nonzero during loading and initialization of executable and
libraries, cleared before the executable's entry point runs. This
must not be initialized to nonzero, because the unused dynamic

View File

@ -56,11 +56,11 @@ __libc_start_main (int (*main) (int, char **, char **), int argc,
/* Some security at this point. Prevent starting a SUID binary where
the standard file descriptors are not opened. */
if (__libc_enable_secure)
if (__builtin_expect (__libc_enable_secure, 0))
check_standard_fds ();
/* Register the destructor of the dynamic linker if there is any. */
if (rtld_fini != NULL)
if (__builtin_expect (rtld_fini != NULL, 1))
atexit (rtld_fini);
/* Call the initializer of the libc. This is only needed here if we
@ -76,14 +76,14 @@ __libc_start_main (int (*main) (int, char **, char **), int argc,
/* Call the initializer of the program, if any. */
#ifdef SHARED
if (_dl_debug_impcalls)
if (__builtin_expect (_dl_debug_impcalls, 0))
_dl_debug_message (1, "\ninitialize program: ", argv[0], "\n\n", NULL);
#endif
if (init)
(*init) ();
#ifdef SHARED
if (_dl_debug_impcalls)
if (__builtin_expect (_dl_debug_impcalls, 0))
_dl_debug_message (1, "\ntransferring control: ", argv[0], "\n\n", NULL);
#endif