前言

LD_PRELOAD和ld --wrap都能实现不修改原始代码,替换指定函数的实现。通常我们会使用这些方法,替换如malloc)()/free()、read()/write()等函数,并在替换函数中做一些记录,以便能分析程序执行时的内存分配和IO情况。这些函数一般叫包裹函数。

LD_PRELAD

链接器会检查LD_PRELOAD这个环境变量,如果不为空,则优先使用LD_PRELOAD指定的动态库中的符号,以malloc()/free()为例。

代码清单 main.c

int main()
{
    malloc(10);
    return 0;
}

代码清单 my.c

void* malloc(size_t size)
{
    void (*__real_malloc)(int) = NULL;
    // 获取真实的malloc()地址
    __real_malloc = dlsym(RTLD_NEXT, "malloc");
    void* ptr =  __real_malloc(size);
    printf("[malloc] addr=%p, size=%u\n", ret, size);
    return ptr;
}

void free(void* ptr)
{
    printf("[free] addr=%p", ptr);
    void (*__real_free)(void*) = NULL;
    __real_free = dlsym(RTLD_NEXT, "free");
    return __real_free(ptr);
}

gcc main.c -o test将main.c编译成testgcc -fPIC -shared my.c -o libmy.somy.c编译成libmy.so

export LD_PRELOAD=./libmy.so后执行test会发现,main()中执行的malloc()实际是libmy.so中的malloc(),其会输出分配的内存地址和大小。因为没有free的输出,所以我们可以得知test存在内存泄漏。这是一个很简陋的例子。

export使得LD_PRELOAD对所有该终端执行的程序都生效,不使用时还需要unset LD_PRELOAD,我们可以通过LD_PRELOAD=./libmy.so ./test使得其只对test生效。

LD_PRELOAD的本质是先加载的先使用。就像我们在编译时会发现如果两个库中有同名函数,那么哪个库在前,就用哪个库中的函数。

ld --wrap

ld --wrap是一个编译链接时的参数,其原理是在编译时将--wrap指定的函数名进行替换,其替换规则就是替换规则就是包裹函数前加__wrap_,真实函数前加__real_,比如gcc main.c -o test -Wl,--wrap=malloc,编译器会将调用malloc()的地方替换为__wrap_malloc(),并将__real_malloc()符号名映射到真实malloc()的地址。

此时my.c的实现就不一样了,我们需要提供__wrap_malloc(),并在真正需要调用malloc()的地方使用__real_malloc()

void* __wrap_malloc(size_t size)
{
    void* ptr =  __real_malloc(size);
    printf("[malloc] addr=%p, size=%u\n", ret, size);
    return ptr;
}

void __wrap_free(void* ptr)
{
    printf("[free] addr=%p", ptr);
    return __real_free(ptr);
}

如果有比较多的--wrap,那么可以将其放在一个文件中,假设文件名为ld-opt,其内容如下

--wrap=malloc
--wrap=free

使用gcc main.c -o test -Wl,@ld-opt就能替换malloc和free了。

ld --wrap的本质是按指定规则替换符号名(malloc->__wrap_malloc),并将特定符号与执行代码关联(__real_malloc->maloc代码)。

最新文章

  1. JavaScript模板引擎artTemplate.js——结语
  2. JS生成二维码,允许中文转码
  3. Intellij IDEA +MAVEN+Jetty实现SpringMVC简单查询功能
  4. 关于Xcode7.2版本访问相册问题
  5. Housse Robber II | leetcode
  6. linux设备驱动归纳总结(九):1.platform总线的设备和驱动【转】
  7. Get start with Android development
  8. Xcode7.0设置网络白名单
  9. php 常用 小知识点
  10. Mac下安装多版本python
  11. Linux内存都去哪了:(1)分析memblock在启动过程中对内存的影响
  12. linux 安装软件三种方法
  13. Collectors类中的静态工厂方法
  14. python之路--初识html前端
  15. [C++] 左值、右值、右值引用
  16. Android文档 学习目录
  17. ubuntu16.04中开启和关闭防火墙
  18. 《Python》 property、classmethod、staticmethod、isinstance、issubclass
  19. try...cath...finally中的return什么时候执行
  20. Spark实际项目中调节并行度

热门文章

  1. JAVA基础-基础类型
  2. Redis HyperLogLog用法简介
  3. ServiceFabric极简文档-4.0 开发环境搭建
  4. UEditor 之初体验后记
  5. Docker实现GPA+Exporter监控告警系统
  6. openstack-neutron基本的网络类型以及分析
  7. 个人永久性免费-Excel催化剂功能第69波-专业图表库新增图表-刘万祥老师中国地图
  8. Linux基础学习整理
  9. bat命令闪退问题
  10. 【git】Git的使用