加载Mach-O可执行文件需要什么? [英] What is required for a Mach-O executable to load?

查看:141
本文介绍了加载Mach-O可执行文件需要什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am attempting to hand-write a Mach-O executable. There are three load commands:

  • LC_SEGMENT_64正在加载__PAGEZERO
  • LC_SEGMENT_64使用单个__text部分加载__TEXT
  • LC_UNIXTHREAD和适当设置的rip
  • LC_SEGMENT_64 loading __PAGEZERO
  • LC_SEGMENT_64 loading __TEXT, with a single __text section
  • LC_UNIXTHREAD with an appropriately-set rip

每个命令都匹配mach/loader.h中的结构和相关的头文件. otool -l按预期列出信息,并且不报告任何错误.从所有人的角度来看,这是一个格式正确的目标文件,而OS X 10.10.5终止了该任务(SIGKILL).

Every command matches the structs in mach/loader.h and related headers. otool -l lists the information as expected and doesn't report any errors. By all accounts it is a well-formed object file — yet OS X 10.10.5 terminates the task (SIGKILL).

在OS X加载之前会检查Mach-O可执行文件的哪些功能?此信息位于何处?这些功能会更改版本到版本吗? (经常被引用的"OS X ABI Mach-O参考"显然丢失了.)

What features of a Mach-O executable are checked before OS X will load it? Where is this information located? Do these features change version-to-version? (The often-cited "OS X ABI Mach-O Reference" is apparently missing.)

这里是二进制文件的已部分注释的十六进制转储.

otool健全性检查(摘录):

otool sanity check (excerpted):

$ 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
…

推荐答案

自优胜美地10.10.5版本开始,可执行文件的长度必须至少为 4096 个字节(PAGE_SIZE),否则为立即被杀死. @Siguza在XNU kernel exec_activate_image函数 https://github.com/apple/darwin-xnu/blob/0a798f6738bc1db01281fc08ae024145e84df927/bsd/kern/kern_exec.c#L1456

Since 10.10.5 Yosemite, the executable file must be at least 4096 bytes long ( PAGE_SIZE ), or it will be killed immediately. The relevant code found by @Siguza in the XNU kernel exec_activate_image function https://github.com/apple/darwin-xnu/blob/0a798f6738bc1db01281fc08ae024145e84df927/bsd/kern/kern_exec.c#L1456

假设您只想使用系统调用来执行64位macOS可执行文件,则需要:

Assuming you want a 64-bit macOS executable using only system calls, you need:

  • Mach-O 64位标头
  • LC_SEGMENT_64 __PAGEZERO(大小非零,名称可以是任意值)
  • LC_SEGMENT_64 __TEXT(名称可以是任何数字;必须可读且可执行;各节是可选的)
  • LC_UNIXTHREAD
  • Mach-O 64-bit Header
  • LC_SEGMENT_64 __PAGEZERO (with nonzero size, name can be anything)
  • LC_SEGMENT_64 __TEXT (name can be anything; must be readable and executable; sections are optional)
  • LC_UNIXTHREAD

这是我的示例.

但是如果没有dyld,您将无法做很多事情,因此,如果要使用它,最小的设置是:

You can't do much without dyld though, so if you want to use it the minimal set is:

  • 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要加载,以使LC_MAIN正常工作)
  • Mach-O 64-bit Header
  • LC_SEGMENT_64 __PAGEZERO (with nonzero size)
  • LC_SEGMENT_64 __TEXT (name can be anything; must be readable and executable; sections are optional)
  • LC_SEGMENT_64 __LINKEDIT (must be writable because dyld requires a writable segment, in a ld linked binary the writable segment typically would be __DATA)
  • LC_DYLD_INFO_ONLY (specifies where the actual dyld load commands physically are in the executable, typically they will be found __LINKEDIT but there's no limitation on this) or interestingly LC_SYMTAB instead, which would make the actual dyld impossible to use without LC_DYLD_INFO_ONLY.
  • LC_DYSYMTAB (this can be empty)
  • LC_LOAD_DYLINKER
  • LC_MAIN or LC_UNIXTHREAD
  • LC_LOAD_DYLIB (at least one actual dylib to load for LC_MAIN to work)

在现代可执行文件(自10.7 Mountain Lion起)中,LC_UNIXTHREADLC_MAIN取代,这需要dyld-但自10.12 Sierra以来,任何可执行文件都支持LC_UNIXTHREAD(并且应该在将来) MacOS版本,因为它由dyld可执行文件本身用来实际启动).

In modern executables (since 10.7 Mountain Lion), LC_UNIXTHREAD is replaced by LC_MAIN, which requires dyld — but LC_UNIXTHREAD is still supported for any executable as of 10.12 Sierra (and it should be in future MacOS versions, because it's utilised by dyld executable itself to actually start).

要使dyld工作,额外的步骤取决于绑定的类型:
bind at load是最省力的方法,其中LC_DYLD_INFO_ONLY指向有效的dyld load commands指向可写段将解决问题.
lazy binding另外需要__TEXT中额外的平台特定代码,该代码利用在加载时间dyld_stub_binder绑定到dyld加载函数的延迟加载地址. 还有dyld binding的其他类型,我在这里不介绍.

For dyld to work the extra steps depend on type of binding:
bind at load is the least effort approach , where LC_DYLD_INFO_ONLY pointing to valid dyld load commands pointing to writable segment will do the trick.
lazy binding additionally requires extra platform specific code in __TEXT which utilises binded at load time dyld_stub_binder to lazy load address of a dyld loaded function.
There are other types of dyld binding which I don't cover here.

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

Further details can be found here: https://github.com/opensource-apple/dyld/blob/master/src/ImageLoaderMachO.cpp

这篇关于加载Mach-O可执行文件需要什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆