【问题标题】:What is required for a Mach-O executable to load?加载 Mach-O 可执行文件需要什么?
【发布时间】:2016-10-04 23:09:33
【问题描述】:

我正在尝试手写一个 Mach-O 可执行文件。加载命令共有三个:

  • LC_SEGMENT_64加载中__PAGEZERO
  • LC_SEGMENT_64 加载 __TEXT,带有单个 __text 部分
  • LC_UNIXTHREAD 带有适当设置的 rip

每个命令都匹配mach/loader.h 和相关标头中的结构。 otool -l 按预期列出信息并且不报告任何错误。众所周知,它是一个格式良好的目标文件——但 OS X 10.10.5 终止了任务 (SIGKILL)。

在 OS X 加载之前检查 Mach-O 可执行文件的哪些功能?此信息位于何处?这些功能是否会因版本而异? (经常被引用的“OS X ABI Mach-O Reference”显然不见了。)


这是二进制文件的partially annotated hexdump

otool 健全性检查(摘录):

$ otool -l machtest
machtest:
Load command 0
      cmd LC_SEGMENT_64
  cmdsize 72
  segname __PAGEZERO
…
Load command 1
      cmd LC_SEGMENT_64
  cmdsize 152
  segname __TEXT
…
Section
  sectname __text
   segname __TEXT
…
Load command 2
        cmd LC_UNIXTHREAD
…

【问题讨论】:

标签: mach-o xnu


【解决方案1】:

自 10.10.5 Yosemite 起,可执行文件的长度必须至少为 4096 字节(PAGE_SIZE),否则会立即被杀死。 @Siguza在XNU kernelexec_activate_image函数https://github.com/apple/darwin-xnu/blob/0a798f6738bc1db01281fc08ae024145e84df927/bsd/kern/kern_exec.c#L1456找到的相关代码

没有 dyld

假设您想要一个仅使用系统调用的 64 位 macOS 可执行文件,您需要:

  • Mach-O 64 位标头
  • LC_SEGMENT_64__PAGEZERO(大小不为零,名称可以是任何值)
  • LC_SEGMENT_64__TEXT(名称可以是任何东西;必须是可读和可执行的;部分是可选的)
  • LC_UNIXTHREAD

这里是 my example 用于这种情况。

使用 dyld

不过,如果没有 dyld,您将无法做很多事情,所以如果您想使用它,最小集合是:

  • Mach-O 64 位标头
  • LC_SEGMENT_64__PAGEZERO(非零大小)
  • LC_SEGMENT_64__TEXT(名称可以是任何东西;必须是可读和可执行的;部分是可选的)
  • LC_SEGMENT_64 __LINKEDIT(必须是可写的,因为 dyld 需要可写段,在 ld 链接的二进制文件中,可写段通常为 __DATA
  • LC_DYLD_INFO_ONLY(指定实际的dyld加载命令在可执行文件中的物理位置,通常它们会在__LINKEDIT找到,但对此没有限制)或者有趣的是LC_SYMTAB,这将使实际的dyld不可能不使用LC_DYLD_INFO_ONLY
  • LC_DYSYMTAB(可以为空)
  • LC_LOAD_DYLINKER
  • LC_MAINLC_UNIXTHREAD
  • LC_LOAD_DYLIB(至少要加载一个实际的 dylib,最终依赖于 libSystem 或 libSystem 本身才能使 LC_MAIN 工作)

LC_UNIXTHREADLC_MAIN

在现代可执行文件中(自 10.7 Mountain Lion 起),LC_UNIXTHREADLC_MAIN 取代,这需要 dyld — 但自 10.12 Sierra 起,任何可执行文件仍支持 LC_UNIXTHREAD(将来应该会支持) MacOS 版本,因为它被 dyld 可执行文件本身用来实际启动)。

要让dyld 工作,额外的步骤取决于绑定类型:
bind at load 是最省力的方法,其中LC_DYLD_INFO_ONLY 指向有效的dyld load commands 指向可写段即可。lazy binding__TEXT 中还需要额外的平台特定代码,它利用在加载时绑定dyld_stub_binderdyld 加载函数的延迟加载地址。
还有其他类型的dyld binding,这里就不一一介绍了。

更多详情可以在这里找到:https://github.com/opensource-apple/dyld/blob/master/src/ImageLoaderMachO.cpp

【讨论】:

    【解决方案2】:

    不是 100% 肯定,但你需要 LC_LOAD_DYLINKER 加载命令在你的可执行文件之前运行 dyld,我很确定 OSX 不会自动映射到 /usr/lib/dyld 如果加载命令不可用.

    您需要/usr/lib/libSystem.B.dylibLC_LOAD_DYLIB 加载命令吗?我不这么认为,但这两者都很好,而且成本也不高。

    【讨论】:

    • 只有当可执行文件动态链接到系统dylds或第三方dylds时才需要这个加载命令。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-05
    • 1970-01-01
    相关资源
    最近更新 更多