从 10.10.5 Yosemite 开始,可执行文件的长度必须至少为4096字节(PAGE_SIZE
),否则会立即被杀死。@Siguza 在XNU kernel
exec_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
这是我的例子。
与 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_MAIN
或者LC_UNIXTHREAD
LC_LOAD_DYLIB
(至少要加载一个实际的 dylib,它最终取决于 libSystem 或 libSystem 本身LC_MAIN
才能工作)
LC_UNIXTHREAD
和LC_MAIN
在现代可执行文件(自 10.7 Mountain Lion 起)中,LC_UNIXTHREAD
被替换为LC_MAIN
, 这需要dyld
- 但LC_UNIXTHREAD
自 10.12 Sierra 起仍然支持任何可执行文件(它应该在未来的 MacOS 版本中,因为它被dyld
可执行文件本身用于实际启动)。
为了dyld
工作,额外的步骤取决于绑定的类型:
bind at load
是最省力的方法,其中LC_DYLD_INFO_ONLY
指向有效dyld load commands
指向可写段就可以了。
lazy binding
另外需要额外的平台特定代码,__TEXT
其中利用在加载时绑定到加载函数dyld_stub_binder
的延迟加载地址。
还有其他类型我在这里不介绍。dyld
dyld binding
更多细节可以在这里找到:https ://github.com/opensource-apple/dyld/blob/master/src/ImageLoaderMachO.cpp