为什么 macOS 会杀死由 clang 创建的静态可执行文件?
Why does macOS kill static executables created by clang?
我有一个用于 m1 arm cpu 的最小 c 程序 returns 42:
void _start() {
asm("mov x0, #42;");
asm("mov x16, #1;");
asm("svc 0x80;");
}
此代码在告诉 clang 使用 _start 符号和 returns 正确值后编译。
clang -Wl,-e, -Wl,__start test.c -o dyn.out
./dyn.out ; echo $?
42
然而,根据 otool,此二进制文件仍然具有动态链接:
otool -L ./dyn.out
./dyn.out:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1311.100.3)
在告诉 clang 生成一个未签名的静态二进制文件之后,macOS 然后在尝试 运行.
时立即杀死二进制文件
clang -Wl,-e, -Wl,__start -static -nostdlib test.c -o static_no_sign.out
zsh: killed ./static_no_sign.out
在 运行ning 之前签署二进制文件也会产生同样的问题。
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
以下消息在控制台中生成:
taskgated: UNIX error exception: 3
taskgated: no signature for pid=93166 (cannot make code: UNIX[No such process])
但是codesign可以验证签名
codesign -v -v static_sign.out
static_sign.out: valid on disk
static_sign.out: satisfies its Designated Requirement
谁能解释为什么 macOS 决定终止 clang 生成的二进制文件?
因为除了 x86_64.
之外的任何架构都明确不允许使用静态二进制文件
XNU 在 Mach-O 加载程序中包含 this code piece:
case MH_EXECUTE:
if (depth != 1 && depth != 3) {
return LOAD_FAILURE;
}
if (header->flags & MH_DYLDLINK) {
/* Check properties of dynamic executables */
if (!(header->flags & MH_PIE) && pie_required(header->cputype, header->cpusubtype & ~CPU_SUBTYPE_MASK)) {
return LOAD_FAILURE;
}
result->needs_dynlinker = TRUE;
} else if (header->cputype == CPU_TYPE_X86_64) {
/* x86_64 static binaries allowed */
} else {
/* Check properties of static executables (disallowed except for development) */
#if !(DEVELOPMENT || DEBUG)
return LOAD_FAILURE;
#endif
}
break;
如果您在 x86_64 上执行完全相同的操作,它会起作用:
void _start()
{
__asm__ volatile
(
".intel_syntax noprefix\n"
"mov eax, 0x2000001\n"
"mov edi, 42\n"
"syscall"
);
}
% clang -Wl,-e,__start -static -nostdlib t.c -o t -arch x86_64
% ./t
% echo $?
42
我有一个用于 m1 arm cpu 的最小 c 程序 returns 42:
void _start() {
asm("mov x0, #42;");
asm("mov x16, #1;");
asm("svc 0x80;");
}
此代码在告诉 clang 使用 _start 符号和 returns 正确值后编译。
clang -Wl,-e, -Wl,__start test.c -o dyn.out
./dyn.out ; echo $?
42
然而,根据 otool,此二进制文件仍然具有动态链接:
otool -L ./dyn.out
./dyn.out:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1311.100.3)
在告诉 clang 生成一个未签名的静态二进制文件之后,macOS 然后在尝试 运行.
时立即杀死二进制文件clang -Wl,-e, -Wl,__start -static -nostdlib test.c -o static_no_sign.out
zsh: killed ./static_no_sign.out
在 运行ning 之前签署二进制文件也会产生同样的问题。
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
以下消息在控制台中生成:
taskgated: UNIX error exception: 3
taskgated: no signature for pid=93166 (cannot make code: UNIX[No such process])
但是codesign可以验证签名
codesign -v -v static_sign.out
static_sign.out: valid on disk
static_sign.out: satisfies its Designated Requirement
谁能解释为什么 macOS 决定终止 clang 生成的二进制文件?
因为除了 x86_64.
之外的任何架构都明确不允许使用静态二进制文件
XNU 在 Mach-O 加载程序中包含 this code piece:
case MH_EXECUTE:
if (depth != 1 && depth != 3) {
return LOAD_FAILURE;
}
if (header->flags & MH_DYLDLINK) {
/* Check properties of dynamic executables */
if (!(header->flags & MH_PIE) && pie_required(header->cputype, header->cpusubtype & ~CPU_SUBTYPE_MASK)) {
return LOAD_FAILURE;
}
result->needs_dynlinker = TRUE;
} else if (header->cputype == CPU_TYPE_X86_64) {
/* x86_64 static binaries allowed */
} else {
/* Check properties of static executables (disallowed except for development) */
#if !(DEVELOPMENT || DEBUG)
return LOAD_FAILURE;
#endif
}
break;
如果您在 x86_64 上执行完全相同的操作,它会起作用:
void _start()
{
__asm__ volatile
(
".intel_syntax noprefix\n"
"mov eax, 0x2000001\n"
"mov edi, 42\n"
"syscall"
);
}
% clang -Wl,-e,__start -static -nostdlib t.c -o t -arch x86_64
% ./t
% echo $?
42