MachO文件格式 - LC_SEGMENT_64加载命令

时间:2016-03-01 17:04:47

标签: macos mach-o otool

我编译了一个简单的程序,如

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的字段相同。

1 个答案:

答案 0 :(得分:1)

otool很难实现,但答案很简单 - 请注意:

TextBlock

__TEXT段从文件的开头(或切片,如果胖(“通用”))映射。也就是说,使用Mach-O标头。这实际上是一个特性,因为Mach-O然后被dyld(你的友好加载器)解析为其他加载命令(特别是库)。另一个问题是__TEXT .__文本通常位于同一页面中,因此您无论如何都必须映射整个页面。