加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

链接Hook和tcmalloc分析

(2012-06-04 09:52:53)
标签:

tcmalloc

函数hook

替换系统调用

杂谈

分类: 软件开发

tcmalloc是Google Perftools中的一个组件,提供强大的内存池,比glibc的malloc快数倍;而且使用方便,只需添加链接选项-ltcmalloc即可。关于tcmalloc原理的分析已经有很多,这里就不重复了。本篇主要研究下tcmalloc是如何通过链接把new/delete/malloc/free等函数替换掉的

查了下相关资料,方法有3种:

方法1:使用环境变量LD_PRELOAD

环境变量LD_PRELOAD指定程序运行时优先加载的动态连接库,这个动态链接库中的符号优先级是最高的。标准C的各种函数都是存放在libc.so的文件中,在程序运行时自动链接。使用LD_PRELOAD后,自己编写的malloc的加载顺序高于glibc中的malloc,这样就实现了替换。

Hoard和TCMalloc的so版本就是这样实现的,陈皓也写过文章描述此方法的一些缺点

下面以strcmp为例来说明此方法

测试代码:

1 #include <stdio.h>
2 #include <string.h>
3   
4 int main(int argc, char **argv)
5 {
6     char passwd[] = "password";
7     if (argc < 2)
8     {
9         printf("Usage: %s <password>\n", argv[0]);
10         return 1;
11       
12   
13     if (!strcmp(passwd, argv[1]))
14     {
15         printf("Correct Password!\n");
16         return 0;
17       
18   
19     printf("Invalid Password!\n");
20     return 1;
21 }

编译:

1 g++ checkpasswd.cpp -o checkpasswd

运行:

1 ./checkpasswd password

结果:Correct Password!

so代码:

1 #include <stdio.h>
2 int strcmp(const char *s1, const char *s2)
3 {
4     printf("hack function invoked. s1=<%s> s2=<%s>\n", s1, s2);
5     return 0;
6 }

编译:

1 g++ hack.cpp -shared -fPIC -o hack.so

运行:

1 LD_PRELOAD="./hack.so" ./checkpasswd abc

结果变成了:

hack function invoked. s1=<password> s2=<abc>
Correct Password!

方法2 malloc调试变量

__malloc_hook是一组glibc提供的malloc调试变量中的一个,这组变量包括:

1 void *(*__malloc_hook)(size_t size, const void *caller);
2 void *(*__realloc_hook)(void *ptr, size_t size, const void *caller);
3 void *(*__memalign_hook)(size_t alignment, size_t size, const void *caller);
4 void (*__free_hook)(void *ptr, const void *caller);
5 void (*__malloc_initialize_hook)(void);
6 void (*__after_morecore_hook)(void);

只要你在程序中写上"__malloc_hook = my_malloc_hook;",之后的malloc调用都会使用my_malloc_hook函数,方便易行。但是这组调试变量不是线程安全的,当你想用系统malloc的时候不得不把他们改回来,多线程调用就得上锁了。因此方法2不很适用于系统内存优化,勉强用来简单管理线程内存使用。

详细用法请看这里;但要注意潜在的调用死循环,详情请看这里

tcmalloc的lib版本就是用的此方法,可以参看google-perftools-1.7版本src/tcmalloc.cc第348行:

http://taurus-ly.com/wp-content/uploads/image/2012/03/tcmalloc_hook.png

方法3 控制链接过程

ld中有一个选项 –wrap,当查找某个符号时,它优先先解析__wrap_symbol, 解析不到才去解析symbol。例如:

1 void *__wrap_malloc (size_t c)
2 {
3      printf ("malloc called with %u\n", c);
4      return __real_malloc (c);
5 }

当其它文件与你实现__wrap_malloc函数的文件链接时使用–wrap malloc ,则所有到malloc的调用都是会链接到__wrap_malloc上。只有调用__reall_malloc时才会调用真正的malloc

1 #include <stdio.h>
2 #include <stdlib.h>
3   
4 extern "C" void *__real_malloc(size_t);
5 extern "C" void *__real_free(void *); 
6   
7 extern "C" void *__wrap_malloc(size_t c)
8 {
9     printf("My MALLOC called: %d\n", c);
10     return __real_malloc(c);
11 }
12 extern "C" void *__wrap_free(void *ptr)
13 {
14     printf("My FREE called: 0xX\n", ptr);
15     return __real_free(ptr);
16 }
17   
18 int main (int argc, char *argv[])
19 {
20     void *ptr = malloc(12);
21     free(ptr);
22     return 0;
23 }

编译:

g++ wrap.cpp -o wrap -Wl,-wrap,malloc,-wrap,free

结果:

My MALLOC called: 12
My FREE called: 0×00501010

-Wl,option
把选项option传递给连接器.如果option中含有逗号,就在逗号处分割成多个选项.

参考:gcc手册http://www.shanghai.ws/gnu/gcc_2.htm

gcc -shared -Wl,-soname,your_soname \
    -o library_name file_list library_list

URL:http://taurus-ly.com/articles/2012/03/156.html

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有