库打桩机制

库打桩机制

什么是库打桩机制

库打桩机制(library interpositioning),允许调用者截获对共享库函数的调用,用调用者所写的代码替换执行。
作用:追踪某个库函数的调用次数,甚至是替换成一个全新功能的函数。
基本思想为:为一个需要打桩的目标函数,创建一个包装函数。包装函数的原型与目标函数需要完全一致。
包装函数通常会执行自己的逻辑,然后调用目标函数,最后将目标函数的返回值传递给调用者。
打桩可以发生在编译时,链接时或者运行时。

以malloc与free函数为例,示范打桩机制过程。

编译时打桩

声明与定义包装的malloc与free函数
头文件mymalloc.h

#ifndef MALLOC_H_
#define MALLOC_H_

#define malloc(size) mymalloc(size)
#define free(ptr)  myfree(ptr)

void *mymalloc(size_t size);
void myfree(void* ptr);

#endif

.c文件mymalloc.cc

#ifdef COMPILETIME
#include <stdio.h>
#include <malloc.h>

void *mymalloc(size_t size){
    void* ptr = malloc(size);
    printf("malloc(%d)=%p\n",(int)size,ptr);
    return ptr;
}

void myfree(void* ptr){
    free(ptr);
    printf("free(%p) \n",ptr);
}

#endif

测试程序main.c

#include <stdio.h>
#include "mymalloc.h"

int main(){
    int *p = malloc(32);
    free(p);
    return 0;
}

利用gcc进行编译:

gcc -DCOMPILETIME -c mymalloc.c
gcc -I. -o test main.c mymalloc.o

结果:

malloc(32)=0x5638216d6670
free(0x5638216d6670) 

从结果看出,确实执行了我们定义的malloc与free函数。

链接时打桩

mymalloc.c

#ifdef LINKTIME
#include <stdio.h>
void *__real_malloc(size_t size);
void __real_free(void* ptr);

void *__wrap_malloc(size_t size){
    void* ptr = __real_malloc(size);
    printf("malloc(%d) = %p\n",(int)size,ptr);
    return ptr;
}

void __wrap_free(void *ptr){
    __real_free(ptr);
    printf("free(%p)\n",ptr);
}

#endif

测试程序跟编译时打桩类似。执行编译与链接指令:

gcc -DLINKTIME -c mymalloc.c
gcc -c main.c
gcc -Wl,--wrap,malloc -Wl,--wrap,free -o test main.o mymalloc.o

这里的-Wl,option标志会把option传递给编译器,所以-Wl,–wrap,malloc就把–wrap与malloc传递给编译器。

运行时打桩

编译时打桩需要访问程序的源代码,链接时打桩需要访问程序的可重定位对象文件(.o),运行时打桩只需要访问动态库即可。
这种机制的实现依赖于动态链接器的LD_PRELOAD环境变量。
mymalloc.c代码`

#ifdef RUNTIME
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

void *malloc(size_t size){
    void *(*mallocp)(size_t size);
    char* error;

    mallocp=dlsym(RTLD_NEXT,"malloc");
    if((error=dlerror()) != NULL){
        fputs(error,stderr);
        exit(1);
    }

    char* ptr = mallocp(size);
    //对一些linux版本,使用printf的话由于printf本身需要使用malloc,来开辟缓存(因为printf使用stdout方式),会导致段错误,因此这里打印通过stderr的方式
    fprintf(stderr,"malloc(%d)=%p\n",(int)size,ptr);
    // fputs("malloc(%d)=%p \n",stderr);
    // printf("malloc(%d)=%p \n",(int)size,ptr);
    return ptr;
}

void free(void* ptr){
    void (*freep)(void*) = NULL;
    char* error;
    if(!ptr){
        return;
    }

    freep=dlsym(RTLD_NEXT,"free");
    if((error=dlerror()) != NULL){
        fputs(error,stderr);
        exit(1);
    }

    freep(ptr);
    fprintf(stderr,"free(%p)\n",ptr);
}


#endif

编译与执行:

gcc -DRUNTIME -shared -fpic -o mymalloc.so mymalloc.c -ldl
LD_PRELOAD="./mymalloc.so" ./test

使用运行时打桩LD_PRELOAD方式,可以对任何可执行文件进行函数打桩。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值