ELF头部和进程虚拟内存中的地址不同

6

我通过在Linux下使用pmap查看进程映像:

08048000       0       4       0 r-x--  [my program]

08049000       0       4       4 rw---  [my program]

上述三个部分是代码、只读数据和可读写数据段,它们都对齐到页面大小(4K),但当我输入命令objdump -h时,ELF头显示如下:

read-only code segment
Load off 0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12
     filesz 0x00000448 memsz 0x00000448 flags r-x

read/write data segment
Load off 0x00000448 vaddr 0x08049448 paddr 0x08049448 align 2**12
     filesz 0x000000e8 memsz 0x00000104 flag rw-

据ELF头文件所述,代码段和数据段分别从虚拟地址0x08048000、0x049448开始寻址,这与内存中的进程映像不同。我知道代码/数据段应该被分配到不同的PAGESIZE中,以便为它们提供不同的保护权限。但是,如果实际的虚拟地址与ELF二进制文件不同,程序如何执行?
1个回答

5
ELF程序加载(以及从文件中的内存映射)是按页为单位的。因此,所涉及的地址、文件中的偏移量和大小都必须是页大小的倍数。
然而,程序加载器足够智能,可以处理不以页边界精确开始或结束的部分,将它们舍入到页边界,映射多余的区域。因此,一些额外的数据将被加载到页面中,但不应访问,因此这并不重要。
在您的示例中,代码段从偏移量0x0处以大小0x448的大小加载到地址0x08048000。地址和偏移量对齐,所以只需要将大小舍入到完整页。数据段从偏移量0x448处加载到0x08049448。它们不对齐,但是兼容--加载器将两者都舍入到页面倍数(0x08049000和0x000),并映射到该页面中。请注意,这最终是来自文件的相同页面作为代码段,因此该页面在两个不同的地址上加载,一个是只读的,另一个是可读写非共享的。因此,代码和数据最终在进程镜像中以两个位置可见,但这并不重要--代码最终位于0x8048000..0x8048447处的r-x,数据最终位于0x8049448..0x804954b处的rw-,这是所有要紧的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接