From 03ca69148b3e96a2051926273c9f673900bda3e2 Mon Sep 17 00:00:00 2001 From: BenceSzalai Date: Thu, 1 May 2025 17:17:31 +0200 Subject: [PATCH] Use separate APE loader for x86_64 and arm on Apple Silicon --- ape/ape.S | 5 +++++ ape/ape.h | 8 ++++++++ libc/proc/execve-sysv.c | 8 +++++++- tool/build/apelink.c | 8 +++++++- tool/build/pledge.c | 4 ++++ tool/cosmocc/README.md | 3 ++- 6 files changed, 33 insertions(+), 3 deletions(-) diff --git a/ape/ape.S b/ape/ape.S index f274e31f6..37d2087d0 100644 --- a/ape/ape.S +++ b/ape/ape.S @@ -613,6 +613,11 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang .ascii "t=\"${TMPDIR:-${HOME:-.}}/.ape-" .ascii APE_VERSION_STR .ascii "\"\n" +#if SupportsXnu() +// Add an architecture suffix to the temporary APE Loader +// name to differentiate between x86_64 and arm64. + .ascii "[ -d /Applications ] && t=\"${t}-$(uname -m 2>/dev/null || printf 'unknown')\"\n" +#endif /* SupportsXnu() */ .ascii "[ -x \"$t\" ] || {\n" .ascii "mkdir -p \"${t%/*}\" &&\n" .ascii "dd if=\"$o\" of=\"$t.$$\" skip=" diff --git a/ape/ape.h b/ape/ape.h index d2f589612..61248a272 100644 --- a/ape/ape.h +++ b/ape/ape.h @@ -10,4 +10,12 @@ #define APE_VERSION_STR_(x, y) APE_VERSION_STR__(x, y) #define APE_VERSION_NOTE_(x, y) (100000000 * (x) + 1000000 * (y)) +#if defined(__x86_64__) +#define GetXnuSuffix() "-x86_64" +#elif defined(__aarch64__) +#define GetXnuSuffix() "-arm64" +#else +#define GetXnuSuffix() "-unknown" +#endif + #endif /* COSMOPOLITAN_APE_APE_H_ */ diff --git a/libc/proc/execve-sysv.c b/libc/proc/execve-sysv.c index e0dbc53b1..b4bec57c9 100644 --- a/libc/proc/execve-sysv.c +++ b/libc/proc/execve-sysv.c @@ -132,7 +132,13 @@ int sys_execve(const char *prog, char *const argv[], char *const envp[]) { RetryExecve("/usr/bin/ape", shargs, envp); } char *buf = alloca(PATH_MAX); - const char *name = "/.ape-" APE_VERSION_STR; + const char *name = ""; + if (IsXnu()) { + name = "/.ape-" APE_VERSION_STR GetXnuSuffix(); + } + else { + name = "/.ape-" APE_VERSION_STR; + } InitExecve(); RetryExecve(Join(g_execve.tmpdir, name, buf), shargs, envp); RetryExecve(Join(g_execve.home, name, buf), shargs, envp); diff --git a/tool/build/apelink.c b/tool/build/apelink.c index f84b50ef2..3be091641 100644 --- a/tool/build/apelink.c +++ b/tool/build/apelink.c @@ -2016,7 +2016,13 @@ int main(int argc, char *argv[]) { // otherwise try to use the ad-hoc self-extracted loader, securely if (loaders.n) { - p = stpcpy(p, "t=\"${TMPDIR:-${HOME:-.}}/.ape-" APE_VERSION_STR "\"\n" + p = stpcpy(p, "t=\"${TMPDIR:-${HOME:-.}}/.ape-" APE_VERSION_STR); + if (support_vector & _HOSTXNU) { + // Add the current architecture to the temporary APE Loader + // name to differentiate between x86_64 and arm64 Ape Loaders. + p = stpcpy(p, "$([ -d /Applications ] && ( printf '-'; ( uname -m 2>/dev/null || printf 'unknown')))"); + } + p = stpcpy(p, "\"\n" "[ x\"$1\" != x--assimilate ] && " "[ -x \"$t\" ] && " "exec \"$t\" \"$o\" \"$@\"\n"); diff --git a/tool/build/pledge.c b/tool/build/pledge.c index 78f5527d5..f7e207e36 100644 --- a/tool/build/pledge.c +++ b/tool/build/pledge.c @@ -555,10 +555,14 @@ void ApplyFilesystemPolicy(unsigned long ipromises) { if ((p = getenv("TMPDIR"))) { UnveilIfExists( __join_paths(buf, sizeof(buf), p, ".ape-" APE_VERSION_STR), "rx"); + UnveilIfExists( + __join_paths(buf, sizeof(buf), p, ".ape-" APE_VERSION_STR GetXnuSuffix()), "rx"); } if ((p = getenv("HOME"))) { UnveilIfExists( __join_paths(buf, sizeof(buf), p, ".ape-" APE_VERSION_STR), "rx"); + UnveilIfExists( + __join_paths(buf, sizeof(buf), p, ".ape-" APE_VERSION_STR GetXnuSuffix()), "rx"); } } } diff --git a/tool/cosmocc/README.md b/tool/cosmocc/README.md index 84802987e..e255ab776 100644 --- a/tool/cosmocc/README.md +++ b/tool/cosmocc/README.md @@ -136,7 +136,8 @@ On Apple Silicon, `aarch64-unknown-cosmo-cc` produces ELF binaries. If you build a hello world program, then you need to say `ape ./hello`. If you don't have an `ape` command then run `cc -o ape bin/ape-m1.c` which should be moved to `/usr/local/bin/ape`. Your APE interpreter might -already exist under a path like `$TMPDIR/.ape-1.10`. It's important to +already exist under a path like `$TMPDIR/.ape-1.10-arm64` or +`$TMPDIR/.ape-1.10-x86_64` if you are using Rosetta. It's important to note this is only a gotcha for the cross compiler. Your `cosmocc` compiler wraps the actual ELF binaries with a shell script that'll extract and compile an APE loader automatically, as needed. This also