我有一个简单的 C 应用程序:
#include <stdio.h>
int main() {
printf("Hello, world!\n");
}
当我:
- 在 Apple Silicon 设备上构建它
- 瞄准 arm64
- 使用为 x86_64 编译的构建系统
- 替换现有的二进制文件(例如在重建期间)
最终的二进制文件无法执行,并根据 shell 报告为“已终止”:
% rm hello
# arch simulates the build system which is still compiled for x86_64
% arch -x86_64 cc -arch arm64 hello.c -o hello
% ./hello
Hello, world!
% arch -x86_64 cc -arch arm64 hello.c -o hello
% ./hello
zsh: killed ./hello
如果我的构建系统是原生 arm64(或 arm64e),那么就没有问题:
% rm hello
% arch -arm64e cc -arch arm64 hello.c -o hello
% ./hello
Hello, world!
% arch -arm64e cc -arch arm64 hello.c -o hello
% ./hello
Hello, world!
如果我将二进制文件复制到新路径然后替换代码签名,那么它可以工作:
% cp hello hello2
% codesign -s - -f hello2
hello2: replacing existing signature
% ./hello2
Hello, world!
原版复现步骤及调试
当我在 Apple Silicon 设备上构建它时,针对 arm64,但使用为 x86_64 编译的构建系统,最终的二进制文件无法执行,并且根据 shell 报告为“已终止”:
# arch simulates the build system which is still compiled for x86_64
% arch -x86_64 cc -arch arm64 hello.c -o hello
% file hello
hello: Mach-O 64-bit executable arm64
% ./hello
zsh: killed ./hello
即使尝试调试它也会失败:
% lldb hello
(lldb) target create "hello"
zsh: killed lldb hello
作为一种解决方法,我可以在调用之前使用 shim 编译器“重置”回 arm64 环境cc
,但这很不雅,而且感觉我缺少一些配置以避免跳过这么多的障碍。
% cc --version
Apple clang version 12.0.0 (clang-1200.0.32.27)
Target: arm64-apple-darwin20.1.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
这是在 macOS Big Sur 11.0.1 上。
从 x86_64 交叉编译
如果我从 x86_64 机器交叉编译并 scp 周围的二进制文件,文件执行得很好:
% SDKROOT=$(xcrun -sdk macosx11.0 --show-sdk-path) \
MACOSX_DEPLOYMENT_TARGET=$(xcrun -sdk macosx11.0 --show-sdk-platform-version) \
cc -arch arm64 hello.c -o hello
% scp hello silicon:/tmp/hello-cross
换机...
% file /tmp/hello-cross
/tmp/hello-cross: Mach-O 64-bit executable arm64
% /tmp/hello-cross
Hello, world!
跟踪子进程
添加--verbose
到cc
调用会打印出子进程(我添加了换行符以突出显示其他调试中的那些):
% arch -x86_64 cc --verbose -arch arm64 hello.c -o hello
Apple clang version 12.0.0 (clang-1200.0.32.27)
Target: aarch64-apple-darwin20.1.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" -cc1 -triple arm64-apple-macosx11.0.0 -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -Werror=implicit-function-declaration -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -discard-value-names -main-file-name hello.c -mrelocation-model pic -pic-level 2 -mthread-model posix -mframe-pointer=non-leaf -fno-strict-return -masm-verbose -munwind-tables -target-sdk-version=11.0 -target-cpu vortex -target-feature +v8.3a -target-feature +fp-armv8 -target-feature +neon -target-feature +crc -target-feature +crypto -target-feature +fullfp16 -target-feature +ras -target-feature +lse -target-feature +rdm -target-feature +rcpc -target-feature +zcm -target-feature +zcz -target-feature +sha2 -target-feature +aes -target-abi darwinpcs -fallow-half-arguments-and-returns -dwarf-column-info -debugger-tuning=lldb -target-linker-version 609.6 -v -resource-dir /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/12.0.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -I/usr/local/include -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/local/include -internal-isystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/12.0.0/include -internal-externc-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include -internal-externc-isystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -Wno-reorder-init-list -Wno-implicit-int-float-conversion -Wno-c99-designator -Wno-final-dtor-non-final-class -Wno-extra-semi-stmt -Wno-misleading-indentation -Wno-quoted-include-in-framework-header -Wno-implicit-fallthrough -Wno-enum-enum-conversion -Wno-enum-float-conversion -fdebug-compilation-dir /tmp/example -ferror-limit 19 -fmessage-length 237 -stack-protector 1 -fstack-check -mdarwin-stkchk-strong-link -fblocks -fencode-extended-block-signature -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fobjc-runtime=macosx-11.0.0 -fmax-type-align=16 -fdiagnostics-show-option -fcolor-diagnostics -o /var/folders/j2/g4_hr3jd2sz415vrf7b1d6300000gp/T/hello-232f6b.o -x c hello.c
clang -cc1 version 12.0.0 (clang-1200.0.32.27) default target x86_64-apple-darwin20.1.0
ignoring nonexistent directory "/usr/local/include"
ignoring nonexistent directory "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/local/include"
ignoring nonexistent directory "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Library/Frameworks"
#include "..." search starts here:
#include <...> search starts here:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/12.0.0/include
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks (framework directory)
End of search list.
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" -demangle -lto_library /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libLTO.dylib -no_deduplicate -dynamic -arch arm64 -platform_version macos 11.0.0 11.0 -syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -o hello -L/usr/local/lib /var/folders/j2/g4_hr3jd2sz415vrf7b1d6300000gp/T/hello-232f6b.o -lSystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/12.0.0/lib/darwin/libclang_rt.osx.a
编译器调用 has-triple arm64-apple-macosx11.0.0
和链接器调用 has -arch arm64
,因此似乎正在传递适当的值。
比较失败和成功的二进制文件
正如评论中所建议的,我尝试比较这两个二进制文件。不幸的是,一旦打开失败的可执行文件,建议的Beyond Compare工具也会崩溃。我怀疑这与 LLDB 报告被杀的根本原因相同。
同时,这是比较原始十六进制数据的输出:
--- /tmp/hello-cross.hex 2020-11-14 05:07:04.000000000 -0800
+++ ./hello.hex 2020-11-14 05:06:52.000000000 -0800
@@ -74,10 +74,10 @@
00000490: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000004a0: 0e00 0000 2000 0000 0c00 0000 2f75 7372 .... ......./usr
000004b0: 2f6c 6962 2f64 796c 6400 0000 0000 0000 /lib/dyld.......
-000004c0: 1b00 0000 1800 0000 7b34 532d f414 3f99 ........{4S-..?.
-000004d0: a866 f4d8 29bf f7ce 3200 0000 2000 0000 .f..)...2... ...
+000004c0: 1b00 0000 1800 0000 0ad8 b6d9 c6c4 32f0 ..............2.
+000004d0: 9522 80e2 f036 54f7 3200 0000 2000 0000 ."...6T.2... ...
000004e0: 0100 0000 0000 0b00 0000 0b00 0100 0000 ................
-000004f0: 0300 0000 0006 6102 2a00 0000 1000 0000 ......a.*.......
+000004f0: 0300 0000 0007 6102 2a00 0000 1000 0000 ......a.*.......
00000500: 0000 0000 0000 0000 2800 0080 1800 0000 ........(.......
00000510: 543f 0000 0000 0000 0000 0000 0000 0000 T?..............
00000520: 0c00 0000 3800 0000 1800 0000 0200 0000 ....8...........
@@ -3094,9 +3094,9 @@
0000c150: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000c160: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000c170: 0000 4000 0000 0000 0000 0001 6865 6c6c ..@.........hell
-0000c180: 6f00 e40f cd6f 1abe f672 0c10 0915 8b30 o....o...r.....0
-0000c190: 5c9a 4a69 c9eb efdd a655 11c8 f5dc 3d86 \.Ji.....U....=.
-0000c1a0: b3d5 ad7f acb2 586f c6e9 66c0 04d7 d1d1 ......Xo..f.....
+0000c180: 6f00 29f3 685d 60bf c358 4179 1735 b8b0 o.).h]`..XAy.5..
+0000c190: d018 3ec5 aa3c 0f60 cc8b a4f2 23bf b37d ..>..<.`....#..}
+0000c1a0: 9ee8 ad7f acb2 586f c6e9 66c0 04d7 d1d1 ......Xo..f.....
0000c1b0: 6b02 4f58 05ff 7cb4 7c7a 85da bd8b 4889 k.OX..|.|z....H.
0000c1c0: 2ca7 ad7f acb2 586f c6e9 66c0 04d7 d1d1 ,.....Xo..f.....
0000c1d0: 6b02 4f58 05ff 7cb4 7c7a 85da bd8b 4889 k.OX..|.|z....H.
在两个文件上运行otool -fahlLDtvV
并比较输出结果:
--- /tmp/hello-cross.dump 2020-11-14 05:41:10.000000000 -0800
+++ hello.dump 2020-11-14 05:41:22.000000000 -0800
@@ -226,7 +226,7 @@
Load command 9
cmd LC_UUID
cmdsize 24
- uuid 7B34532D-F414-3F99-A866-F4D829BFF7CE
+ uuid 0AD8B6D9-C6C4-32F0-9522-80E2F03654F7
Load command 10
cmd LC_BUILD_VERSION
cmdsize 32
@@ -235,7 +235,7 @@
minos 11.0
ntools 1
tool ld
- version 609.6
+ version 609.7
Load command 11
cmd LC_SOURCE_VERSION
cmdsize 16
这似乎对应于原始十六进制转储的第一个大块,这表明重要的区别在于第二个大块。
代码签名
MachOView指示地址0xc180
出现在“代码签名”部分中。但是,签名似乎足够有效:
% codesign --verify --verbose hello
hello: valid on disk
hello: satisfies its Designated Requirement
查看 Console.app,我确实看到了以下几行:
CODE SIGNING: cs_invalid_page(0x10439c000): p=32470[hello] final status 0x23020200, denying page sending SIGKILL
CODE SIGNING: process 32470[hello]: rejecting invalid page at address 0x10439c000 from offset 0x0 in file "/private/tmp/example/hello" (cs_mtime:1605366572.426749233 == mtime:1605366572.426749233) (signed:1 validated:1 tainted:1 nx:0 wpmapped:1 dirty:0 depth:0)