mirror of
git://sourceware.org/git/glibc.git
synced 2024-11-21 01:12:26 +08:00
Update.
2001-09-08 Ulrich Drepper <drepper@redhat.com> * elf/dl-close.c (_dl_close): If object has no r_list (i.e., wasn't loaded directly) determine length if l_initfini list by iterating over its elements. Minor optimizations. * elf/dl-deps.c (_dl_map_object_deps): Always add own map to l_initfini for dependency objects. If object was already loaded check whether any of the dependencies is already on the relocation dependency list. If yes, remove the latter. Minor optimizations. * elf/dl-lookup.c (add_dependency): Add check for self reference of maps here. Search l_initfini list only if the object was loaded directly and not only as a dependency. (_dl_lookup_symbol): Add relocation dependency also if object is not in global scope. Remove test for self-reference here. (_dl_lookup_versioned_symbol): Likewise. * elf/dl-object (_dl_new_object): Cleanup. Initialize dont_free element of first name record. * elf/loadtest.c: Add some more test to recognize early if an object wasn't unloaded. * elf/Makefile: Add rules to build and run reldep5. * elf/reldep5.c: New file. * elf/reldepmod5.c: New file. * elf/reldepmod6.c: New file. * elf/reldep2.c: Fix typo. * elf/dl-object.c (_dl_new_object): Initialize l_scope and l_scope_max.
This commit is contained in:
parent
5a21d307c5
commit
c4bb124a75
29
ChangeLog
29
ChangeLog
@ -1,8 +1,35 @@
|
||||
2001-09-08 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* elf/dl-close.c (_dl_close): If object has no r_list (i.e., wasn't
|
||||
loaded directly) determine length if l_initfini list by iterating
|
||||
over its elements. Minor optimizations.
|
||||
* elf/dl-deps.c (_dl_map_object_deps): Always add own map to l_initfini
|
||||
for dependency objects.
|
||||
If object was already loaded check whether any of the dependencies
|
||||
is already on the relocation dependency list. If yes, remove the
|
||||
latter. Minor optimizations.
|
||||
* elf/dl-lookup.c (add_dependency): Add check for self reference of
|
||||
maps here. Search l_initfini list only if the object was loaded
|
||||
directly and not only as a dependency.
|
||||
(_dl_lookup_symbol): Add relocation dependency also if object
|
||||
is not in global scope. Remove test for self-reference here.
|
||||
(_dl_lookup_versioned_symbol): Likewise.
|
||||
* elf/dl-object (_dl_new_object): Cleanup. Initialize dont_free
|
||||
element of first name record.
|
||||
* elf/loadtest.c: Add some more test to recognize early if an object
|
||||
wasn't unloaded.
|
||||
* elf/Makefile: Add rules to build and run reldep5.
|
||||
* elf/reldep5.c: New file.
|
||||
* elf/reldepmod5.c: New file.
|
||||
* elf/reldepmod6.c: New file.
|
||||
|
||||
* elf/reldep2.c: Fix typo.
|
||||
|
||||
2001-09-07 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* include/link.h (struct link_map): Add l_scope_mem and l_scope_max
|
||||
elements. Change l_scope to be a pointer only.
|
||||
* elf/dl-object.c (_dl_new_ojbect): Initialize l_scope and l_scope_max.
|
||||
* elf/dl-object.c (_dl_new_object): Initialize l_scope and l_scope_max.
|
||||
* elf/dl-open.c (dl_open_worker): If dependency wasn't just opened
|
||||
here add searchlist of newly open file to the dependency's scope.
|
||||
* elf/dl-close.c (_dl_close): If dependency is used otherwise remove
|
||||
|
10
elf/Makefile
10
elf/Makefile
@ -55,6 +55,7 @@ distribute := $(rtld-routines:=.c) dynamic-link.h do-rel.h dl-machine.h \
|
||||
nodlopenmod.c nodelete.c nodelmod1.c nodelmod2.c \
|
||||
nodelmod3.c nodelmod4.c nodlopen.c dl-osinfo.h \
|
||||
reldepmod1.c reldepmod2.c reldepmod3.c reldepmod4.c \
|
||||
reldepmod5.c reldepmod6.c \
|
||||
reldep4mod1.c reldep4mod2.c reldep4mod3.c reldep4mod4.c \
|
||||
nextmod1.c nextmod2.c pathoptobj.c tst-pathopt.sh \
|
||||
neededobj1.c neededobj2.c neededobj3.c neededobj4.c \
|
||||
@ -106,7 +107,7 @@ tests = loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
|
||||
reldep reldep2 reldep3 reldep4 $(tests-nodelete-$(have-z-nodelete)) \
|
||||
$(tests-nodlopen-$(have-z-nodlopen)) neededtest neededtest2 \
|
||||
neededtest3 neededtest4 unload2 lateglobal initfirst global \
|
||||
restest2 next dblload dblunload
|
||||
restest2 next dblload dblunload reldep5
|
||||
test-srcs = tst-pathopt
|
||||
tests-vis-yes = vismain
|
||||
tests-nodelete-yes = nodelete
|
||||
@ -122,7 +123,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
|
||||
neededobj1 neededobj2 neededobj3 neededobj4 \
|
||||
neededobj5 neededobj6 firstobj globalmod1 \
|
||||
unload2mod unload2dep ltglobmod1 ltglobmod2 pathoptobj \
|
||||
dblloadmod1 dblloadmod2 dblloadmod3
|
||||
dblloadmod1 dblloadmod2 dblloadmod3 reldepmod5 reldepmod6
|
||||
modules-vis-yes = vismod1 vismod2 vismod3
|
||||
modules-nodelete-yes = nodelmod1 nodelmod2 nodelmod3 nodelmod4
|
||||
modules-nodlopen-yes = nodlopenmod
|
||||
@ -285,6 +286,8 @@ $(objpfx)reldep4mod1.so: $(objpfx)reldep4mod3.so
|
||||
$(objpfx)reldep4mod2.so: $(objpfx)reldep4mod4.so
|
||||
$(objpfx)dblloadmod1.so: $(objpfx)dblloadmod3.so
|
||||
$(objpfx)dblloadmod2.so: $(objpfx)dblloadmod3.so
|
||||
$(objpfx)reldepmod5.so: $(objpfx)reldepmod2.so
|
||||
$(objpfx)reldepmod6.so: $(objpfx)reldepmod2.so
|
||||
|
||||
# filtmod1.so has a special rule
|
||||
$(filter-out $(objpfx)filtmod1.so, $(test-modules)): $(objpfx)%.so: $(objpfx)%.os
|
||||
@ -423,3 +426,6 @@ $(objpfx)dblload.out: $(objpfx)dblloadmod1.so $(objpfx)dblloadmod2.so
|
||||
|
||||
$(objpfx)dblunload: $(libdl)
|
||||
$(objpfx)dblunload.out: $(objpfx)dblloadmod1.so $(objpfx)dblloadmod2.so
|
||||
|
||||
$(objpfx)reldep5: $(libdl)
|
||||
$(objpfx)reldep5.out: $(objpfx)reldepmod5.so $(objpfx)reldepmod5.so
|
||||
|
@ -48,7 +48,8 @@ _dl_close (void *_map)
|
||||
unsigned int *new_opencount;
|
||||
|
||||
/* First see whether we can remove the object at all. */
|
||||
if ((map->l_flags_1 & DF_1_NODELETE) && map->l_init_called)
|
||||
if (__builtin_expect (map->l_flags_1 & DF_1_NODELETE, 0)
|
||||
&& map->l_init_called)
|
||||
/* Nope. Do nothing. */
|
||||
return;
|
||||
|
||||
@ -63,14 +64,8 @@ _dl_close (void *_map)
|
||||
{
|
||||
/* There are still references to this object. Do nothing more. */
|
||||
if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0))
|
||||
{
|
||||
char buf[20];
|
||||
|
||||
buf[sizeof buf - 1] = '\0';
|
||||
|
||||
_dl_debug_printf ("\nclosing file=%s; opencount == %u\n",
|
||||
map->l_name, map->l_opencount);
|
||||
}
|
||||
_dl_debug_printf ("\nclosing file=%s; opencount == %u\n",
|
||||
map->l_name, map->l_opencount);
|
||||
|
||||
/* One decrement the object itself, not the dependencies. */
|
||||
--map->l_opencount;
|
||||
@ -82,8 +77,15 @@ _dl_close (void *_map)
|
||||
list = map->l_initfini;
|
||||
|
||||
/* Compute the new l_opencount values. */
|
||||
new_opencount = (unsigned int *) alloca (map->l_searchlist.r_nlist
|
||||
* sizeof (unsigned int));
|
||||
i = map->l_searchlist.r_nlist;
|
||||
if (__builtin_expect (i == 0, 0))
|
||||
/* This can happen if we handle relocation dependencies for an
|
||||
object which wasn't loaded directly. */
|
||||
for (i = 1; list[i] != NULL; ++i)
|
||||
;
|
||||
|
||||
new_opencount = (unsigned int *) alloca (i * sizeof (unsigned int));
|
||||
|
||||
for (i = 0; list[i] != NULL; ++i)
|
||||
{
|
||||
list[i]->l_idx = i;
|
||||
|
@ -448,11 +448,13 @@ _dl_map_object_deps (struct link_map *map,
|
||||
{
|
||||
needed[nneeded++] = NULL;
|
||||
|
||||
l->l_initfini = malloc (nneeded * sizeof needed[0]);
|
||||
l->l_initfini = (struct link_map **)
|
||||
malloc ((nneeded + 1) * sizeof needed[0]);
|
||||
if (l->l_initfini == NULL)
|
||||
_dl_signal_error (ENOMEM, map->l_name, NULL,
|
||||
N_("cannot allocate dependency list"));
|
||||
memcpy (l->l_initfini, needed, nneeded * sizeof needed[0]);
|
||||
l->l_initfini[0] = l;
|
||||
memcpy (&l->l_initfini[1], needed, nneeded * sizeof needed[0]);
|
||||
}
|
||||
|
||||
/* If we have no auxiliary objects just go on to the next map. */
|
||||
@ -462,7 +464,7 @@ _dl_map_object_deps (struct link_map *map,
|
||||
while (runp != NULL && runp->done);
|
||||
}
|
||||
|
||||
out:
|
||||
out:
|
||||
if (errno == 0 && errno_saved != 0)
|
||||
__set_errno (errno_saved);
|
||||
|
||||
@ -489,7 +491,7 @@ out:
|
||||
|
||||
for (nlist = 0, runp = known; runp; runp = runp->next)
|
||||
{
|
||||
if (trace_mode && runp->map->l_faked)
|
||||
if (__builtin_expect (trace_mode, 0) && runp->map->l_faked)
|
||||
/* This can happen when we trace the loading. */
|
||||
--map->l_searchlist.r_nlist;
|
||||
else
|
||||
@ -500,6 +502,30 @@ out:
|
||||
runp->map->l_reserved = 0;
|
||||
}
|
||||
|
||||
/* Maybe we can remove some relocation dependencies now. */
|
||||
assert (map->l_searchlist.r_list[0] == map);
|
||||
for (i = 0; i < map->l_reldepsact; ++i)
|
||||
{
|
||||
unsigned int j;
|
||||
|
||||
for (j = 1; j < nlist; ++j)
|
||||
if (map->l_searchlist.r_list[j] == map->l_reldeps[i])
|
||||
{
|
||||
/* A direct or transitive dependency is also on the list
|
||||
of relocation dependencies. Remove the latter. */
|
||||
--map->l_reldeps[i]->l_opencount;
|
||||
|
||||
for (j = i + 1; j < map->l_reldepsact; ++j)
|
||||
map->l_reldeps[j - 1] = map->l_reldeps[j];
|
||||
|
||||
--map->l_reldepsact;
|
||||
|
||||
/* Account for the '++i' performed by the 'for'. */
|
||||
--i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now determine the order in which the initialization has to happen. */
|
||||
memcpy (map->l_initfini, map->l_searchlist.r_list,
|
||||
nlist * sizeof (struct link_map *));
|
||||
|
150
elf/dl-lookup.c
150
elf/dl-lookup.c
@ -79,92 +79,94 @@ internal_function
|
||||
add_dependency (struct link_map *undef_map, struct link_map *map)
|
||||
{
|
||||
struct link_map **list;
|
||||
struct link_map *runp;
|
||||
unsigned int act;
|
||||
unsigned int i;
|
||||
int result = 0;
|
||||
|
||||
/* Avoid self-references. */
|
||||
if (undef_map == map)
|
||||
return 0;
|
||||
|
||||
/* Make sure nobody can unload the object while we are at it. */
|
||||
__libc_lock_lock_recursive (_dl_load_lock);
|
||||
|
||||
/* Determine whether UNDEF_MAP already has a reference to MAP. First
|
||||
look in the normal dependencies. */
|
||||
list = undef_map->l_initfini;
|
||||
|
||||
for (i = 0; list[i] != NULL; ++i)
|
||||
if (list[i] == map)
|
||||
break;
|
||||
|
||||
if (__builtin_expect (list[i] == NULL, 1))
|
||||
if (undef_map->l_searchlist.r_list != NULL)
|
||||
{
|
||||
/* 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;
|
||||
list = undef_map->l_initfini;
|
||||
|
||||
for (i = 0; i < act; ++i)
|
||||
for (i = 0; list[i] != NULL; ++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 (__builtin_expect (act >= undef_map->l_reldepsmax, 0))
|
||||
{
|
||||
/* 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
|
||||
* sizeof(struct link_map *));
|
||||
|
||||
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 (__builtin_expect (act < undef_map->l_reldepsmax, 1))
|
||||
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_mask & DL_DEBUG_FILES, 0))
|
||||
_dl_debug_printf ("\
|
||||
\nfile=%s; needed by %s (relocation dependency)\n\n",
|
||||
map->l_name[0] ? map->l_name : _dl_argv[0],
|
||||
undef_map->l_name[0]
|
||||
? undef_map->l_name : _dl_argv[0]);
|
||||
}
|
||||
else
|
||||
/* Whoa, that was bad luck. We have to search again. */
|
||||
result = -1;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
goto out;
|
||||
|
||||
/* 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. */
|
||||
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 (__builtin_expect (act >= undef_map->l_reldepsmax, 0))
|
||||
{
|
||||
/* 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
|
||||
* sizeof (struct link_map *));
|
||||
|
||||
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 (__builtin_expect (act < undef_map->l_reldepsmax, 1))
|
||||
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_mask & DL_DEBUG_FILES, 0))
|
||||
_dl_debug_printf ("\
|
||||
\nfile=%s; needed by %s (relocation dependency)\n\n",
|
||||
map->l_name[0] ? map->l_name : _dl_argv[0],
|
||||
undef_map->l_name[0]
|
||||
? undef_map->l_name : _dl_argv[0]);
|
||||
}
|
||||
else
|
||||
/* Whoa, that was bad luck. We have to search again. */
|
||||
result = -1;
|
||||
|
||||
out:
|
||||
/* Release the lock. */
|
||||
__libc_lock_unlock_recursive (_dl_load_lock);
|
||||
|
||||
@ -212,8 +214,6 @@ _dl_lookup_symbol (const char *undef_name, struct link_map *undef_map,
|
||||
we have to prevent the latter from being unloaded unless the
|
||||
UNDEF_MAP object is also unloaded. */
|
||||
if (__builtin_expect (current_value.m->l_type == lt_loaded, 0)
|
||||
&& current_value.m->l_global
|
||||
&& undef_map != current_value.m
|
||||
/* Don't do this for explicit lookups as opposed to implicit
|
||||
runtime lookups. */
|
||||
&& ! explicit
|
||||
@ -395,8 +395,6 @@ _dl_lookup_versioned_symbol (const char *undef_name,
|
||||
we have to prevent the latter from being unloaded unless the
|
||||
UNDEF_MAP object is also unloaded. */
|
||||
if (__builtin_expect (current_value.m->l_type == lt_loaded, 0)
|
||||
&& current_value.m->l_global
|
||||
&& undef_map != current_value.m
|
||||
/* Don't do this for explicit lookups as opposed to implicit
|
||||
runtime lookups. */
|
||||
&& ! explicit
|
||||
|
@ -37,14 +37,18 @@ _dl_new_object (char *realname, const char *libname, int type,
|
||||
struct link_map *l;
|
||||
int idx;
|
||||
size_t libname_len = strlen (libname) + 1;
|
||||
struct link_map *new = calloc (sizeof *new, 1);
|
||||
struct libname_list *newname = malloc (sizeof *newname + libname_len);
|
||||
if (! new || ! newname)
|
||||
struct link_map *new;
|
||||
struct libname_list *newname;
|
||||
|
||||
new = (struct link_map *) calloc (sizeof *new, 1);
|
||||
newname = (struct libname_list *) malloc (sizeof *newname + libname_len);
|
||||
if (new == NULL || newname == NULL)
|
||||
return NULL;
|
||||
|
||||
new->l_name = realname;
|
||||
newname->name = memcpy (newname + 1, libname, libname_len);
|
||||
newname->name = (char *) memcpy (newname + 1, libname, libname_len);
|
||||
newname->next = NULL;
|
||||
newname->dont_free = 0;
|
||||
new->l_libname = newname;
|
||||
new->l_type = type;
|
||||
new->l_loader = loader;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <mcheck.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/* How many load/unload operations do we do. */
|
||||
@ -139,6 +140,23 @@ main (int argc, char *argv[])
|
||||
testobjs[index].name, testobjs[index].handle);
|
||||
|
||||
testobjs[index].handle = NULL;
|
||||
|
||||
if (testobjs[0].handle == NULL
|
||||
&& testobjs[1].handle == NULL
|
||||
&& testobjs[5].handle == NULL)
|
||||
{
|
||||
/* In this case none of the objects above should be
|
||||
present. */
|
||||
for (map = _r_debug.r_map; map != NULL; map = map->l_next)
|
||||
if (map->l_type == lt_loaded
|
||||
&& (strstr (map->l_name, testobjs[0].name) != NULL
|
||||
|| strstr (map->l_name, testobjs[1].name) != NULL
|
||||
|| strstr (map->l_name, testobjs[5].name) != NULL))
|
||||
{
|
||||
printf ("`%s' is still loaded\n", map->l_name);
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (debug)
|
||||
@ -151,8 +169,8 @@ main (int argc, char *argv[])
|
||||
{
|
||||
printf ("\nclose: %s: l_initfini = %p, l_versions = %p\n",
|
||||
testobjs[count].name,
|
||||
((struct link_map*)testobjs[count].handle)->l_initfini,
|
||||
((struct link_map*)testobjs[count].handle)->l_versions);
|
||||
((struct link_map *) testobjs[count].handle)->l_initfini,
|
||||
((struct link_map *) testobjs[count].handle)->l_versions);
|
||||
|
||||
if (dlclose (testobjs[count].handle) != 0)
|
||||
{
|
||||
|
71
elf/reldep5.c
Normal file
71
elf/reldep5.c
Normal file
@ -0,0 +1,71 @@
|
||||
#include <dlfcn.h>
|
||||
#include <mcheck.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
void *h1;
|
||||
void *h2;
|
||||
int (*fp) (void);
|
||||
int *vp;
|
||||
|
||||
mtrace ();
|
||||
|
||||
/* Open the two objects. */
|
||||
h1 = dlopen ("reldepmod5.so", RTLD_LAZY);
|
||||
if (h1 == NULL)
|
||||
{
|
||||
printf ("cannot open reldepmod5.so: %s\n", dlerror ());
|
||||
exit (1);
|
||||
}
|
||||
h2 = dlopen ("reldepmod6.so", RTLD_LAZY);
|
||||
if (h2 == NULL)
|
||||
{
|
||||
printf ("cannot open reldepmod6.so: %s\n", dlerror ());
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* Get the address of the variable in reldepmod1.so. */
|
||||
fp = dlsym (h2, "bar");
|
||||
if (fp == NULL)
|
||||
{
|
||||
printf ("cannot get address of \"bar\": %s\n", dlerror ());
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* Call the function. */
|
||||
puts ("calling fp for the first time");
|
||||
if (fp () != 0)
|
||||
{
|
||||
puts ("function \"call_me\" returned wrong result");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* Now close the first object. It must still be around since we have
|
||||
an implicit dependency. */
|
||||
if (dlclose (h1) != 0)
|
||||
{
|
||||
printf ("closing h1 failed: %s\n", dlerror ());
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* Calling the function must still work. */
|
||||
puts ("calling fp for the second time");
|
||||
if (fp () != 0)
|
||||
{
|
||||
puts ("function \"call_me\" the second time returned wrong result");
|
||||
exit (1);
|
||||
}
|
||||
puts ("second call suceeded as well");
|
||||
|
||||
/* Close the second object, we are done. */
|
||||
if (dlclose (h2) != 0)
|
||||
{
|
||||
printf ("closing h2 failed: %s\n", dlerror ());
|
||||
exit (1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
5
elf/reldepmod5.c
Normal file
5
elf/reldepmod5.c
Normal file
@ -0,0 +1,5 @@
|
||||
int
|
||||
foo (void)
|
||||
{
|
||||
return 42;
|
||||
}
|
7
elf/reldepmod6.c
Normal file
7
elf/reldepmod6.c
Normal file
@ -0,0 +1,7 @@
|
||||
extern int call_me (void);
|
||||
|
||||
int
|
||||
bar (void)
|
||||
{
|
||||
return call_me ();
|
||||
}
|
Loading…
Reference in New Issue
Block a user