有没有办法将共享对象文件 (.so) 添加到 ld.so.cache?

问题描述

我编写了一个简单的 C 程序,它对共享对象执行 dlopen:

 handle = dlopen ("./MySharedobject.so",RTLD_LAZY);
        if (!handle) {
            fputs (dlerror(),stderr);
            exit(1);
        }
sleep(20)
dlclose(..)

现在我将我的程序编译为可执行文件,并在同一台机器上同时运行多个可执行文件实例。我认为将在所有运行中返回的句柄将是相同的。但是,似乎 ld.so.cache 中加载的共享对象是唯一可以返回相同句柄的对象。

我的目标不是使用 dlopen 两次加载相同的代码。有没有人知道如何实现这一目标?

解决方法

我认为在所有运行中返回的句柄都是一样的。

它不会是,但这并不意味着你似乎认为它意味着什么。

即使句柄不同,共享库仍然有效并且仍然在多个进程之间共享。换句话说,这里没有问题需要您解决。

但是,似乎 ld.so.cache 中加载的共享对象是唯一可以返回相同句柄的对象。

这也是错误的:绝对不能保证 ld.so.cache 中列出的对象将在不同进程中使用相同的句柄。

更新:

我假设句柄是指向共享库加载内容的指针。

这是不正确的:在 GLIBC 下,句柄是指向描述特定库的堆分配块的指针。它不指向库本身。

如果我 dlsym 一个符号,理想情况下它应该返回符号定义加载位置的开始。

正确。

在这种情况下,我得到不同的 dlsym 值。这是否意味着符号被加载了两次?

不,它没有。通过虚拟内存的魔力,RAM 的相同物理页可以出现在不同进程中的不同地址。当 ASLR 开启时,这对于共享库来说非常常见。

例如,这里是同一个 /bin/date 二进制文件的两次执行:

$ ldd /bin/date | grep libc.so.6
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f60ff32f000)
$ ldd /bin/date | grep libc.so.6
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffa38e2a000)

请注意,libc.so.6 已加载到不同的地址(同时仍与系统上当前正在运行的所有其他进程共享)。

也很容易造成相同的物理 RAM 页面出现在单个进程内的不同地址的情况:只需在同一个文件描述符上调用 mmap(fd,...,0) 两次即可。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...