加载 Mach-O 可执行文件需要什么?
What is required for a Mach-O executable to load?
我正在尝试 hand-write 一个 Mach-O 可执行文件。一共有三个加载命令:
LC_SEGMENT_64
加载中 __PAGEZERO
LC_SEGMENT_64
加载 __TEXT
,带有单个 __text
部分
LC_UNIXTHREAD
与 appropriately-set rip
每个命令都匹配 mach/loader.h
和相关 headers 中的结构。 otool -l
按预期列出信息并且不报告任何错误。从各方面来看,它是一个 well-formed object 文件 — 然而 OS X 10.10.5 终止了任务 (SIGKILL)。
Mach-O 可执行文件的哪些功能在 OS X 加载之前会被检查?这些信息位于何处?这些功能会改变 version-to-version 吗? (often-cited "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
…
不是 100% 确定,但你需要 LC_LOAD_DYLINKER
在你的可执行文件之前加载命令到 运行 dyld,我很确定 OSX如果该加载命令不可用,则不会自动映射到 /usr/lib/dyld
。
您需要 /usr/lib/libSystem.B.dylib
和 LC_LOAD_DYLIB
加载命令吗?我不这么认为,但拥有两者都很好,而且花费不多。
从 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 位 Header
LC_SEGMENT_64
__PAGEZERO
(非零大小,名称可以是任何东西)
LC_SEGMENT_64
__TEXT
(名称可以是任何东西;必须是可读和可执行的;部分是可选的)
LC_UNIXTHREAD
这里是my example这个案例。
用dyld
虽然没有 dyld 你不能做很多事情,所以如果你想使用它,最小的设置是:
- Mach-O 64 位 Header
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
(至少要加载一个最终依赖于 libSystem 或 libSystem 本身才能使 LC_MAIN
工作的实际 dylib)
此外,自 MacOS Monterey 12.3 起:
LC_SYMTAB
(如果使用 LC_DYSYMTAB
,则现在需要)
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
我正在尝试 hand-write 一个 Mach-O 可执行文件。一共有三个加载命令:
LC_SEGMENT_64
加载中__PAGEZERO
LC_SEGMENT_64
加载__TEXT
,带有单个__text
部分LC_UNIXTHREAD
与 appropriately-setrip
每个命令都匹配 mach/loader.h
和相关 headers 中的结构。 otool -l
按预期列出信息并且不报告任何错误。从各方面来看,它是一个 well-formed object 文件 — 然而 OS X 10.10.5 终止了任务 (SIGKILL)。
Mach-O 可执行文件的哪些功能在 OS X 加载之前会被检查?这些信息位于何处?这些功能会改变 version-to-version 吗? (often-cited "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
…
不是 100% 确定,但你需要 LC_LOAD_DYLINKER
在你的可执行文件之前加载命令到 运行 dyld,我很确定 OSX如果该加载命令不可用,则不会自动映射到 /usr/lib/dyld
。
您需要 /usr/lib/libSystem.B.dylib
和 LC_LOAD_DYLIB
加载命令吗?我不这么认为,但拥有两者都很好,而且花费不多。
从 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 位 Header
LC_SEGMENT_64
__PAGEZERO
(非零大小,名称可以是任何东西)LC_SEGMENT_64
__TEXT
(名称可以是任何东西;必须是可读和可执行的;部分是可选的)LC_UNIXTHREAD
这里是my example这个案例。
用dyld
虽然没有 dyld 你不能做很多事情,所以如果你想使用它,最小的设置是:
- Mach-O 64 位 Header
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
(至少要加载一个最终依赖于 libSystem 或 libSystem 本身才能使LC_MAIN
工作的实际 dylib)
此外,自 MacOS Monterey 12.3 起:
LC_SYMTAB
(如果使用LC_DYSYMTAB
,则现在需要)
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