我编译了一个简单的程序,例如
int main()
{
return 0;
}
使用 Clang 进入可执行文件并要求otool
报告编译器生成的加载命令。我感兴趣的是LC_SEGMENT_64
,特别是描述__TEXT
文件中段的那个。我得到的描述是这样的:
$ otool -lV foo
foo:
Load command 0
cmd LC_SEGMENT_64
cmdsize 72
segname __PAGEZERO
vmaddr 0x0000000000000000
vmsize 0x0000000100000000
fileoff 0
filesize 0
maxprot ---
initprot ---
nsects 0
flags (none)
Load command 1
cmd LC_SEGMENT_64
cmdsize 312
segname __TEXT
vmaddr 0x0000000100000000
vmsize 0x0000000000001000
fileoff 0
filesize 4096
maxprot rwx
initprot r-x
nsects 3
flags (none)
Section
sectname __text
segname __TEXT
addr 0x0000000100000f90
size 0x000000000000000f
offset 3984
align 2^4 (16)
reloff 0
nreloc 0
type S_REGULAR
attributes PURE_INSTRUCTIONS SOME_INSTRUCTIONS
reserved1 0
reserved2 0
我的问题是:为什么fileoff
第二个加载命令中的字段设置为零?
苹果在该领域的文档指出
该文件从 fileoff 开始映射到内存中段的开头 vmaddr。
最初,这使我相信该字段与 一起filesize
指示加载器,如下所示:“将文件的内容从fileoff
to 获取fileoff + filesize
,这是您将要求处理器运行的指令序列”。但是,如果这个值是零,我的假设当然不成立。
我认为,由于该段至少有一个部分,加载程序将使用该部分描述中相应偏移量的值来定位要运行的代码,因此并不完全需要这样的值 --- 我们可以看到,实际上,该段中的第一部分具有该offset
字段的值(在本例中为 3984,我使用它进行了验证,otool -s __TEXT __text -j foo
并且实际上是指该部分在文件中的偏移量)。
但是,如果我对从同一个源文件(即类型为MH_OBJECT
而不是 的文件MH_EXECUTE
)生成的目标文件执行相同的操作,我得到的结果是:
$ otool -lV foo.o
foo.o:
Load command 0
cmd LC_SEGMENT_64
cmdsize 312
segname
vmaddr 0x0000000000000000
vmsize 0x0000000000000070
fileoff 464
filesize 112
maxprot rwx
initprot rwx
nsects 3
flags (none)
Section
sectname __text
segname __TEXT
addr 0x0000000000000000
size 0x000000000000000f
offset 464
align 2^4 (16)
reloff 0
nreloc 0
type S_REGULAR
attributes PURE_INSTRUCTIONS SOME_INSTRUCTIONS
reserved1 0
reserved2 0
在这种情况下,加载命令的字段确实有一个值fileoff
,这与其第一部分的值相同__text
。