From 03ca69148b3e96a2051926273c9f673900bda3e2 Mon Sep 17 00:00:00 2001 From: BenceSzalai Date: Thu, 1 May 2025 17:17:31 +0200 Subject: [PATCH 1/5] 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 From 43ea22477fb9830570bfb6f08627fa4a087a3ee1 Mon Sep 17 00:00:00 2001 From: BenceSzalai Date: Thu, 1 May 2025 17:51:50 +0200 Subject: [PATCH 2/5] APE Uninstall script should remove new ad-hoc APE files --- ape/apeuninstall.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ape/apeuninstall.sh b/ape/apeuninstall.sh index 3e74d3ac4..bc725fbf7 100755 --- a/ape/apeuninstall.sh +++ b/ape/apeuninstall.sh @@ -59,6 +59,9 @@ for x in .ape \ .ape-1.7 \ .ape-1.8 \ .ape-1.9 \ + .ape-1.10-arm64 \ + .ape-1.10-arm64.c \ + .ape-1.10-x86_64 \ .ape-1.10; do rm -f \ ~/$x \ From e40fe1a391420db4b3cfbacb308d3a2f0d0612eb Mon Sep 17 00:00:00 2001 From: BenceSzalai Date: Thu, 1 May 2025 17:53:20 +0200 Subject: [PATCH 3/5] Also clean up additional `.ape-x.xx.c` files on Darwin for all versions --- ape/apeuninstall.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ape/apeuninstall.sh b/ape/apeuninstall.sh index bc725fbf7..e3cf72e6b 100755 --- a/ape/apeuninstall.sh +++ b/ape/apeuninstall.sh @@ -60,7 +60,6 @@ for x in .ape \ .ape-1.8 \ .ape-1.9 \ .ape-1.10-arm64 \ - .ape-1.10-arm64.c \ .ape-1.10-x86_64 \ .ape-1.10; do rm -f \ @@ -68,4 +67,9 @@ for x in .ape \ /tmp/$x \ o/tmp/$x \ "${TMPDIR:-/tmp}/$x" + rm -f \ + ~/$x \ + /tmp/$x \ + o/tmp/$x \ + "${TMPDIR:-/tmp}/$x.c" done From d5a790d455f3e9780c27eae4b2f31c019bbe0f80 Mon Sep 17 00:00:00 2001 From: BenceSzalai Date: Thu, 1 May 2025 18:10:45 +0200 Subject: [PATCH 4/5] Try to better adhere to existing line length conventions --- ape/ape.S | 5 ++++- tool/build/apelink.c | 7 ++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ape/ape.S b/ape/ape.S index 37d2087d0..9a6e7378f 100644 --- a/ape/ape.S +++ b/ape/ape.S @@ -616,7 +616,10 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang #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" + .ascii "[ -d /Applications ] && " + .ascii "t=\"${t}-$(" + .ascii "uname -m 2>/dev/null || printf 'unknown'" + .ascii ")\"\n" #endif /* SupportsXnu() */ .ascii "[ -x \"$t\" ] || {\n" .ascii "mkdir -p \"${t%/*}\" &&\n" diff --git a/tool/build/apelink.c b/tool/build/apelink.c index 3be091641..3408abd18 100644 --- a/tool/build/apelink.c +++ b/tool/build/apelink.c @@ -2018,9 +2018,10 @@ int main(int argc, char *argv[]) { if (loaders.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')))"); + // Add an architecture suffix to the temporary APE Loader + // name to differentiate between x86_64 and arm64. + p = stpcpy(p, "$([ -d /Applications ] && ( printf '-'; " + "( uname -m 2>/dev/null || printf 'unknown') ))"); } p = stpcpy(p, "\"\n" "[ x\"$1\" != x--assimilate ] && " From b78f8911a0447e52187a3519d5f5f26790aee0b0 Mon Sep 17 00:00:00 2001 From: BenceSzalai Date: Thu, 1 May 2025 19:13:22 +0200 Subject: [PATCH 5/5] Apply `clang-format` changes --- libc/proc/execve-sysv.c | 7 +++---- tool/build/apelink.c | 4 ++-- tool/build/pledge.c | 10 ++++++---- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/libc/proc/execve-sysv.c b/libc/proc/execve-sysv.c index b4bec57c9..a45b9551b 100644 --- a/libc/proc/execve-sysv.c +++ b/libc/proc/execve-sysv.c @@ -134,10 +134,9 @@ int sys_execve(const char *prog, char *const argv[], char *const envp[]) { char *buf = alloca(PATH_MAX); const char *name = ""; if (IsXnu()) { - name = "/.ape-" APE_VERSION_STR GetXnuSuffix(); - } - else { - name = "/.ape-" APE_VERSION_STR; + name = "/.ape-" APE_VERSION_STR GetXnuSuffix(); + } else { + name = "/.ape-" APE_VERSION_STR; } InitExecve(); RetryExecve(Join(g_execve.tmpdir, name, buf), shargs, envp); diff --git a/tool/build/apelink.c b/tool/build/apelink.c index 3408abd18..947b62334 100644 --- a/tool/build/apelink.c +++ b/tool/build/apelink.c @@ -2020,8 +2020,8 @@ int main(int argc, char *argv[]) { if (support_vector & _HOSTXNU) { // Add an architecture suffix to the temporary APE Loader // name to differentiate between x86_64 and arm64. - p = stpcpy(p, "$([ -d /Applications ] && ( printf '-'; " - "( uname -m 2>/dev/null || printf 'unknown') ))"); + p = stpcpy(p, "$([ -d /Applications ] && ( printf '-'; ( uname -m " + "2>/dev/null || printf 'unknown')))"); } p = stpcpy(p, "\"\n" "[ x\"$1\" != x--assimilate ] && " diff --git a/tool/build/pledge.c b/tool/build/pledge.c index f7e207e36..b35ba60af 100644 --- a/tool/build/pledge.c +++ b/tool/build/pledge.c @@ -555,14 +555,16 @@ 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"); + 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"); + UnveilIfExists(__join_paths(buf, sizeof(buf), p, + ".ape-" APE_VERSION_STR GetXnuSuffix()), + "rx"); } } }