From 55de7bca15c8f269e2506f9cd7a998c341d30a6b Mon Sep 17 00:00:00 2001 From: Jonah Walker Date: Tue, 21 Jul 2026 00:33:01 -0400 Subject: [PATCH] fix(thumb): keep SP 8-byte aligned for native calls with >4 argv words invokeNative_thumb.s rounds the outgoing-stack reservation up to 8 bytes and then unconditionally added another 4 ("+4 because odd(5) registers are in stack"). But SP is already 8-byte aligned at that point: the prologue pushes r4-r7 + lr (20 bytes) and does sub sp,#4, i.e. 24 bytes total (.cfi_def_cfa_offset 24). The reservation must therefore be a multiple of 8 and nothing more; the extra word left SP at 4 mod 8 at the blx for any native called with more than 4 packed argv words. AAPCS requires 8-byte stack alignment at a public interface. Effect: the compiler places an outgoing 8-byte argument (e.g. a vararg i64) at a slot it models as 8-aligned but whose real address is 4 mod 8; the callee's va_arg realigns to the true 8-byte boundary 4 bytes lower and reads the low word paired with a zero, so a %lld in such a native printed value * 2^32. The value itself arrives intact in r2:r3, which is why register-level inspection looked clean. Remove the stray add r6, r6, #4; the reservation is already correctly rounded, and the restore path (add sp, sp, r6) is symmetric, so nothing else changes. Signed-off-by: Jonah Walker Co-Authored-By: Claude Opus 4.8 --- core/iwasm/common/arch/invokeNative_thumb.s | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/iwasm/common/arch/invokeNative_thumb.s b/core/iwasm/common/arch/invokeNative_thumb.s index 9a3f651b40..4c929ac19a 100644 --- a/core/iwasm/common/arch/invokeNative_thumb.s +++ b/core/iwasm/common/arch/invokeNative_thumb.s @@ -61,12 +61,16 @@ _invokeNative: sub r5, r5, #4 /* argc -= 4, now we have r0 ~ r3 */ - /* Ensure address is 8 byte aligned */ + /* Reserve stack for the remaining args, rounded up to 8 bytes so SP + stays 8-byte aligned at the blx below (AAPCS requires 8-byte SP + alignment at a public interface). SP is already 8-aligned here: + the prologue pushed r4-r7 + lr (20 bytes) and did sub sp,#4, i.e. + 24 bytes (see .cfi_def_cfa_offset 24). The reservation must + therefore be a multiple of 8 and nothing more. */ lsl r6, r5, #2 /* r6 = argc * 4 */ mov r7, #7 add r6, r6, r7 /* r6 = (r6 + 7) & ~7 */ bic r6, r6, r7 - add r6, r6, #4 /* +4 because odd(5) registers are in stack */ mov r7, sp sub r7, r7, r6 /* reserved stack space for left arguments */ mov sp, r7