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



我在linux下通过pmap看到流程图:

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

上面的三个段是代码、rodata和数据段,它们都与PAGESIZE(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程序的加载方式(以及通常从文件中进行的内存映射)是基于页面的。因此,所涉及的地址、文件中的偏移量和大小都必须是页面大小的倍数。

然而,程序加载器足够聪明,可以通过将它们四舍五入到页面边界来处理不完全在页面边界上开始或结束的部分,从而映射超出所需的内容。因此,会从文件中加载一些额外的数据来填充页面,但不应该访问这些数据,所以这应该无关紧要。

在您的示例中,代码段从偏移量0x0加载到地址0x08048000,大小为0x448。地址和偏移量是对齐的,所以只需要将大小四舍五入到一整页。数据段从偏移量0x448加载到0x08049448。它们没有对齐,但是兼容的——加载程序将两者向下舍入为一个页面倍数(0x08049000和0x000),并映射到该页面中。请注意,这最终是文件中与代码段相同的页面,因此该页面加载在两个不同的地址,一个只读,另一个读写非共享。因此,代码和数据在进程映像中的两个位置都是可见的,但这并不重要——代码在0x8048000..0x8048447处以r-x结尾,数据在0x8049448.0x804954b处以rw-结尾,这才是最重要的。

最新更新