ELF程序头虚拟地址和文件偏移量
ELF program header virtual address and file offset
我知道两者的关系:
virtual address mod page alignment == file offset mod page alignment
但是有人能告诉我这两个数字是从哪个方向计算出来的吗?
虚拟地址是根据上面的关系从文件偏移量计算出来的,还是反之?
更新
这里有一些更详细的信息:当链接器写入ELF文件头时,它设置了程序头的虚拟地址和文件偏移量。(段)
例如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 R E 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 紧跟在第一个 LOAD 之后,文件偏移量为 0x00154,但是当此 ELF 加载到内存中时,它从第一个 LOAD 段结束后的 0x1000 字节开始。
但是,为什么?如果我们必须考虑内存页面对齐,为什么第二个 LOAD 段不从 0x80489000 开始?为什么它从第一个加载段结束后的 0x1000 字节开始?
我知道第二个LOAD的虚拟地址满足关系:
virtual address mod page alignment == file offset mod page alignment
但是不知道为什么一定要满足这个关系
Why does it start at 0x1000 bytes AFTER THE END of the first LOAD segment?
如果没有,它必须从 0x08048154
开始,但它不能:两个 LOAD
段有不同的 flags为其映射指定(第一个映射为 PROT_READ|PROT_EXEC
,第二个映射为 PROT_READ|PROTO_WRITE
。保护(作为页面 table 的一部分)只能应用于 整个 页,而不是页的一部分。因此,具有不同保护的映射必须属于不同的页。
virtual address mod page alignment == file offset mod page alignment
But I don't know why this relationship must be satisfied.
LOAD
段直接从文件中mmap
编辑。为您的示例执行的第二个 LOAD
段的实际映射看起来像这样(您可以 运行 您的程序在 strace
和 下看到 确实如此):
mmap(0x08049000, 0x158, PROT_READ|PROT_WRITE, MAP_PRIVATE, $fd, 0)
如果您尝试使虚拟地址或偏移量非页对齐,mmap
将失败并返回 EINVAL
。使文件数据出现在虚拟内存中所需地址的唯一方法是使 VirtAddr
与 Offset
模 Align
一致,而这正是静态链接器所做的。
请注意,对于如此小的第一个 LOAD
片段,整个 第一个片段也出现在 第二个 的开头] 映射(带有错误的保护)。但是该程序不应访问 [0x08049000,0x08049154)
范围内的任何内容。一般来说,在第二个 LOAD
段 实际数据 开始之前几乎总是有一些 "junk" (除非你真的很幸运并且第一个 LOAD
段结束于页面边界)。
另见 mmap man page。
virtual address mod page alignment == file offset mod page alignment
But can someone tell me in which direction are these two numbers computed?
我相信虚拟地址是故意按照文件偏移量这样设置的。文件本身应该是紧凑的,因此可以节省磁盘 space,因此所有段都紧挨着彼此存储,它们的边界记录在 ELF header.
virtual address mod page alignment == file offset mod page alignment
But I don't know why this relationship must be satisfied.
需要不需要,这里的第二段可以毫无问题的映射到0x08049000。只要将具有不同标志的段映射到不同的虚拟页面,就可以了。但是 OS 必须为映射分配另一个物理页面(通常为 4 KB),并在加载生成的 ELF 可执行文件时将文件偏移量 0x154 处的 4 字节复制到页面的开头,这有点浪费.
但是,如果满足关系,OS 可以只分配一个物理页面并将文件的整个 0x158(0x154 + 0x4)字节复制到该页面,并将物理页面映射到到具有不同标志的 0x08048000 和 0x08049000。这节省了物理内存,并使像 demand-paging 这样的虚拟内存技术更容易应用。
我知道两者的关系:
virtual address mod page alignment == file offset mod page alignment
但是有人能告诉我这两个数字是从哪个方向计算出来的吗?
虚拟地址是根据上面的关系从文件偏移量计算出来的,还是反之?
更新
这里有一些更详细的信息:当链接器写入ELF文件头时,它设置了程序头的虚拟地址和文件偏移量。(段)
例如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 R E 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 紧跟在第一个 LOAD 之后,文件偏移量为 0x00154,但是当此 ELF 加载到内存中时,它从第一个 LOAD 段结束后的 0x1000 字节开始。
但是,为什么?如果我们必须考虑内存页面对齐,为什么第二个 LOAD 段不从 0x80489000 开始?为什么它从第一个加载段结束后的 0x1000 字节开始?
我知道第二个LOAD的虚拟地址满足关系:
virtual address mod page alignment == file offset mod page alignment
但是不知道为什么一定要满足这个关系
Why does it start at 0x1000 bytes AFTER THE END of the first LOAD segment?
如果没有,它必须从 0x08048154
开始,但它不能:两个 LOAD
段有不同的 flags为其映射指定(第一个映射为 PROT_READ|PROT_EXEC
,第二个映射为 PROT_READ|PROTO_WRITE
。保护(作为页面 table 的一部分)只能应用于 整个 页,而不是页的一部分。因此,具有不同保护的映射必须属于不同的页。
virtual address mod page alignment == file offset mod page alignment
But I don't know why this relationship must be satisfied.
LOAD
段直接从文件中mmap
编辑。为您的示例执行的第二个 LOAD
段的实际映射看起来像这样(您可以 运行 您的程序在 strace
和 下看到 确实如此):
mmap(0x08049000, 0x158, PROT_READ|PROT_WRITE, MAP_PRIVATE, $fd, 0)
如果您尝试使虚拟地址或偏移量非页对齐,mmap
将失败并返回 EINVAL
。使文件数据出现在虚拟内存中所需地址的唯一方法是使 VirtAddr
与 Offset
模 Align
一致,而这正是静态链接器所做的。
请注意,对于如此小的第一个 LOAD
片段,整个 第一个片段也出现在 第二个 的开头] 映射(带有错误的保护)。但是该程序不应访问 [0x08049000,0x08049154)
范围内的任何内容。一般来说,在第二个 LOAD
段 实际数据 开始之前几乎总是有一些 "junk" (除非你真的很幸运并且第一个 LOAD
段结束于页面边界)。
另见 mmap man page。
virtual address mod page alignment == file offset mod page alignment
But can someone tell me in which direction are these two numbers computed?
我相信虚拟地址是故意按照文件偏移量这样设置的。文件本身应该是紧凑的,因此可以节省磁盘 space,因此所有段都紧挨着彼此存储,它们的边界记录在 ELF header.
virtual address mod page alignment == file offset mod page alignment
But I don't know why this relationship must be satisfied.
需要不需要,这里的第二段可以毫无问题的映射到0x08049000。只要将具有不同标志的段映射到不同的虚拟页面,就可以了。但是 OS 必须为映射分配另一个物理页面(通常为 4 KB),并在加载生成的 ELF 可执行文件时将文件偏移量 0x154 处的 4 字节复制到页面的开头,这有点浪费.
但是,如果满足关系,OS 可以只分配一个物理页面并将文件的整个 0x158(0x154 + 0x4)字节复制到该页面,并将物理页面映射到到具有不同标志的 0x08048000 和 0x08049000。这节省了物理内存,并使像 demand-paging 这样的虚拟内存技术更容易应用。