动态加载使用--wrap=malloc编译的库时未解析的符号__real_malloc

unresolved symbol __real_malloc while dynamically loading a library which is compiled with --wrap=malloc

本文关键字:malloc 符号 real 加载 --wrap 编译 动态      更新时间:2023-10-16

如其他SO答案中所述,我正在使用GNU ld的包装机制来拦截Linux上对malloc的调用(请参阅此处获取示例)。所使用的链接器标志是-Wl,--wrap=malloc,并且还定义了相应的void __wrap_malloc(size_t)。这在所有编译单元都链接到同一个二进制文件的测试应用程序中运行良好。

现在,我需要修改一个动态链接库,该库通过dlopen()加载到主程序中。链接库成功,但用undefined symbol: __real_malloc将其加载到主程序失败。

在库上运行nm表明__wrap_malloc已定义,但__real_malloc未定义。但是,根据man ld和这个SO答案,当使用该技术时,malloc应该被__wrap_malloc取代,并且__real_malloc应该指向malloc

在测试应用程序中,我看到__real_malloc在编译的对象文件中是未定义的,但在链接到可执行文件后被解析。

那么,为什么符号在测试应用程序中解析,而在动态库中却没有解析呢?在这两种情况下,都会执行最后一个链接步骤,该步骤应解析此符号。还是需要在动态库的链接步骤中添加另一个库才能解析__real_malloc

以防万一,不可能修改通过dlopen加载动态库的目标应用程序。

它应该可以工作,并且只需要对您链接的问题中的代码进行轻微更改。

testapp.c

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
typedef void f_t(void);
int main()
{
    void* h = dlopen("./malloc_wrapper.so", RTLD_NOW);
    if (h == NULL)
    {
        puts(dlerror());
        exit(1);
    }
    f_t* f = (f_t*)dlsym(h, "test");
    if (f == NULL)
    {
        puts(dlerror());
        exit(1);
    }
    (*f)();
    return 0;
}

malloc_wapper.c

#include <stdlib.h> /* added */
#include <stdio.h>
void *__real_malloc (size_t);
/* This function wraps the real malloc */
void *__wrap_malloc(size_t size)
{
    void *lptr = __real_malloc(size);
    printf("Malloc: %lu bytes @%pn", size, lptr);
    return lptr;
}
void test(void) /* added */
{
    free(malloc(1024));
}

编译并运行。

gcc -Wl,-wrap,malloc -shared -fpic malloc_wrapper.c -o malloc_wrapper.so
gcc testapp.c -o testapp -ldl
./testapp
Malloc: 1024 bytes @0x1d44680

像这样编译malloc_wrapper.so会重现您描述的错误:

gcc -shared -fpic malloc_wrapper.c -o malloc_wrapper.so
./testapp
./malloc_wrapper.so: undefined symbol: __real_malloc

也许您在编译和链接可执行文件而不是共享对象时使用了wrap?