简体   繁体   English

在运行时将函数与LD_PRELOAD链接

[英]Linking functions with LD_PRELOAD at runtime

I am writing a lib that intercepts the calls to malloc and free at runtime by running the program with LD_PRELOAD=mylib myexe . 我写拦截到的调用一个lib mallocfree与正在运行的程序在运行时LD_PRELOAD=mylib myexe

The calls to malloc and free are intercept fine. mallocfree的调用是很好的拦截。 My problem is that there's another function in mylib that I also want intercepted when LD_PRELOAD is used and I cannot figure out why it doesn't 'just work' like the calls to malloc and free . 我的问题是,在使用LD_PRELOAD时我还想要拦截mylib中的另一个函数,我无法弄清楚它为什么不像调用mallocfree那样“正常工作”。

In mylib.c: 在mylib.c中:

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

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

void otherThing(size_t)
{
    doThing();
}

In myexe.cpp: 在myexe.cpp中:

#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.
}

One way I have managed to get it to work is by doing: 我设法让它发挥作用的一种方法是:

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().
}

but I don't want to write all this code; 但我不想写所有这些代码; I don't have to do it for malloc and free . 我没有必要为mallocfree做这件事。 It's ok if the program crashes if the LD_PRELOAD prefix is missing. 如果程序在LD_PRELOAD前缀丢失时崩溃,则可以。

I feel like you're applying a single solution ( LD_PRELOAD ) to solve two different problems. 我觉得你正在应用一个解决方案( LD_PRELOAD )来解决两个不同的问题。 First, you want to patch malloc() and free() . 首先,您要修补malloc()free() You've got that working--great. 你有这个工作 - 很棒。 Next, you want to have a runtime "plug-in" system where you don't link against any library at build time, but only do so at runtime. 接下来,您希望拥有一个运行时“插件”系统,在该系统中,您不会在构建时链接任何库,而只能在运行时进行链接。 This is typically done using dlopen() and dlsym() , and I recommend you use those. 这通常使用dlopen()dlsym() ,我建议你使用它们。

The idea is that you don't want to specify a particular implementation of otherThing() at build time, but you do need to have some implementation at runtime (or you rightly expect to crash). 我们的想法是你不想在构建时指定otherThing()的特定实现,但是你需要在运行时有一些实现(或者你正确地期望崩溃)。 So let's be explicit about it and use dlsym() to resolve the function name at runtime, of course with error detection in case it's not found. 因此,让我们明确一下,并使用dlsym()在运行时解析函数名称,当然还有错误检测,以防它找不到。

As for where to define otherThing() , it can be in a totally separate file given to dlopen() , or in mylib (in which case pass NULL as the filename to dlopen() ). 至于在哪里定义otherThing() ,它可以在一个完全独立的文件中给予dlopen() ,或者在mylib (在这种情况下,将NULL作为文件名传递给dlopen() )。

It's a bit of a gotcha. 这有点儿了。 There are several posts relating to this on the internet, but I'll try to break it down to 'getting it to work'. 在互联网上有几个与此相关的帖子,但我会尝试将其分解为“让它工作”。

If this is under Linux, then what has happened is that the app has been compiled to not be able to use the external symbol. 如果这是在Linux下,那么发生的事情是该应用程序已被编译为无法使用外部符号。 The quickest solution is to add the same compilation flags to the main application as are used in the library ie add the -fPIC flag to the compilation of the main application, just like it is done for the library. 最快的解决方案是将相同的编译标志添加到主应用程序中,就像在库中使用一样,即将-fPIC标志添加到主应用程序的编译中,就像为库完成一样。

Rather than using the -Wl,--unresolved-symbols=ignore-all flag, you should be using the __attribute__ ((weak)) for the function, like: 而不是使用-Wl,--unresolved-symbols=ignore-all标志,你应该使用__attribute__ ((weak))来实现这个功能,例如:

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

And checking it for NULL at run-time, which will allow you to determine if it's been set or not. 并在运行时检查它是否为NULL,这将允许您确定它是否已设置。

By compiling the main application in the same way as a .so , you are implicitly allowing it to be used itself as a target for LD_PRELOAD as, by the manual page: 通过以与.so相同的方式编译主应用程序,您隐式允许将其自身用作LD_PRELOAD的目标,如手册页所示:

LD_PRELOAD LD_PRELOAD

A list of additional, user-specified, ELF shared libraries to be loaded before all others. 要在所有其他库之前加载的其他用户指定的ELF共享库的列表。 The items of the list can be separated by spaces or colons. 列表中的项目可以用空格或冒号分隔。 This can be used to selectively override functions in other shared libraries . 这可用于有选择地覆盖其他共享库中的函数

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM