库打桩的基本思想:
给定一个需要打桩的目标函数,创建一个包装函数,它的原型与目标函数完全一样。使用某种特殊的打桩机制,就可以欺骗操作系统调用包装函数而不是目标函数。包装函数会有自己的逻辑,然后再去调用目标函数,最后将目标函数的返回值传递给调用者。
库打桩的作用:
可以截获对共享库函数的调用,取而代之执行自己的代码。

1.编译时打桩

(1)明确:编译时打桩需要能够访问程序的源代码。

(2)编译时打桩的主要思想:
就是让C预处理器在搜索通常的系统目录之前,先在当前目录中查找头文件,如果在当前目录中查找到对应的头文件,就会使用此头文件,而不会再去寻找其他的。

(3)如何进行编译时打桩:
第一步:首先在当前目录中存放好需要被调用的头文件,这个头文件里面有设计好的包装函数。(加入在本地保存的文件叫"malloc.h",包装函数所在文件叫“mymalloc.c”)
第二步:编译和链接,如下:
linux> gcc -DCOMPILETIME -c mymalloc.c
linux> gcc -I. -o intc int.c mymalloc.o
使用“-I.”进行编译链接,可以告诉C预处理器在搜哟通常的系统目录之前,现在当前目录中寻找malloc.h。
注:
①这里的-DCOMPILETIME是mymalloc.c里面定义的一个宏,这个宏作为mymalloc.c程序的开关
②mymalloc.c里面的包装函数分别是mymalloc()和myfree(),这两个函数内部各自调用系统的malloc()和free(),并在调用完毕打印出申请和释放的地址及大小。通过这样的打桩机制,可以看到申请空间的起始地址。

2.链接时打桩

Linux静态链接器支持用–wrap f标志进行链接时安装,这个标志告诉链接器,把对符号f的引用解析成_ _ wrap_f。

(1)明确:链接时打桩需要能够访问程序的可重定位对象文件。

(2)链接时打桩的主要思想:
链接时打桩就是在输入链接指令的时候将“-wl,f”写入到链接指令中,然后让程序链接指定库中的对应的f这个函数
例如:
linux> gcc -DLINKTIME -c mymalloc
linux> gcc -c int.c
linux> gcc -wl,–wrap,malloc -wl --wrap,free -o intl tin.o mymalloc.o

(3)如何进行链接时打桩:
注:下面的symbol可以替换成你想要进行打桩的目标函数名。–wrap是GCC的选项,用来进行链接时打桩。
第一步:链接时打桩就是当我们把目标文件链接成可执行文件的时候,加上“-wl,opction”,这里的“-wl,opction”标志会把opction传递给链接器,然后使得opction里面的每一个成员从原本的以逗号分割变为以空格分割,如:opction是 “ --wrap,symbol ” 变为 “–wrap symbol ”
第二步:最后链接器将 “–wrap symbol ”引用解析对应的成包装函数“_ _ wrap_ symbol”。
第三步:注意的是,包装函数写成_ _ wrap_‘目标函数名’,而包装函数里面需要调用的目标函数要写成“_ _ real_ ‘目标函数名’ ”的格式,这样在引用解析的时候就会去掉“_ _ real_”,从而调用目标函数。

3.运行时打桩

(1)明确:运行时打桩只需要能够访问可执行目标文件即可。

(2)运行时打桩的基本思想:
将LD_PRELOAD环境变量设置为一个共享库路径名的列表,当加载和执行一个程序,需要解析未定义的引用时,动态链接器会先搜索LD_PRELOAD库,然后才搜索其他的库。
注意:使用LD_PRELOAD,当我们加载和执行任意可执行文件时,可以对任何可执行程序的库函数调用打桩。

(3)如何进行运行时打桩:
运行时打桩就是在输入命令进行连接的时候设置“LD_PRELOAD”环境变量为共享库路径名的列表。
例如:
linux> LD_PRELOAD=“./mymalloc.so” ./intr
除此之外,需要注意的是:因为是在运行时打桩,所以应该考虑到在应用程序被加载后执行前,动态链接器加载和连接共享库的场景,所以我们的共享库文件应该是使用Linux系统为动态链接器提供的接口"dlsym、dlerror……"等接口函数来编写包装函数。