From 9f8e6c10dd7429c89913c72717f75797bd95210b Mon Sep 17 00:00:00 2001
From: Daniil Kulchenko <daniil@kulchenko.com>
Date: Mon, 27 Jun 2022 16:28:59 -0700
Subject: [PATCH] Work around Rosetta clobbering startup registers on M1 Macs
 (issue #429) (#453)

Rosetta doesn't correctly respect the startup registers as defined in LC_UNIXTHREAD
which makes platform detection go awry. But at least Rosetta appears to consistently
set rbx to 0x00000000ffffffff and rdx to 0x0000000000000001 at startup for every
x64 executable I could get my hands on. So we use that to detect Rosetta's presence
and set up the correct registers for XNU.
---
 ape/loader-elf.S   | 13 ++++++++++++-
 ape/loader-macho.S | 13 ++++++++++++-
 ape/loader.c       |  4 ++--
 libc/crt/crt.S     | 12 ++++++++++++
 4 files changed, 38 insertions(+), 4 deletions(-)

diff --git a/ape/loader-elf.S b/ape/loader-elf.S
index 7ba774525..5e2c3725c 100644
--- a/ape/loader-elf.S
+++ b/ape/loader-elf.S
@@ -213,7 +213,18 @@ macho:	.long	0xFEEDFACE+1
 //
 //	@see	APE_LOADER_ENTRY
 //	@see	ape/loader.h
-_start:	mov	%rsp,%rsi
+_start:
+
+//	Hack for detecting M1 Rosetta environment.
+//	https://github.com/jart/cosmopolitan/issues/429#issuecomment-1166704377
+	cmp	$-1,%ebx
+	jne	0f
+	cmp	$+1,%edx
+	jne	0f
+	mov	$XNU,%dl
+	xor	%ecx,%ecx
+
+0:	mov	%rsp,%rsi
 	jmp	ApeLoader
 	.endfn	_start,globl
 
diff --git a/ape/loader-macho.S b/ape/loader-macho.S
index b027760a7..5bd2bbcd5 100644
--- a/ape/loader-macho.S
+++ b/ape/loader-macho.S
@@ -113,7 +113,18 @@ macho:	.long	0xFEEDFACE+1
 	.endobj	macho,globl
 
 	.align	64
-_start:	mov	%rsp,%rsi
+_start:
+
+//	Hack for detecting M1 Rosetta environment.
+//	https://github.com/jart/cosmopolitan/issues/429#issuecomment-1166704377
+	cmp	$-1,%ebx
+	jne	0f
+	cmp	$+1,%edx
+	jne	0f
+	mov	$XNU,%dl
+	xor	%ecx,%ecx
+
+0:	mov	%rsp,%rsi
 	jmp	ApeLoader
 	.endfn	_start,globl
 
diff --git a/ape/loader.c b/ape/loader.c
index 5e1f3de82..e5354eb09 100644
--- a/ape/loader.c
+++ b/ape/loader.c
@@ -595,11 +595,11 @@ __attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl,
   // detect freebsd
   if (handoff) {
     os = handoff->os;
+  } else if (SupportsXnu() && dl == XNU) {
+    os = XNU;
   } else if (SupportsFreebsd() && di) {
     os = FREEBSD;
     sp = (long *)di;
-  } else if (SupportsXnu() && dl == XNU) {
-    os = XNU;
   } else {
     os = 0;
   }
diff --git a/libc/crt/crt.S b/libc/crt/crt.S
index f30fde679..1cdca0e69 100644
--- a/libc/crt/crt.S
+++ b/libc/crt/crt.S
@@ -31,6 +31,18 @@
 //	@noreturn
 _start:
 
+#if SupportsXnu()
+//	Hack for detecting M1 Rosetta environment.
+//	https://github.com/jart/cosmopolitan/issues/429#issuecomment-1166704377
+	cmp	$-1,%ebx
+	jne	0f
+	cmp	$+1,%edx
+	jne	0f
+	mov	$XNU,%cl
+	xor	%edi,%edi
+0:
+#endif
+
 #if SupportsFreebsd()
 //	detect free besiyata dishmaya
 	test	%rdi,%rdi