前言

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. bzoj1584 9.20考试 cleaning up 打扫卫生

    1584: [Usaco2009 Mar]Cleaning Up 打扫卫生 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 549  Solved: 38 ...

  2. Linux关闭进程。

    一.shell命令根据端口后关闭指定进程. $(netstat -nlp | | awk '{print $7}' | awk -F"/" '{ print $1 }') nets ...

  3. vs2005 打不开resoure view?

    原来是破解版 vc助手惹的祸. 解决方法:卸载vc助手或者换一个注册的vc助手

  4. [PTA] 1001. 害死人不偿命的(3n+1)猜想 (Basic)

    import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Sc ...

  5. hdu6396 Swordsman(贪心)

    Swordsman 题目传送门 解题思路 先将每种属性排序,因为打倒怪兽会使属性增强,所以肯定是能打就打,用cnt[i]记录怪兽i已经被超过的属性数量,如果被超过的属性数为k了,则打倒此怪兽,将获得的 ...

  6. ASP.NET登录验证码解决方案

    目录 #验证码效果图 #代码 0.html代码 1.Handler中调用验证码生成类 2.验证码图片绘制生成类 3.高斯模糊算法类 #注意 #参考 在web项目中,为了防止登录被暴力破解,需要在登录的 ...

  7. c++语言常用转义序列符号

    \a      响铃 \n      换行符 \r       回车符 t        水平制表符(Tab键) \b      退格符(BackSpace键) \\       反斜线 \'     ...

  8. java练习---5

    //程序员:罗元昊  2017.9.17 package demo;import java.util.Scanner;public class Ly { public static void main ...

  9. windows无法执行 git reset head^版本回退操作的正确打开方式

    ^是cmd.exe的escape字符,属于特殊字符,命令里要用到文字 ^ 时必须用双引号把它夹起来,因此只要如下就可以正确执行: git reset head"^"或者git re ...

  10. Ubuntu下Mongo的安装和笔记

    在linux下的安装 打开https://www.mongodb.com/download-center#community选择linux然后选择自己的Version复制DOWNLOAD旁边的链接 打 ...