From 7ac4f424d649f4a83876d433457b1de538987d6d Mon Sep 17 00:00:00 2001 From: octalide Date: Sun, 28 Jun 2026 17:25:33 -0400 Subject: [PATCH] fix(runtime/darwin): rewrite aarch64 _start in mach's inline-asm dialect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit the aarch64 darwin _start was written in standard ARM syntax that mach's inline-asm dialect rejects, so darwin-aarch64 could not link: '#'-prefixed immediates (mach treats '#' as the comment char, stripped at lower time, so 'add x1, sp, #8' became 'add x1, sp,'), a 4-operand shifted-register add 'add x2, x1, x2, lsl #3', and a bitmask-immediate 'and sp, sp, #-16'. mirror the CI-tested linux aarch64 _start instruction-form style — bare immediates, an explicit lsl+add for the envp scale, and no explicit stack realignment (sp is 16-byte aligned on arm64 kernel entry) — while preserving the darwin semantics: entry symbol 'start', the _rt_argc/_rt_argv/_rt_envp capture, _rt_init then main, and the darwin 'svc 0x80' exit. closes #320 --- src/runtime/darwin/aarch64.mach | 43 ++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/src/runtime/darwin/aarch64.mach b/src/runtime/darwin/aarch64.mach index 9dce9b9..f9b44f2 100644 --- a/src/runtime/darwin/aarch64.mach +++ b/src/runtime/darwin/aarch64.mach @@ -10,9 +10,9 @@ # # this entrypoint: # 1. extracts argc and argv from the initial stack -# 2. aligns the stack to 16 bytes (required by AAPCS64 before BL) -# 3. calls user-supplied `main(argc, argv)` -# 4. exits via sys_exit with the return code from main +# 2. captures argc/argv/envp for the runtime, then calls `main(argc, argv)` +# (sp is already 16-byte aligned on kernel entry, an arm64 invariant) +# 3. exits via sys_exit with the return code from main # # user code must define: # #[symbol("main")] @@ -43,30 +43,33 @@ fun _rt_init() { #[symbol("start")] pub fun _start() { asm aarch64 { - ldr x0, [sp] # argc -> x0 (1st argument) - add x1, sp, #8 # argv -> x1 (2nd argument) + mov x9, sp # x9 = initial stack pointer (argc at [x9]) + ldr x0, [x9] # argc -> x0 (1st argument to main) + add x1, x9, 8 # argv -> x1 (2nd argument to main) # envp = argv + (argc + 1) * 8 - add x2, x0, #1 - add x2, x1, x2, lsl #3 + add x10, x0, 1 + lsl x10, x10, 3 + add x10, x1, x10 # x10 = envp - adrp x3, _rt_argc - str x0, [x3, :lo12:_rt_argc] - adrp x3, _rt_argv - str x1, [x3, :lo12:_rt_argv] - adrp x3, _rt_envp - str x2, [x3, :lo12:_rt_envp] + adrp x11, _rt_argc + str x0, [x11, :lo12:_rt_argc] + adrp x11, _rt_argv + str x1, [x11, :lo12:_rt_argv] + adrp x11, _rt_envp + str x10, [x11, :lo12:_rt_envp] - and sp, sp, #-16 # align stack to 16 bytes + # sp is 16-byte aligned on kernel entry (an arm64 architectural + # invariant), so no realignment is needed before the calls. bl _rt_init - adrp x3, _rt_argc - ldr x0, [x3, :lo12:_rt_argc] - adrp x3, _rt_argv - ldr x1, [x3, :lo12:_rt_argv] + adrp x11, _rt_argc + ldr x0, [x11, :lo12:_rt_argc] + adrp x11, _rt_argv + ldr x1, [x11, :lo12:_rt_argv] bl main - mov x16, #1 # SYS_exit - svc #0x80 + mov x16, 1 # SYS_exit + svc 0x80 } }