I have a minimal c program for the m1 arm cpu that returns 42:
void _start() {
asm("mov x0, #42;");
asm("mov x16, #1;");
asm("svc 0x80;");
}
This code compiles after telling clang to use the _start symbol and returns the correct value.
clang -Wl,-e, -Wl,__start test.c -o dyn.out
./dyn.out ; echo $?
42
However this binary still has dynamic links according to otool:
otool -L ./dyn.out
./dyn.out:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1311.100.3)
After telling clang to produce a unsigned static binary however macOS then immediately kills the binary when trying to run.
clang -Wl,-e, -Wl,__start -static -nostdlib test.c -o static_no_sign.out
zsh: killed ./static_no_sign.out
Signing the binary before running also produces the same problem.
clang -Wl,-e, -Wl,__start -static -nostdlib test.c -o static_sign.out
codesign -s - static_sign.out
./static_sign.out
zsh: killed ./static_sign.out
The following messages are produced in Console:
taskgated: UNIX error exception: 3
taskgated: no signature for pid=93166 (cannot make code: UNIX[No such process])
But codesign can verify the signature
codesign -v -v static_sign.out
static_sign.out: valid on disk
static_sign.out: satisfies its Designated Requirement
Can anyone clarify why macOS is deciding to kill the clang produced binaries?
Because static binaries are explicitly disallowed on any architecture other than x86_64.
XNU contains this code piece in the Mach-O loader:
If you do the exact same thing on x86_64, it works: