一文搞懂linux的库打桩
Linux下的链接器支持一个强大的库打桩(library interpositioning),允许你阻拦对系统标准库中某个目标函数的调用,取而代之执行自己的包装函数。它可以给我们带来两个好处,一是通过增加某些语句,可以追踪自己的程序对某些库函数的调用情况;二是可以在你自己的程序中,对某些库函数偷天换日,替换成一个完全不同的实现。
打桩可以发生在编译,链接和运行的任意一个阶段,相应的代码编写和编译也有少量区别,下文将分别做一阐述:
需求:假设需要在主程序myprog.c中跟踪对库函数malloc和free的使用情况。
1.编译时打桩
1.1 建立包装函数
建立mymalloc.c文件,定义需要的包装函数mymalloc和myfree.
#ifdef COMPILETIME#include <stdio.h>#include <malloc.h>//定义malloc 包装函数void *mymalloc(size_t size){ void *ptr = malloc(size); printf("malloc(%d) = %p\n", (int)size, ptr); return ptr;}//定义free 包装函数void *myfree(void *ptr){ free(ptr); printf("free(%p) = %p\n", ptr);}#endif1.2 建立头文件malloc.h
该文件向预解决器指明用mymalloc.c中的包装函数替换库里的目标函数
#define malloc(size) mymalloc(size)#define free(ptr) myfree(ptr)void *mymalloc(size_t size);void *myfree(void *ptr);1.3 建立自己的程序文件
建立文件myprog.c,并在其中正常调用malloc函数.
#include <stdio.h>#include <malloc.h>int main(void){ int *p = malloc(32); free(p); return 0;}1.4 编译链接
gcc -DCOMPILETIME -c mymalloc.cgcc -I. -o myprog myprog.c mymalloc.c-I.:指示C预解决器在搜索通常的系统目录前,先在当前目录中查找malloc.h
1.5 运行结果
./myprogmalloc(32) = 0x9ee010free(0x9ee010)2.链接时打桩
linux利用静态链接器完成库打桩。先看它的一个命令行参数:
–wrap f:指示链接器把对符号f的引用解析成__wrap_f,把对__real_f的引用解析成符号f。
此处f代表任意的库函数名或者变量名-Wl,option:将option传递给链接器, option中的每个逗号都要用空格来替换。
2.1 建立包装函数
创立mymalloc.c文件,定义需要的包装函数.
#ifdef LIKETIME#include <stdio.h>void *__real_malloc(size_t size);void __real_free(void *ptr);//定义malloc 包装函数void *__wrap_malloc(size_t size){ void *ptr = *__real_malloc(size); //调用标准库里的malloc printf("malloc(%d) = %p\n", (int)size, ptr); return ptr;}//定义free 包装函数void *__wrap_free(void *ptr){ __real_free(ptr); //调用标准库里的free printf("free(%p) = %p\n", ptr);}#endif2.2 建立自己的程序文件
建立文件myprog.c,并在其中正常调用malloc函数.
#include <stdio.h>int main(void){ int *p = malloc(32); free(p); return 0;}2.3 编译链接
gcc -DLINKTIME -c mymalloc.cgcc -c myprog.cgcc -Wl,--wrap,malloc -Wl,--wrap,free -o myprog myprog.o mymalloc.o- -Wl,option:将option传递给链接器。 option中的每个逗号都要用空格来替换, 所以
-Wl,--wrap,malloc意味着把--wrap malloc传递给链接器。
2.4 运行结果
./myprogmalloc(32) = 0x18cf010free(0x18cf010)3 运行时打桩
编译时打桩需要访问程序的源代码,而链接时需要访问可重定位目标文件。那有没有一种办法让仅仅访问可执行目标就能达到同样的目的呢?我们可以利用基于动态链接器的LD_PRELOAD环境变量来实现。
当你将LD_PRELOAD环境变量设置为一个共享路径名的列表(以空格或者分号分开),那么在运行一个程序时,动态链接器(LD-LINUX.SO)会先搜索列表里的库,而后才搜素系统其它库。
利用这个原理,你可以对任何共享库中的任何函数打桩,包括libc.so。
3.1 建立包装函数文件
下面建立mymalloc.c文件,其中定义了malloc和free的包装函数。每个包装函数中,利用dlsym调用libc中的标准函数。
#ifdef RUNTIME#define _GNU_SOURCE#include <stdio.h>#include <stdlib.h>#include <dlfcn.h>//定义malloc 包装函数void *malloc(size_t size){ void *(*mallocp)(size_t size); //取得libc中malloc函数的地址 if( !(mallocp = dlsym(RTLD_NEXT, "malloc")) ){ fputs(dlerror()); exit(1); } char *ptr = *mallocp(size); //利用函数指针间接调用libc中的malloc函数 printf("malloc(%d) = %p\n", (int)size, ptr); return ptr;}//定义free 包装函数void *free(void *ptr){ void (*free)(void *) = NULL; if(!ptr) return; //取得libc中free函数的地址 if( !(freep = dlsym(RTLD_NEXT, "free")) ){ fputs(dlerror()); exit(1); } *freep(ptr); //利用函数指针间接调用libc中的free函数 printf("free(%p)\n", ptr); }#endif3.2 建立自己的程序文件
建立文件myprog.c,并在其中正常调用malloc函数.
#include <stdio.h>int main(void){ int *p = malloc(32); free(p); return 0;}3.3 编译包含包装函数的共享库
gcc -DRUNTIME -shared -fpic -o mymalloc.so mymalloc.c -ldl- -fpic:(position independent code)指示生成位置无关的目标文件;编译共享库时该参数为必选!
- -DRUNTIME:在命令行中定义宏定义RUNTIME,为了与文件头部
ifdef RUNTIME呼应。 - -shared:指示编译器生成一个共享目标文件。
- -ldl:指示链接器链接到libdl.so 共享库。
3.4 编译与运行主程序
gcc -o myprog myprog.c //编译在bash中运行,及其结果:
LD_PRELOAD="./mymalloc.so" ./myprog 结果如下
malloc(32) = 0x1bf7010 free(0x1bf7010)在csh或者tcsh中运行方法:
(setenv LD_PRELOAD "./mymalloc.so"; ./myprog; unsetenv LD_PRELOAD)结果如下
malloc(32) = 0x2157010 free(0x2157010)4. 拓展
GNU binutils包有许多实用的工具特别有帮助,而且可以运行在每一个Linux平台上。
- AR: 创立静态库,插入/删除/列出和提取成员函数。
- STRINGS:列出目标文件中所有可打印字符串;
- STRIP:从目标文件中删除符号表信息;
- NM: 列出目标文件中符号表中定义的符号;
- SIZE:列出目标文件中各段的大小;
- READELF:显示目标文件的完整结构,包括ELF头中编码的所有信息。包含了NM和SIZE的作用;
- OBJDUMP:显示目标文件中所有的信息,最大的左右是反汇编.text段中的二进制指令成汇编指令。
- LDD:列出可执行文件运行时需要的所有共享库。
获取更多知识,请点击关注:
嵌入式Linux&ARM
CSDN博客
简书博客
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 一文搞懂linux的库打桩