今天遇到一个因为没有定义的符号导致 dlopen失败的问题。
这个问题可以用几段简单的代码来模拟:
$ cat 1.c
void foo(void)
{
}
$ cat 2.c
extern void foo();
void goo()
{
foo();
}
$ cat test.c
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main()
{
void *handle;
char *error;
void (*goo)(void);
handle = dlopen("./lib2.so", RTLD_NOW);
if(!handle)
{
fprintf(stderr, "dlopen failure: %s\n", dlerror());
return 0;
}
dlerror();
goo = (void(*)(void))dlsym(handle, "goo");
error = dlerror();
if(error != NULL)
{
fprintf(stderr, "dlsym failure: %s\n", error);
return 0;
}
(*goo)();
return 0;
}
执行命令:
$ gcc -shared -fpic 1.c -g -o lib1.so
$ gcc -shared -fpic 2.c -g -o lib2.so
$ gcc test.c -g -o test
执行测试代码:
$ ./test
dlopen failure: ./lib2.so: undefined symbol: foo
在 lib2.so里找不到 foo的定义。
用 nm查看一下:
$ nm lib2.so | grep foo
U foo
foo 确实是 "U"
用 ldd查看下 lib2.so的依赖:
$ ldd lib2.so
statically linked
没有依赖lib1.so, 这或许是问题的原因。
加上lib1.so的依赖, 重新编译 lib2.so:
gcc -shared -fpic 2.c -g -o lib2.so -l1 -L.
再用 ldd查看:
$ldd lib2.so
linux-vdso.so.1 (0x00007ffd250ca000)
lib1.so => ./lib1.so (0x00007cfb6e36f000)
再执行 test,就没有刚才的那个问题了。