加载Mach-O可执行文件需要什么? [英] What is required for a Mach-O executable to load?
问题描述
我正在尝试手写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
sectionLC_UNIXTHREAD
with an appropriately-setrip
每个命令都匹配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_MAIN
或LC_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 ald
linked binary the writable segment typically would be__DATA
)LC_DYLD_INFO_ONLY
(specifies where the actualdyld
load commands physically are in the executable, typically they will be found__LINKEDIT
but there's no limitation on this) or interestinglyLC_SYMTAB
instead, which would make the actualdyld
impossible to use withoutLC_DYLD_INFO_ONLY
.LC_DYSYMTAB
(this can be empty)LC_LOAD_DYLINKER
LC_MAIN
orLC_UNIXTHREAD
LC_LOAD_DYLIB
(at least one actual dylib to load forLC_MAIN
to work)
在现代可执行文件(自10.7 Mountain Lion起)中,LC_UNIXTHREAD
被LC_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屋!