C语言 如何覆盖标准 libc 函数



例如,如果我想覆盖malloc(),最好的方法是什么?

目前我所知道的最简单的方法是:

马洛克·

#include <stdlib.h>
#define malloc my_malloc
void* my_malloc (size_t size);

福巴

#include "malloc.h"
void foobar(void)
{
    void* leak = malloc(1024);
}

这种方法的问题在于我们现在必须使用"malloc.h",而永远不能使用"stdlib.h"。 有没有办法解决这个问题? 我对导入第三方库特别感兴趣,根本不修改它们,而是强迫它们调用我的自定义 libc 函数(如 malloc)。

简短的回答是您可能想使用LD_PRELOAD技巧:LD_PRELOAD技巧是什么?

这种方法基本上是在加载任何其他共享库之前在运行时插入您自己的自定义共享库,导出要覆盖的函数,例如 malloc()。加载其他共享库时,您的符号已经存在,并且在解析从其他库调用该符号名称时获得首选项。在 malloc() 包装器/替换器中,您甚至可以选择调用下一个 malloc 符号,它通常是实际的 libc 符号。

这篇博文有很多关于这种方法的全面信息:

http://samanbarghi.com/blog/2014/09/05/how-to-wrap-a-system-call-libc-function-in-linux/

请注意,示例覆盖了libc的write()和puts()函数,但相同的逻辑适用于malloc():

LD_PRELOAD允许在任何其他库之前加载共享库。所以我需要做的就是编写一个覆盖写入并放置函数的共享库。如果我们包装这些函数,我们需要一种方法来调用真正的函数来执行系统调用。dlsym 只是为我们 [man 3 dlsym] 这样做:> 函数 dlsym() 获取 dlopen() 返回的动态库的"句柄"和以 null 结尾的符号名称,返回该符号加载到内存中的地址。如果未找到该符号,则在指定的库或加载该库时由 dlopen() 自动加载的任何库中,dlsym() 返回 NULL...

所以在包装函数内部,我们可以使用 dlsym 获取内存中相关符号的地址并调用 glibc 函数。另一种方法是直接调用系统调用,这两种方法都有效。

那篇博文还描述了一个我不知道的编译时方法,该方法涉及将链接器标志传递给ld,"--wrap":

包装函数的另一种方法是在链接时使用链接器。GNU 链接器提供了一个选项来包装符号的函数 [man 1 ld]:> 对符号使用包装函数。任何对符号的未定义引用都将解析为"__wrap_symbol"。任何对"__real_symbol"的未定义引用都将解析为符号。

LD_PRELOAD的方便之处在于,它可能允许您更改生产应用程序上的 malloc() 实现以进行快速测试,甚至允许用户选择(我在某些服务器应用程序中这样做)要使用的实现。例如,"tcmalloc"库可以很容易地插入到应用程序中,以评估重线程应用程序的性能提升(其中tcmalloc的性能往往比libc的malloc实现好得多)。

最后,如果你在Windows上,也许可以试试这个:LD_PRELOAD等效于Windows预加载共享库。

最新更新