【问题标题】:I redefine a standard C library function in a dynamic library, but I can't use it我在动态库中重新定义了一个标准 C 库函数,但我不能使用它
【发布时间】:2016-03-20 12:58:24
【问题描述】:

有一个简单的例子来描述我的问题:

我有 3 个文件,ma​​inlevel1.solevel2.so。 (我的操作系统是solaris11.3,gcc版本是3.4.3)

ma​​in中,它从level1.so调用execute()execute()level2.so 调用 run()run() 调用 fcloseall(),在 level2.so 中重新定义。

fcloseall()被重新定义为什么都不做(它将关闭所有打开的fd,包括最初的stdout、stdin和stderr)。

现在我想在 main 中打印 execute() 周围的内容,但只打印 execute() 之前的消息。

代码如下:

level2.solevel2.clevel2depend.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;
}

ma​​in 是从 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;
}

ma​​kefile 是:

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 &lt;stdio.h&gt;,这是 fcloseall() 的原型。您的每个“子”文件都需要一个头文件。链接 main.c 时,需要引用您定义的库,因此将首先查看它们。注意:编写与系统函数同名的函数总是一个坏主意。
  • 谢谢@Mike,我已经调试过了,我从一个相当复杂的项目中提取了这个例子。感谢@user3629249,你的回答给了我灵感。这个问题就像一个“全局符号插入”:当需要在全局符号表中添加一个符号时,如果存在相同的符号将被忽略。我使用ldd 来查找main 引用libc.so.1。更重要的是,fclosealllibc.so.1 中定义。所以如果我不使用-llevel2main 会从lib.so.1 中找到fcloseall
  • 您可能需要将 level2 与 -Bsymbolic 标志链接,但请记住,这可能不是一个好主意。
  • 谢谢@n.m。我加了-Wl,-Bsymbolic,就可以了!

标签: c gcc shared-libraries solaris ld


【解决方案1】:

可以使用ld提供的wrap函数。

gcc -Wl,-wrap,fcloseall ....

在您的源代码中,

int __wrap_fcloseall(void)
{...}

【讨论】:

  • 谢谢@lyyyuna,你的方法可以解决我的问题。我添加-Wl,-wrap, fcloseall 来构建liblevel2.so,而不是添加-llevel2 来构建main,它就像我想要的那样工作!但是在我的构建机(sol10)中,ld 无法识别-wrap...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-14
  • 1970-01-01
  • 2022-10-14
  • 1970-01-01
相关资源
最近更新 更多