我试图找到RTLD_NOW和RTLD_LAZY标志之间的差异。我的查询是为什么RTLD_LAZY加载了我从未报道过的函数的库。
我创建了一个dlrun.c文件
#include "stdio.h"
#include "dlfcn.h"
main()
{
void * ptr;
void (*fptr)(void);
printf("\nMy ID is- %d \n",getpid());
getchar();
ptr = dlopen("./fun5.so", RTLD_NOW);
if(ptr==NULL)
printf("failed to open fun5.so");
else
{
printf("I got fun5.so");
fptr= dlsym(ptr,"fun5");
getchar();
fptr();
printf("end of fun5");
dlclose(ptr);
}
}
下一个文件fun5.c as
#include "stdio.h"
void fun2(void);
void fun1(void);
fun5()
{
printf("I am in fun5");
getchar();
fun1();
}
fun()
{
getchar();
fun2();
}
其他文件fun1.c是
#include "stdio.h"
fun1()
{
printf("I am in fun1");
getchar();
}
和文件fun2.c是
#include "stdio.h"
fun2()
{
printf("I am in fun2");
getchar();
}
然后我使用命令
gcc -c -fPIC -o fun1.o fun1.c
gcc -c -fPIC -o fun2.o fun2.c
gcc -c -fPIC -o fun5.o fun5.c
gcc -shared -o fun1.so fun1.o
gcc -shared -o fun2.so fun2.o
gcc -shared -o fun5.so fun5.o ./fun1.so ./fun2.so
gcc dlrun.c -o run -ldl
./run
现在我想检查
加载哪些库cd /proc/<pid>
vi maps
这里看起来在fun5.so调用之前没有加载nonstansard libray并且在调用fun5函数之后所有fun5.so,fun1.so和fun.2.so按照期望加载。现在如果我用RTLD_LAZY替换RTLD_NOW然后应该加载fun5.so和fun1.so,因为我从来没有调用过fun()和fun2(),但实际上fun2.so也在加载。所以我错了?我在创建fun5.so时错了吗?如果是的话那我应该怎么创建呢?
由于
答案 0 :(得分:10)
以下示例应该非常明确:
<强> libtest.so:强>
void bar();
void foo()
{
bar();
}
_
$> nm libtest.so
000085d0 a _DYNAMIC
000086b0 a _GLOBAL_OFFSET_TABLE_
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
w _Jv_RegisterClasses
000005c0 r __FRAME_END__
000085cc d __JCR_END__
000085cc d __JCR_LIST__
000086e0 d __TMC_END__
000086e4 B __bss_end__
000086e0 B __bss_start
000086e0 B __bss_start__
w __cxa_finalize@@GLIBC_2.4
000004f8 t __do_global_dtors_aux
000085c8 t __do_global_dtors_aux_fini_array_entry
000086dc d __dso_handle
000086e4 B __end__
000085c4 t __frame_dummy_init_array_entry
w __gmon_start__
000086e4 B _bss_end__
000086e0 D _edata
000086e4 B _end
000005b8 T _fini
000003e0 T _init
U bar
00000424 t call_weak_fn
000086e0 b completed.8847
00000448 t deregister_tm_clones
000005a8 T foo
00000560 t frame_dummy
0000049c t register_tm_clones
main.c(flag == RTLD_LAZY):
#include <dlfcn.h>
#include <stdio.h>
int
main(int argc, char **argv)
{
void *lib = dlopen("./libtest.so", RTLD_LAZY);
if (!lib) {
printf("error: %s\n", dlerror());
return 0;
}
int (*a)() = dlsym(lib, "foo");
printf("a: %p\n", a);
(*a)();
dlclose(lib);
return 1;
}
$> ./main.c
a: 0xb6e225a8
./main: symbol lookup error: ./libtest.so: undefined symbol: bar
main.c(flag == RTLD_NOW):
#include <dlfcn.h>
#include <stdio.h>
int
main(int argc, char **argv)
{
void *lib = dlopen("./libtest.so", RTLD_NOW);
if (!lib) {
printf("error: %s\n", dlerror());
return 0;
}
int (*a)() = dlsym(lib, "foo");
printf("a: %p\n", a);
(*a)();
dlclose(lib);
return 1;
}
$> ./main.c
error: ./libtest.so: undefined symbol: bar
答案 1 :(得分:4)
RTLD_LAZY
实际上意味着懒惰地解析符号,而不是懒惰地加载库。 fun5.so
取决于这两个库,因此在加载fun5.so
时会加载它们。
该行:
gcc -shared -o fun5.so fun5.o ./fun1.so ./fun2.so
告诉我们fun5.so
明确取决于fun1.so
和fun2.so
,这就是您看到此行为的原因。
答案 2 :(得分:0)
在“ fliX”之后,您可以看到nm给出的示例:
U bar
然后我们得到未解决的错误。
因此,如果装载中包含一些未定义的符号,则无法调用该函数,而您则调用该库。因此,即使在某些时候它是死代码,也应在加载时解决,因为当该符号命中时,PROCESSOR指令将是未知的。