【问题标题】:Function of shared library is loaded at different physical addresses for different processes共享库的功能被加载到不同的进程不同的物理地址
【发布时间】:2016-10-09 11:23:39
【问题描述】:

我在两个程序中得到了 libc.so 中函数“printf”的物理地址,两个物理地址不同。而且我读取了两个不同的物理地址,内容几乎是一样的。这意味着函数“printf”在内存中有两个副本?

详情:

  1. 我的操作系统是 32 位 linux。

  2. 通过读取“/proc/self/pagemap”计算物理地址。

  3. 物理地址读取通过fmem模块实现,源码在git@github.com:NateBrune/fmem.git

【问题讨论】:

  • “内容几乎一样”是什么意思?如果这两个printf() 的实现不同,那么它们当然必须在不同的地方,也许这两个程序使用不同版本的libc?
  • "物理地址"你确定吗?每个进程都使用自己的虚拟地址空间。
  • 这就是现在大多数动态链接器的工作方式:它为使用该库的每个进程一次又一次地加载共享库。理想情况下,每个进程的内存访问都与任何其他进程隔离,以便它们相互保护。这适用于代码和数据,例如您不希望一个有缺陷的进程破坏或破坏另一个进程的代码。因此,为每个进程多次加载库比一次加载动态库并为多个进程多次映射内存位置更容易、更安全。

标签: c linux shared-libraries elf


【解决方案1】:

我在两个程序中得到libc.so中函数“printf”的物理地址,两个物理地址不同。

你可能做错了(但很难猜到:你没有提供任何细节)。

特别注意以下程序:

#include <stdio.h>

int main()
{
  printf("&printf: %p\n", &printf);
  return 0;
}

libc.so.6 中打印printf 的实际地址,这可以通过GDB 观察到:

(gdb) start
Temporary breakpoint 1 at 0x8048426: file pagemap.c, line 5.
Starting program: /tmp/pagemap

Temporary breakpoint 1, main () at pagemap.c:5
5     printf("&printf: %p\n", &printf);
(gdb) n
&printf: 0x80482f0
6     return 0;

(gdb) info symbol 0x80482f0
printf@plt in section .plt of /tmp/pagemap

(gdb) p &printf
$1 = (<text variable, no debug info> *) 0xf7e5add0 <printf>

(gdb) info sym 0xf7e5add0
printf in section .text of /lib32/libc.so.6

注意printf @0x80482f0 在主可执行文件中,并且应该被共享(除了在同一可执行文件的多个实例之间同时运行),并且不是 printf 的代码实际所在的位置。

printf @0xf7e5add0libc.so.6 中,而printf 的代码实际所在的位置。 那个页面应该被所有使用libc.so.6的进程共享。

附:要在libc.so.6 中获取printf实际地址,可以改用这个程序:

#include <stdio.h>
#include <dlfcn.h>

int main()
{
  printf("&printf: %p\n", &printf);
  printf("&printf: %p\n", dlsym(RTLD_NEXT, "printf"));
  return 0;
}

gcc -g pagemap.c -o pagemap -m32 -ldl -D_GNU_SOURCE

(gdb) run
Starting program: /tmp/pagemap
&printf: 0x80483c0
&printf: 0xf7e55dd0

(gdb) info sym 0xf7e55dd0
printf in section .text of /lib32/libc.so.6

【讨论】:

  • 我有一个问题.. 我认为 plt 中的符号名称是printf@plt。但是为什么dlsym(RTLD_DEFAULT, "printf") 会找到 plt 条目呢?为什么普通的非 plt'ed 符号字符串没有像 gdb 那样找到真实的东西?
  • @litb "我认为 plt 中的符号名称是 printf@plt" -- 不是。如您在readelf -Ws 输出中所见,它是printf@plt 是 GDB 制造的一个名称,以便更清楚地了解该符号是什么。
  • @EmployedRussian,你是对的,我得到的'printf'的虚拟地址实际上是'printf@plt'的,'printf'的真实虚拟地址存储在'printf'之后的GOT中是绑定的。最后在我的实验中,我在两个程序中得到了'printf'的虚拟地址0xb7581590和0xb7635590,它们的物理地址都是0x7bc6b590。
  • @EmployedRussian 我的测试输出不包含printf,而是printf@GLIBC_2.2.5。但仍然使用RTLD_DEFAULT 搜索printf 得到的结果与使用RTLD_NEXT 不同。这是否意味着动态链接器将在运行时将printf 与符号printf@GLIBC_2.2.5 匹配?这些是版本后缀,我不确定它们在运行时如何匹配非后缀符号。知道在哪里查找吗?
  • 啊,我们有dlvsym需要版本匹配,dlsym即使不同版本也能找到符号。
猜你喜欢
  • 2011-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-20
相关资源
最近更新 更多