我编译了一个简单的程序,如
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
字段设置为零?
Apple关于此字段的文档说明了
文件从fileoff开始映射到内存中段的开头vmaddr。
这最初让我相信这个字段与filesize
一起表明加载程序是这样的:“将文件的内容从fileoff
转移到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
在这种情况下,load命令确实有一个fileoff
字段的值,该字段与第一部分__text
的字段相同。
答案 0 :(得分:1)
otool很难实现,但答案很简单 - 请注意:
TextBlock
__TEXT段从文件的开头(或切片,如果胖(“通用”))映射。也就是说,使用Mach-O标头。这实际上是一个特性,因为Mach-O然后被dyld(你的友好加载器)解析为其他加载命令(特别是库)。另一个问题是__TEXT .__文本通常位于同一页面中,因此您无论如何都必须映射整个页面。