在运行时将函数与LD_PRELOAD链接

时间:2013-04-21 01:01:12

标签: c++ linux gcc

我正在编写一个lib,它通过运行malloc的程序来拦截在运行时对freeLD_PRELOAD=mylib myexe的调用。

mallocfree的调用是正确的。我的问题是,在使用LD_PRELOAD时我还想要拦截mylib中的另一个函数,我无法弄清楚为什么它不像调用malloc和{{1}那样“正常工作” }。

在mylib.c中:

free

在myexe.cpp中:

void* malloc(size_t s)
{
    return doMyMalloc();
}

void free(void* p)
{
    doMyFree(p);
}

void otherThing(size_t)
{
    doThing();
}

我设法让它发挥作用的一种方法是:

#include <malloc.h>

extern "C" void otherThing(size_t);  // Compile with -Wl,--unresolved-symbols=ignore-all

int main(int argc, char* argv[])
{
    void* x = malloc(1000);   // Successfully intercepted.
    free(x);  // Successfully intercepted.
    otherThing(1);  // Segfault.
}

但我不想写所有这些代码;我不必为typedef void (*FUNC)(size_t); FUNC otherThing = NULL; int main(int argc, char* argv[]) { otherThing = (FUNC)dlsym(RTLD_NEXT, "otherThing"); otherThing(1); // Successfully calls mylib's otherThing(). } malloc执行此操作。 如果程序在free前缀丢失的情况下崩溃,则可以。

2 个答案:

答案 0 :(得分:0)

我觉得你正在应用一个解决方案(LD_PRELOAD)来解决两个不同的问题。首先,您要修补malloc()free()。你有这个工作 - 很棒。接下来,您希望拥有一个运行时“插件”系统,在该系统中,您不会在构建时链接任何库,而只能在运行时进行链接。这通常使用dlopen()dlsym()完成,我建议您使用这些。

这个想法是你不想在构建时指定otherThing()的特定实现,但是你需要在运行时有一些实现(或者你正确地期望崩溃)。因此,让我们明确一点,并使用dlsym()在运行时解析函数名称,当然还有错误检测,以防它找不到。

至于定义otherThing()的位置,它可以位于dlopen()mylib中的完全独立的文件中(在这种情况下,将NULL作为文件名传递给{{1} }})。

答案 1 :(得分:0)

这有点儿了。在互联网上有几个与此相关的帖子,但我会尝试将其分解为“让它工作”。

如果这是在Linux下,那么发生的事情是该应用程序已被编译为无法使用外部符号。最快的解决方案是向主应用程序添加与库中使用的相同的编译标志,即将-fPIC标志添加到主应用程序的编译中,就像为库完成一样。

您应该使用-Wl,--unresolved-symbols=ignore-all作为函数,而不是使用__attribute__ ((weak))标志,例如:

extern "C" void otherThing(size_t) __attribute__ ((weak);

在运行时检查它是否为NULL,这将允许您确定它是否已设置。

通过以与.so相同的方式编译主应用程序,您隐含地允许将其自身用作LD_PRELOAD的目标,如手册页所示:

<强> LD_PRELOAD

  

要包含的其他用户指定的ELF共享库的列表                 在所有其他人之前加载列表中的项目可以分隔                 空格或冒号。这可以用于有选择地覆盖                 其他共享库中的函数