__wrap_malloc 研究

__wrap_malloc 研究
即__malloc_hook 不推荐使用后, 用什么办法来在malloc 之前来注入代码呢?
gcc/g++ 的链接选项 -Wl,--wrap-malloc 可以解决这个问题. 下面给出一个具体
的实例来包装malloc, 包装free, 甚至包装任意一个函数.
它的作用是,在调用一个真实的库函数之前, 先调用包装函数.

先看一下主体代码, test.cpp中调用了 foo(), malloc(),free()函数.

$ cat test.cpp 
#include <stdio.h>
#include <stdlib.h>
#include "foo.h"
#include "wrap.h"

//必须要声明foo()的函数原型,否则编译不通过
//test.cpp|7 col 2| error: ‘foo’ was not declared in this scope
int main()
{
	foo();
	//因为添加了链接选项 -wl,--wrap=malloc, 所以会链接 __wrap_malloc
	// 否则, test.cpp:(.text+0xe):对‘__wrap_malloc’未定义的引用
	void* p1 = malloc(10);	
	//因为添加了链接选项 -wl,--wrap=free, 所以会链接 __wrap_free
	// 否则, test.cpp:(.text+0x1e):对‘__wrap_free’未定义的引用
	free(p1);
	fprintf(stdout, "test finish\n");
	return 0;
}

$ cat foo.h
#ifndef _FOO_H
#define _FOO_H
extern "C"
{
	extern void foo();
}
#endif

$ cat foo.cpp
#include <stdio.h>
#include "foo.h"
void foo()
{
	fprintf(stdout, "call foo function\n");
}

如果我们写Makefile

$ cat 1.mak
test: test.o foo.o 
	g++ -o test  $^ 

生成执行文件test: make -f 1.mak

执行:

$ ./test 
call foo function
test finish

现在,我们想注入,或者说包装或者说探测foo(),malloc(),free(), 怎么样操作呢? gcc 给了我们答案.

先写包装函数, 包装foo(),malloc(),free() 再改写一下Makefile.

先看一下Makefile 的改变

 cat Makefile 
test: test.o foo.o wrap.o
	g++ -o test  $^ -Wl,--wrap=malloc -Wl,--wrap=free -Wl,--wrap=foo

我们看到多了-Wl,--wrap=malloc -Wl,--wrap=free -Wl,--wrap=foo

同时也多了一个wrap.o是需要我们生成的. 下面看看wrap.cpp 长什么样

$ cat wrap.cpp 
#include <stdio.h>
#include "wrap.h"

//定义__wrap_malloc 及__wrap_free
//由于调用了__real_malloc, __real_free, 所以需要声明
//void * __real_malloc(size_t size);
//void __real_free(void *ptr)
//并且是 c_decl , 否则会有编译错误
// ‘__real_malloc’ was not declared in this scope   
//同时把__wrap_malloc,__wrap_free 声明为 c_decl, 否则还是链接不上
//‘__wrap_malloc’未定义的引用
void* __wrap_malloc(size_t size)
{
	fprintf(stdout, "_^_ call wrap malloc function _^_\n");
	return __real_malloc(size);
}

void __wrap_free(void* ptr)
{
	fprintf(stdout, "_^_ call wrap free function _^_\n");
	__real_free(ptr);
}

void __wrap_foo()
{
	fprintf(stdout, "_^_ call wrap foo function _^_\n");
	__real_foo();
}

命名规范必须是__wrap_xxx 形式, 通过__real_xxx方式调用真正的,原始的函数定义.  gcc 连接时负责把malloc 转化成__wrap_malloc 调用, 报___real_malloc 转化成malloc 来调用.

注意 __wrap_malloc, __real_malloc 都是cdecl 形式的调用, 所以,要在头文件中声明:

$ cat wrap.h
#ifndef _WRAP_H
#define _WRAP_H

//需要声明为 c_decl
extern "C"
{
	void* __real_malloc(size_t size);
	void __real_free(void* ptr);
	void* __wrap_malloc(size_t size);
	void __wrap_free(void* ptr);
//添加一个自定义函数
	void __wrap_foo();
	void __real_foo();
}

#endif

编译生成可执行文件,运行看看结果吧.

$ ./test 
_^_ call wrap foo function _^_
call foo function
_^_ call wrap malloc function _^_
_^_ call wrap free function _^_
test finish

我们看到确实先调用了wrap 函数,  这也叫调用的乾坤大挪移之法吧.

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值