fix(handles): 变参调用按 Win64 8 字节槽位提升(整数 sext 到 i64, f32 提升 f64)

根因: 变参按窄类型(i32)传入, LLVM 只写 4 字节进 8 字节栈槽, 高 4 字节残留旧数据;
viperlib %d 强制 va_arg 读 i64 暴露残留高位(如 0x400921FB00001000, 高位是 PI 残留)。
修复: found_func.IsVarArg==1 且参数在变参位时提升, 对齐 TPC/Python-llvmlite ABI 自动提升。
SprintfTest R1-R4 PASS, DefineTest PAGE=4096 验证通过。
This commit is contained in:
TermiNexus committed 2026-08-09 04:06:17 +08:00
1 parent e5a99abb63
commit da23160ca6
1 file changed
+14
+14
View File
@@ -5500,6 +5500,20 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
if fpty is not None:
arg_val = HandlesExpr.coerce_to_type(
builder, arg_val, fpty, arg)
elif found_func.IsVarArg == 1:
# Win64 变参 8 字节槽位:<64 位整数按 i64 传(sext 符号扩展),
# f32 提升为 f64。若按原窄类型传,调用点只写 4 字节进 8 字节槽,
# 高 4 字节残留旧栈数据,va_arg(i64) 读到垃圾(如 DefineTest
# PAGE=%d 读到 0x400921FB00001000,高位是 PI 残留)。
# 对齐 TPC FuncGen/Python-llvmlite 的 ABI 自动提升。
ab_va: int = HandlesExpr.get_llvm_type_bits(arg_val.Ty)
af_va: int = HandlesExpr.get_llvm_float_bits(arg_val.Ty)
i64_va: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
if ab_va != 0 and ab_va < 64:
arg_val = llvmlite.build_sext(builder, arg_val, i64_va)
elif af_va == 32:
arg_val = llvmlite.build_fpext(
builder, arg_val, llvmlite.Double(pool))
arg_val.Next = None
if head is None:
head = arg_val