通过RTLD_LAZY链接动态库

时间:2014-03-23 13:23:13

标签: linux dynamic-linking

我试图找到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时错了吗?如果是的话那我应该怎么创建呢?

由于

3 个答案:

答案 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.sofun2.so,这就是您看到此行为的原因。

答案 2 :(得分:0)

在“ fliX”之后,您可以看到nm给出的示例:

     U bar

然后我们得到未解决的错误。

因此,如果装载中包含一些未定义的符号,则无法调用该函数,而您则调用该库。因此,即使在某些时候它是死代码,也应在加载时解决,因为当该符号命中时,PROCESSOR指令将是未知的。