ELF程序头虚拟地址和文件偏移量

我知道两者之间的关系:

虚拟地址mod页面alignment==文件偏移mod页面alignment

但有人能告诉我这两个数字在哪个方向计算吗?

根据上述关系计算文件偏移量的虚拟地址,反之亦然?

更新

这里有一些细节:当链接器写ELF文件头时,它设置程序头的虚拟地址和文件偏移量(段)

例如有readelf -l someELFfile的输出readelf -l someELFfile

 Elf file type is EXEC (Executable file) Entry point 0x8048094 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x000000 0x08048000 0x08048000 0x00154 0x00154 RE 0x1000 LOAD 0x000154 0x08049154 0x08049154 0x00004 0x00004 RW 0x1000 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x10 

我们可以看到2个LOAD段。

第一个LOAD的虚拟地址在0x8048154处结束,而第二个LOAD在0x8049154处开始。

在ELF文件中,第二个LOAD在文件偏移量为0x00154的第一个LOAD之后,但是当这个ELF被加载到内存中时,它将在第一个LOAD段结束后的0x1000字节处开始。

但为什么? 如果我们不得不考虑内存页面alignment,为什么第二个LOAD段从0x80489000开始? 为什么在第一个LOAD段结束后,它从0x1000个字节开始?

我知道第二个LOAD的虚拟地址满足以下关系:

虚拟地址mod页面alignment==文件偏移mod页面alignment

但是我不知道为什么这个关系必须得到满足。

Solutions Collecting From Web of "ELF程序头虚拟地址和文件偏移量"

为什么在第一个LOAD段结束后,它从0x1000个字节开始?

如果没有,它将不得不从0x08048154开始,但它不能:两个LOAD段为它们的映射指定了不同的标志 (第一个用PROT_READ|PROT_EXEC映射,第二个用PROT_READ|PROTO_WRITE 。作为页表的一部分)只能应用于整个页面,而不能应用于页面的一部分,因此具有不同保护的映射必须属于不同的页面。

虚拟地址mod页面对齐==文件偏移mod页面对齐
但是我不知道为什么这个关系必须得到满足。

LOAD段直接从文件中mmap 。 为你的例子执行的第二个LOAD段的实际映射看起来像这样(你可以在strace下运行你的程序, 看看它的确如此):

 mmap(0x08049000, 0x158, PROT_READ|PROT_WRITE, MAP_PRIVATE, $fd, 0) 

如果尝试使虚拟地址或偏移量非页面对齐,则mmap将失败并显示EINVAL 。 使文件数据在虚拟内存中出现在所需地址的唯一方法是使VirtAddrOffsetAlign ,这正是静态链接器所做的。

请注意,对于这样一个小的第一个LOAD段, 整个第一个段也出现在第二个映射的开始处(带有错误的保护)。 但是该程序不应该访问[0x08049000,0x08049154)范围内的任何内容。 通常情况下,第二个LOAD段中的实际数据开始之前会有一些“垃圾”(除非您真的很幸运,并且第一个LOAD段在页边界上结束)。

另请参阅mmap手册页 。