【问题标题】:lib specified by LD_PRELOAD can not be loaded无法加载 LD_PRELOAD 指定的库
【发布时间】:2016-02-20 14:39:26
【问题描述】:

我在使用 LD_PRELOAD 加载我的 so 时遇到了一些麻烦。

步骤如下:

  1. libtest.c:

    void fun()
    {
        return 
    }
    
  2. gcc -o libtest.so libtest.c -fPIC --shared

  3. 导出 LD_PRELOAD=pwd/libtest.so

  4. main.c

    extern void fun(); void main() { fun() }

  5. gcc -o 主 -L。 main.c -ltest

  6. 然后ldd main

    ldd main linux-vdso.so.1=>(0x00007ffff7ffd000) /home/shiyanlou/Code/libtest.so(0x00007ffff7df9000) libtest.so=>not found libc.so.6=>/lib/x86_64-linux-gnu/libc.so.6 (0x00007ffffa29000) /lib64/ld-linux-x86-64.so.2 (0x0000555555554000)

  7. 执行主./main 它促进: 加载共享库时出错:libtest.so。无法打开共享对象文件:没有这样的文件或目录。

不知道为什么导出LD_PRELOAD变量后提示找不到libtest.so。但是,我也尝试使用 LD_PRELOAD 指定不同的共享库(不是“libc.so”)来注入 malloc 函数,它可以工作! 为什么 LD_PRELOAD 只对链接时未使用的共享库有效???

【问题讨论】:

    标签: gcc shared-libraries shared ldd ld-preload


    【解决方案1】:

    您需要创建 2 个版本的 *.so。具有默认行为并通过“-ltest”加载和硬链接的一种。

    现在构建您的默认 libtest.so 并使用 nm -B 证明您希望拦截的符号是动态链接的。

    现在将 main.c 构建到 main.o 中,然后使用 nm 检查 main.o 以查看它对符号的外部未满足的链接要求。

    现在将./main 与 main.o 和 libtest.so 链接,然后运行它。 ./main 需要默认运行此副本,演示默认行为,并通过 ldd 命令显示正确 DSO 的正确路径。

    ...

    现在您开始创建 LD_PRELOAD 版本。

    你应该称之为libtest2.so。你不使用-ltest2

    关键是./main的构建者根本不知道libtest2.so,没有硬链接依赖。

    libtest2.so 具有替代行为,例如 make foo() 返回不同的字符串/数字),现在的目标是在运行时拦截此第二个版本,因此默认情况下(或根本不调用)第一个版本。通过使用 LD_PRELOAD 环境。

    LD_PRELOAD=./libtest2.so ./main

    ...

    祝你好运。

    【讨论】:

    • 您好,感谢您的帮助。我知道你的方法有效。但我只想知道为什么 LD_PRELOAD 不适用于我用来链接可执行程序的 lib?
    • 因为已经加载了? -ltest 建立硬 DSO 依赖关系,这不是 LD_PRELOAD 的意义所在。你误解了目的。也许如果您复制到另一个名称并加载它。 cp libtest.so libtest9.so 然后 LD_PRELOAD=./libtest9.so ./main 由于 libtest.so 已经加载,因此默认情况下 /home/shiyanlou/Code/libtest.so(0x00007ffff7df9000) 动态链接器只会将 DSO 加载到进程地址空间中一次。通过复制文件,它变成了一个不同的 DSO。
    • 感谢您的进一步解释。总而言之,我使用libtest.so 来进行硬DSO 依赖,并且LD_PRELOAD 也设置为/home/shiyanlou/Code/libtest.so。当我执行 ./main 时,由于硬 DSO 依赖而不是 LD_PRELOAD,它将加载 libtest.so。然后 LD_PRELOAD 将被忽略,因为已经加载了相同的 DSO。结果,libtest.so 实际上没有加载,./main 无法执行。我对吗?如果是这样,为什么 LD_PRELOAD 被命名为 LD_PRELOAD?它不应该在任何其他 DSO 之前加载吗??
    • 我不是来讨论它为什么被这样命名的。但简而言之,您要求加载相同的 DSO(作为硬依赖项和 LD_PRELOAD)并且它确实被加载了。那么问题是什么?重要的是 LD_PRELOAD 是否被加载?它是否设法拦截符号?既然答案是肯定的,那么看起来它是通过硬依赖加载的有什么关系,因为可执行文件的可观察行为是相同的。现在复制并重命名 DSO 并再次观察。
    • 我想我明白为什么它不能工作了。谢谢兄弟。
    【解决方案2】:

    我将DSO复制并重命名为libtest2.so并将LD_PRELOAD重置为重命名的DSO(带有绝对路径),它还提示找不到libtest.so。

    我认为之所以会这样提示是因为无法加载用于硬依赖的libtest.so。

    也就是说LD_PRELOAD已经加载完毕,但是硬依赖不能满足,所以也不能执行./main

    现在我可以得出结论,在执行./main时,必须满足硬依赖DSO,因为每个硬依赖DSO也必须被加载(虽然这个DSO要被完全替换!),否则会提示DSO不能被成立!

    感谢您的帮助@Darryl Miles

    【讨论】:

      猜你喜欢
      • 2019-11-19
      • 1970-01-01
      • 2022-01-24
      • 2013-07-17
      • 1970-01-01
      • 1970-01-01
      • 2010-11-13
      • 1970-01-01
      • 2018-12-04
      相关资源
      最近更新 更多