前言

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代码)。

LD_PRELOAD和ld --wrap的更多相关文章

  1. Linux下的库操作工具-nm、ar、ldd、ldconfig和ld.so

    Linux下的库操作工具-nm.ar.ldd.ldconfig和ld.so .nm [options] file 列出file中的所有符号 [option] -c 将符号转化为用户级的名字 -s 当用 ...

  2. CSAPP CH7链接的应用:静动态库制作与神奇的库打桩机制

    目录 创建静态库 创建动态库 库打桩机制 编译时打桩: 链接时打桩 运行时打桩 运行时打桩的printf与malloc循环调用debug 使用LD_PRELOAD对任意可执行程序调用运行时打桩 总结 ...

  3. How to install 64-bit Google Chrome 28+ on 64-bit RHEL/CentOS 6 or 7

    How to install 64-bit Google Chrome 28+ on 64-bit RHEL/CentOS 6 or 7 The problem Google developers s ...

  4. ERROR: ld.so: object '/usr/lib64/libtcmalloc.so.4' from LD_PRELOAD cannot be preloaded: ignored

    出现错误: ERROR: ld.so: object '/usr/lib64/libtcmalloc.so.4' from LD_PRELOAD cannot be preloaded: ignore ...

  5. Linux Dynamic Shared Library && LD Linker

    目录 . 动态链接的意义 . 地址无关代码: PIC . 延迟版定(PLT Procedure Linkage Table) . 动态链接相关结构 . 动态链接的步骤和实现 . Linux动态链接器实 ...

  6. gcc ld 链接器相关知识,调试指令(程序员的自我修养----链接、装载与库)

    最近解决一个动态链接上的问题,因为以前从来没有接触过这方面的知识,所以恶补了一下,首先要了解gcc编译指令(makefile),ld链接器的选项(还有连接脚本section指定内存位置),熟悉查看连接 ...

  7. 【Linux】LD_PRELOAD用法

    转载https://blog.csdn.net/iEearth/article/details/49952047 还有一篇博客也可以看看https://blog.csdn.net/xp5xp6/art ...

  8. LD_PRELOAD & LD_LIBRARY_PATH 动态库路径

    参考:http://www.cnblogs.com/waterlin/archive/2011/07/14/2106056.html 143上的glibc较低,同学又不能进行升级(造成全局影响),所以 ...

  9. 使用LD_Preload的Linux权限升级技巧

      0x00 前言 共享库是程序在启动时加载的库.正确安装共享库后,之后启动的所有程序将自动使用新的共享库. 0x01 共享库名称 每个共享库都有一个名为soname的特殊名称.soname有前缀li ...

随机推荐

  1. node调试工具--nodemon使用简介

    这个工具和node-supervisor基本上是一致的,但是其功能比较强大,个人觉得在开发环境还是用 nodemon,因为配置比较方便,文档也很清晰.所以这里先主要讲 nodemon. nodemon ...

  2. Java编程思想:Preferences

    import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; public class Test ...

  3. 如何入门 MySQL

    如何入门MySQL 前言: 关于如何入门MySQL,后台有好多同学咨询我,可能部分读者刚开始学习MySQL,我前面发的文章对部分同学来说暂时接触不到.原本写技术文章的目的是记录自己的工作学习,没有考虑 ...

  4. 洛谷 P3367 并查集 【模板题】

    题目描述 如题,现在有一个并查集,你需要完成合并和查询操作. 输入输出格式 输入格式: 第一行包含两个整数N.M,表示共有N个元素和M个操作. 接下来M行,每行包含三个整数Zi.Xi.Yi 当Zi=1 ...

  5. eclipse(java windows)

    百度云:链接:http://pan.baidu.com/s/1i4Zjv97    密码:u0qh 官方下载网址:http://www.eclipse.org/downloads/eclipse-pa ...

  6. AMD CPU环境下使用android studio,eclipse的Genymotion插件

    1.下载安装VirtualBox Genymotion的运行需要此环境(链接) 2.下载安装android模拟器Genymotion 由于官网的下载速度过慢,建议直接百度下载Genymotion(链接 ...

  7. 备战金九银十,Java研发面试题(Spring、MySQL、JVM、Mybatis、Redis、Tomcat)[带答案],刷起来!

    八月在即,马上就是"金九银十",又是跳槽招聘季.咱们这行公认涨薪不如跳槽加的快.但不建议频繁跳槽,还是要学会融合团队,抓住每个机会提升技能. 苏先生在这里给大家整理了一套各大互联网 ...

  8. StringBuffer类的delete()方法和deleteCharAt()方法的区别

    引言 StringBuffer类的delete()方法和deleteCharAt()方法都是用来删除StringBuffer字符串中的字符 区别 1.对于delete(int start,int en ...

  9. 【Python3爬虫】当爬虫碰到表单提交,有点意思

    一.写在前面 我写爬虫已经写了一段时间了,对于那些使用GET请求或者POST请求的网页,爬取的时候都还算得心应手.不过最近遇到了一个有趣的网站,虽然爬取的难度不大,不过因为表单提交的存在,所以一开始还 ...

  10. java中dao层和service层的区别是什么

    dao层中已经有操作数据库的方法了,为什么还要service层去封装?有什么好处? tanghui12321 | 浏览 131990 次  我有更好的答案  推荐于2017-10-06 18:44:5 ...