【发布时间】:2016-03-20 12:58:24
【问题描述】:
有一个简单的例子来描述我的问题:
我有 3 个文件,main、level1.so 和 level2.so。 (我的操作系统是solaris11.3,gcc版本是3.4.3)
在main中,它从level1.so调用execute()。 execute() 从 level2.so 调用 run()。 run() 调用 fcloseall(),在 level2.so 中重新定义。
fcloseall()被重新定义为什么都不做(它将关闭所有打开的fd,包括最初的stdout、stdin和stderr)。
现在我想在 main 中打印 execute() 周围的内容,但只打印 execute() 之前的消息。
代码如下:
level2.so由level2.c和level2depend.c编译而成。
level2.c:
#include <stdio.h>
int run()
{
fcloseall();
return 0;
}
level2depend.c:
#include <stdio.h>
int fcloseall() //redefine the std c function fcloseall
{
printf("in redefined fcloseall\n");
return 0;
}
level1.so是从level1.c编译而来的。
level1.c
#include <dlfcn.h>
int execute()
{
int (*sofunc)(void);
void * lib_handle = NULL;
char *errorInfo;
lib_handle = dlopen("./liblevel2.so",RTLD_LAZY);
if(!lib_handle)
{
return 0;
}
sofunc = (int(*)(void))dlsym(lib_handle,"run");
errorInfo = dlerror();
if (errorInfo != NULL){
dlclose(lib_handle);
return 0;
}
int ret = sofunc();
dlclose(lib_handle);
return 0;
}
main 是从 main.c 编译而来的。
main.c
#include <dlfcn.h>
#include <stdio.h>
int main()
{
int (*sofunc)(void);
void * lib_handle = NULL;
char *errorInfo;
lib_handle = dlopen("./liblevel1.so",RTLD_LAZY);
if(!lib_handle)
{
return 0;
}
sofunc = (int(*)(void))dlsym(lib_handle,"execute");
errorInfo = dlerror();
if (errorInfo != NULL){
dlclose(lib_handle);
return 0;
}
printf("before\n");
int ret = sofunc();
printf("after\n");
dlclose(lib_handle);
return 0;
}
makefile 是:
all:
gcc level2depend.c -o level2depend.o -c -g -fPIC
gcc level2.c -o level2.o -c -g -fPIC
gcc -shared -g level2.o level2depend.o -o liblevel2.so -fPIC
gcc level1.c -o level1.o -c -g -fPIC
gcc level1.o -o liblevel1.so -shared -fPIC
gcc main.c -o main -g -ldl
clean:
rm level2depend.o level1.o liblevel1.so level2.o liblevel2.so main
我执行main,结果是:
root@solaris#./main
before
如果我把makefile改成gcc main.c -o main -g -ldl -llevel2,结果是:
root@solaris#./main
before
in redefined fcloseall
after
这就是我想要的。
我想知道为什么会这样。谢谢!
【问题讨论】:
-
为什么不通过调试器运行它并自己单步调试代码?
-
level2 代码包含:
#include <stdio.h>,这是fcloseall()的原型。您的每个“子”文件都需要一个头文件。链接 main.c 时,需要引用您定义的库,因此将首先查看它们。注意:编写与系统函数同名的函数总是一个坏主意。 -
谢谢@Mike,我已经调试过了,我从一个相当复杂的项目中提取了这个例子。感谢@user3629249,你的回答给了我灵感。这个问题就像一个“全局符号插入”:当需要在全局符号表中添加一个符号时,如果存在相同的符号将被忽略。我使用
ldd来查找main 引用libc.so.1。更重要的是,fcloseall在libc.so.1中定义。所以如果我不使用-llevel2,main 会从lib.so.1中找到fcloseall。 -
您可能需要将 level2 与
-Bsymbolic标志链接,但请记住,这可能不是一个好主意。 -
谢谢@n.m。我加了
-Wl,-Bsymbolic,就可以了!
标签: c gcc shared-libraries solaris ld