例如,如果我想覆盖malloc(),那么最好的方法是什么?
目前我所知道的最简单的方法是:
malloc.h所
#include <stdlib.h>
#define malloc my_malloc
void* my_malloc (size_t size);
foobar.c但是
#include "malloc.h"
void foobar(void)
{
void* leak = malloc(1024);
}
这种方法的问题是我们现在必须使用“malloc.h”并且永远不能使用“stdlib.h”。有没有解决的办法?我特别感兴趣的是导入第三方库而不修改它们,但强迫它们调用我的自定义libc函数(如malloc)。
答案 0 :(得分:5)
简短的回答是你可能想要使用LD_PRELOAD技巧:What is the LD_PRELOAD trick?
该方法基本上在加载任何其他共享库之前在运行时插入您自己的自定义共享库,导出您要覆盖的函数,例如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允许在任何其他库之前加载共享库。所以我需要做的就是编写一个覆盖write和puts函数的共享库。如果我们包装这些函数,我们需要一种方法来调用实际函数来执行系统调用。 dlsym只为我们这样做[man 3 dlsym]:&gt;函数dlsym()接受dlopen()返回的动态库的“句柄”和以null结尾的符号名称,返回该符号加载到内存中的地址。如果未找到符号,则在指定的库或dlopen()在加载该库时自动加载的任何库中,dlsym()将返回NULL ...
所以在包装函数中我们可以使用dlsym来获取内存中相关符号的地址并调用glibc函数。另一种方法是直接调用系统调用,两种方法都可以。
该博客文章还描述了一个我不知道的编译时方法,涉及将链接器标志传递给ld,&#34; - wrap&#34;:
包装函数的另一种方法是在链接时使用链接器。 GNU链接器提供了一个包含符号函数的选项[man 1 ld]:&gt;使用符号包装函数。任何未定义的符号引用都将解析为“__wrap_symbol”。对“__real_symbol”的任何未定义引用都将被解析为符号。
关于LD_PRELOAD的一个方便的事情是,可能允许您更改生产应用程序上的malloc()实现以进行快速测试,甚至允许用户选择(我在某些服务器应用程序中执行此操作)要使用的实现。 &#39; tcmalloc&#39;例如,库可以很容易地插入到应用程序中,以评估高度线程化应用程序中的性能提升(其中tcmalloc往往比libc的malloc实现更好)。
最后,如果您使用的是Windows,请尝试以下操作:LD_PRELOAD equivalent for Windows to preload shared libraries