假设我有一个源文件dll.c
,它使用dlopen
和函数来加载在运行时dlsym
调用的共享库。F.so
dll.c
引用some_function()
,并F.so
具有 的定义some_function()
。
假设下图是prog
通过以下方式获得的可执行对象
linux> gcc -rdynamic -o prog dll.c -ldl
so部分包含程序加载并开始调用时需要解析.text
的引用some_function()
F.so
some_function()
我的问题是:
在我看来, RAM中的
.text
部分(some_function()
属于哪里)(可执行文件被复制到内存中)需要由动态链接器修改,以便some_function()
可以解析 的引用,我的理解正确吗?如果动态链接器需要修改
.text
RAM中的部分,它是如何做到的呢?根据我的理解,.text
section是RAM中的只读段,如果只读段被称为只读,那么如何修改它呢?
答案1
您的图表中缺少 ELF 的两个功能,它们用于动态链接:全局偏移表 (GOT) 和过程链接表 (PLT)。 GOT 是用于多种目的的偏移量表,PLT 是用于间接跳转的过程存根表。 GOT 通常是可读写的; PLT 可以是读写的,也可以是只读的(然后由 GOT 条目或单独的 PLT 特定 GOT 支持)。
这允许动态链接器更新符号地址而不触及只读数据。
一些较旧的二进制文件需要修改只读段中的重定位数据;这对于动态链接器来说不是问题,但它确实意味着内存中的相应内存区域不能再在进程之间共享。
看如何编写共享库了解详情。
答案2
A.1
.text
根据CPU的不同,调用部分的代码some_function()
将是某种间接调用。它将在运行时计算地址,可能会缓存结果以提高效率。这使得.text
可以保持不变,因此可以共享。代码通常会稍微大一些并且速度慢一些。
A2
这个假设是错误的,所以这个问题不会出现。然而,没有什么可以阻止内核复制内存页面并为其赋予不同的读/写/执行属性并将新页面映射到同一地址。例如,这可以通过ptrace
系统调用来完成,并由调试器用来设置软件断点。