Why does my native arm64 application built using an x86_64 build system fail to be code signed unless I remove the previous executable?

南笙酒味 提交于 2020-12-08 05:54:36

问题


I have a simple C application:

#include <stdio.h>

int main() {
  printf("Hello, world!\n");
}

When I:

  1. build this on an Apple Silicon device
  2. targeting arm64
  3. using a build system that is compiled for x86_64
  4. replace an existing binary (such as during a rebuild)

The final binary cannot be executed and is reported as "killed" according to the 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

If my build system is native arm64 (or arm64e), then there's no problem:

% 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!

If I copy the binary to a new path and then replace the code signature, then it works:

% cp hello hello2

% codesign -s - -f hello2
hello2: replacing existing signature

% ./hello2
Hello, world!

Original reproduction steps and debugging

When I build this on an Apple Silicon device, targeting arm64, but using a build system that is compiled for x86_64, the final binary cannot be executed and is reported as "killed" according to the 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

Even attempting to debug it fails:

% lldb hello
(lldb) target create "hello"
zsh: killed     lldb hello

As a workaround, I can use a shim compiler to "reset" back to an arm64 environment before calling cc, but that's inelegant and it feels like I'm missing some configuration to avoid jumping through so many hoops.

% 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

This is on macOS Big Sur 11.0.1.

Cross compiling from x86_64

If I cross-compile from an x86_64 machine and scp the binary around, the file executes fine:

% 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

Switch machines...

% file /tmp/hello-cross
/tmp/hello-cross: Mach-O 64-bit executable arm64

% /tmp/hello-cross
Hello, world!

Tracing child processes

Adding --verbose to the cc invocation prints out the child processes (I added newlines to highlight those among the other debugging):

% 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

The compiler invocation has -triple arm64-apple-macosx11.0.0 and the linker invocation has -arch arm64, so it seems like appropriate values are being passed.

Comparing failing and successful binaries

As suggested in a comment, I've tried comparing the two binary files. Unfortunately, the suggested Beyond Compare tool also crashes as soon as the failing executable is opened. I suspect that it's for the same underlying reason that LLDB reports being killed.

In the meantime, here's the output of comparing the raw hex data:

--- /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.

Running otool -fahlLDtvV on both files and comparing the outputs yields:

--- /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

This seems to correspond to the first hunk of the raw hex dump, suggesting that the important difference is in the second hunk.

Code signing

MachOView indicates that address 0xc180 occurs within the "Code Signature" section. However, it appears that the signature is valid enough:

% codesign --verify --verbose hello
hello: valid on disk
hello: satisfies its Designated Requirement

Looking at Console.app, I do see these lines:

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)

来源:https://stackoverflow.com/questions/64830671/why-does-my-native-arm64-application-built-using-an-x86-64-build-system-fail-to

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!