在specification of the ELF file format的第2-7页和第2-8页上,有两张图片给出了可执行程序程序标题的示例以及它们将如何加载到内存中:
规范说明:
虽然示例的文件偏移量和虚拟地址是 全等模数4 KB,用于文本和数据,最多四个文件页面 保存不纯的文本或数据(取决于页面大小和文件系统块 尺寸)。
- 第一个文本页面包含ELF标题,程序标题表和其他信息。
- 最后一个文本页面包含数据开头的副本。
- 第一个数据页面包含文本结尾的副本。
- 最后一个数据页面可能包含与正在运行的进程无关的文件信息。
我的问题是:
答案 0 :(得分:3)
页面是虚拟内存的最小可映射单元。如果您不熟悉基础知识,请参阅the wikipedia article on virtual memory。在常见系统上,页面大小为4096字节,或十六进制为0x1000。
A"文字页面"包含可执行代码; a"数据页"包含数据。这些必须映射到固定地址,以便代码中的偏移是正确的。在共享库或与位置无关的可执行文件中,不再指定确切的虚拟地址,但它们的相对位置是。在此示例中,第0个文本页面从0x8048000变为0x8048fff,这是在文本段开始之前(0x8048100)。第1个文本页面从0x8049000变为0x8049fff。最后一个文本页面从0x8073000变为0x8073fff,超出了文本段的末尾(0x8073eff)。
第一个数据页面位于0x8074000,但数据段在0x8074f00之前不会启动。此页面由文件的相同部分作为最后一个文本页面支持,但必须单独映射,因为它具有不同的权限(PROT_EXEC|PROT_READ
vs PROT_READ
)。这就是"数据开头的副本" /"文本末尾的副本"。
如果有两个以上的段,则加载完全相同。 "文本"和"数据"完全是任意的,重要的是为每个段指定的标志和地址。您可以使用readelf
或objdump
请注意,在现实世界中,文本和数据段之间通常存在未映射的空间("空洞"),但不一定在只读数据和读写数据之间或初始化与未初始化数据。
例如,运行cat /proc/self/maps
会给我:
ben@joyplim ~ % cat /proc/self/maps
00400000-0040c000 r-xp 00000000 fe:01 36176026 /bin/cat
0060b000-0060c000 r--p 0000b000 fe:01 36176026 /bin/cat
0060c000-0060d000 rw-p 0000c000 fe:01 36176026 /bin/cat
<plus the heap, stack, library, and special kernel stuff>