From 3f5258c7db80c100e1b9d566108d15dcdbd3203e Mon Sep 17 00:00:00 2001 From: Wenqiang Wei Date: Wed, 26 Aug 2026 18:07:00 +0800 Subject: [PATCH 1/5] LATX, fix: Restore FCSR state on sigreturn FXSAVE and XSAVE restore the architectural x87 control and status words, but LATX continues with the LoongArch FCSR left by the signal handler. A handler that changes rounding or exception state can therefore affect translated x87 instructions after sigreturn. Rebuild the FCSR rounding, exception enable, and exception flag fields from the restored x87 control and status words. Tests: - Verify x87 round-down survives SIGUSR1 in 32-bit and 64-bit hard-float and LATX_SOFTFPU=1/2 modes Signed-off-by: Wenqiang Wei --- linux-user/i386/signal.c | 3 +++ target/i386/cpu.h | 3 +++ target/i386/tcg/fpu_helper.c | 27 +++++++++++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c index 857a126699c..cb4d24c4f7f 100644 --- a/linux-user/i386/signal.c +++ b/linux-user/i386/signal.c @@ -836,6 +836,9 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc) #endif unlock_user_struct(fpstate, fpstate_addr, 0); #ifdef CONFIG_LATX + if (!err) { + cpu_x86_sync_latx_fcsr(env); + } load_xmm_from_env(env); #endif } else { diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 7a3f8aeb894..c75aa3ef446 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1934,6 +1934,9 @@ void cpu_x86_fxsave(CPUX86State *s, target_ulong ptr); void cpu_x86_fxrstor(CPUX86State *s, target_ulong ptr); void cpu_x86_xsave(CPUX86State *s, target_ulong ptr); void cpu_x86_xrstor(CPUX86State *s, target_ulong ptr); +#ifdef CONFIG_LATX +void cpu_x86_sync_latx_fcsr(CPUX86State *s); +#endif /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c index 1efc9d70b76..b40d433d9b3 100644 --- a/target/i386/tcg/fpu_helper.c +++ b/target/i386/tcg/fpu_helper.c @@ -3222,6 +3222,33 @@ void cpu_x86_xrstor(CPUX86State *env, target_ulong ptr) { do_xrstor(env, ptr, -1, 0); } + +#ifdef CONFIG_LATX +void cpu_x86_sync_latx_fcsr(CPUX86State *env) +{ + static const uint8_t rounding_map[4] = { 0, 3, 2, 1 }; + static const uint8_t exception_map[5] = { 5, 4, 3, 2, 0 }; + uint32_t fpuc = env->fpuc; + uint32_t fpus = env->fpus; + uint32_t rc = (fpuc & FPU_RC_MASK) >> FPU_RC_SHIFT; + uint32_t fcsr = rounding_map[rc] << 8; + int i; + + /* Keep these exception mappings in sync with tr-fctrl.c. */ + for (i = 0; i < 5; i++) { + uint32_t x87_mask = 1 << exception_map[i]; + + if ((!option_enable_fcsr_exc || i != 0) && !(fpuc & x87_mask)) { + fcsr |= 1 << i; + } + if (fpus & x87_mask) { + fcsr |= 1 << (16 + i); + } + } + + env->fcsr = fcsr; +} +#endif #endif uint64_t helper_xgetbv(CPUX86State *env, uint32_t ecx) From 45551c90590eea1c6e7198e05ecda95fdac5ad61 Mon Sep 17 00:00:00 2001 From: Wenqiang Wei Date: Wed, 26 Aug 2026 18:13:48 +0800 Subject: [PATCH 2/5] LATX, fix: Restore x87 mode on sigreturn LATX tracks x87 and MMX execution in the private mode_fpu field, but its saved x87 image does not encode MMX's valid tags and 0xffff exponents. A signal handler can change mode_fpu while the interrupted mode exists only outside the signal frame. In LATX_SOFTFPU=2 mode, subsequent MMX instructions can then read the wrong host register set. Canonicalize MMX state before building the signal frame, recognize its physical-register encoding after restore, and rebuild mode_fpu. Tests: - Verify MMX state survives a SIGUSR1 handler that executes FNINIT in 32-bit and 64-bit hard-float and LATX_SOFTFPU=1/2 modes Signed-off-by: Wenqiang Wei --- linux-user/i386/signal.c | 2 ++ target/i386/cpu.h | 2 ++ target/i386/tcg/fpu_helper.c | 38 ++++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c index cb4d24c4f7f..5943a653112 100644 --- a/linux-user/i386/signal.c +++ b/linux-user/i386/signal.c @@ -454,6 +454,7 @@ static void setup_sigcontext(struct target_sigcontext *sc, CPUState *cs = env_cpu(env); #ifdef CONFIG_LATX save_xmm_to_env(env); + cpu_x86_canonicalize_latx_mmx_state(env); #endif #ifndef TARGET_X86_64 uint16_t magic; @@ -838,6 +839,7 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc) #ifdef CONFIG_LATX if (!err) { cpu_x86_sync_latx_fcsr(env); + cpu_x86_sync_latx_fpu_mode(env); } load_xmm_from_env(env); #endif diff --git a/target/i386/cpu.h b/target/i386/cpu.h index c75aa3ef446..1f1bd730d44 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1935,7 +1935,9 @@ void cpu_x86_fxrstor(CPUX86State *s, target_ulong ptr); void cpu_x86_xsave(CPUX86State *s, target_ulong ptr); void cpu_x86_xrstor(CPUX86State *s, target_ulong ptr); #ifdef CONFIG_LATX +void cpu_x86_canonicalize_latx_mmx_state(CPUX86State *s); void cpu_x86_sync_latx_fcsr(CPUX86State *s); +void cpu_x86_sync_latx_fpu_mode(CPUX86State *s); #endif /* you can call this signal handler from your SIGBUS and SIGSEGV diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c index b40d433d9b3..f5e719196ac 100644 --- a/target/i386/tcg/fpu_helper.c +++ b/target/i386/tcg/fpu_helper.c @@ -3224,6 +3224,39 @@ void cpu_x86_xrstor(CPUX86State *env, target_ulong ptr) } #ifdef CONFIG_LATX +void cpu_x86_canonicalize_latx_mmx_state(CPUX86State *env) +{ + int i; + + if (env->mode_fpu) { + return; + } + + env->fpstt = 0; + memset(env->fptags, 0, sizeof(env->fptags)); + for (i = 0; i < 8; i++) { + CPU_LDoubleU reg = { .d = env->fpregs[i].d }; + + reg.l.upper = 0xffff; + env->fpregs[i].d = reg.d; + } +} + +static bool latx_x87_state_is_mmx(const CPUX86State *env) +{ + int i; + + /* MMX sets every x87 tag valid and every physical exponent to 0xffff. */ + for (i = 0; i < 8; i++) { + CPU_LDoubleU reg = { .d = env->fpregs[i].d }; + + if (env->fptags[i] || reg.l.upper != 0xffff) { + return false; + } + } + return true; +} + void cpu_x86_sync_latx_fcsr(CPUX86State *env) { static const uint8_t rounding_map[4] = { 0, 3, 2, 1 }; @@ -3248,6 +3281,11 @@ void cpu_x86_sync_latx_fcsr(CPUX86State *env) env->fcsr = fcsr; } + +void cpu_x86_sync_latx_fpu_mode(CPUX86State *env) +{ + env->mode_fpu = !latx_x87_state_is_mmx(env); +} #endif #endif From 49a31b8402f283a6c907c0f7fb6679298f95a35a Mon Sep 17 00:00:00 2001 From: Wenqiang Wei Date: Wed, 26 Aug 2026 18:17:01 +0800 Subject: [PATCH 3/5] linux-user, fix: Initialize x87 state for signal handlers The 64-bit signal path saves interrupted state with non-destructive FXSAVE or XSAVE, then enters the handler without initializing live x87 state. The handler consequently observes the interrupted x87 stack and control state. Initialize only x87 after successfully building the signal frame. Do not change MXCSR or vector and extended state, and leave the frame unchanged so sigreturn restores the interrupted state. Tests: - Verify a 64-bit SIGUSR1 handler starts with initial x87 state while non-x87 state remains unchanged and sigreturn restores saved state - Verify 32-bit and 64-bit x87 state survives SIGUSR1 in hard-float and LATX_SOFTFPU=1/2 modes Signed-off-by: Wenqiang Wei --- linux-user/i386/signal.c | 4 ++++ target/i386/cpu.h | 1 + target/i386/tcg/fpu_helper.c | 10 ++++++++++ 3 files changed, 15 insertions(+) diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c index 5943a653112..4b5b8992bb1 100644 --- a/linux-user/i386/signal.c +++ b/linux-user/i386/signal.c @@ -639,6 +639,8 @@ void setup_frame(int sig, struct target_sigaction *ka, unlock_user_struct(frame, frame_addr, 1); + cpu_x86_init_user_x87(env); + return; give_sigsegv: @@ -729,6 +731,8 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, unlock_user_struct(frame, frame_addr, 1); + cpu_x86_init_user_x87(env); + return; give_sigsegv: diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 1f1bd730d44..19529e95810 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1934,6 +1934,7 @@ void cpu_x86_fxsave(CPUX86State *s, target_ulong ptr); void cpu_x86_fxrstor(CPUX86State *s, target_ulong ptr); void cpu_x86_xsave(CPUX86State *s, target_ulong ptr); void cpu_x86_xrstor(CPUX86State *s, target_ulong ptr); +void cpu_x86_init_user_x87(CPUX86State *s); #ifdef CONFIG_LATX void cpu_x86_canonicalize_latx_mmx_state(CPUX86State *s); void cpu_x86_sync_latx_fcsr(CPUX86State *s); diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c index f5e719196ac..a7b526e81d2 100644 --- a/target/i386/tcg/fpu_helper.c +++ b/target/i386/tcg/fpu_helper.c @@ -3287,6 +3287,16 @@ void cpu_x86_sync_latx_fpu_mode(CPUX86State *env) env->mode_fpu = !latx_x87_state_is_mmx(env); } #endif + +void cpu_x86_init_user_x87(CPUX86State *env) +{ + do_fninit(env); + +#ifdef CONFIG_LATX + env->fcsr = 0; + env->mode_fpu = 1; +#endif +} #endif uint64_t helper_xgetbv(CPUX86State *env, uint32_t ecx) From 8c089a183a9f7824eb866e90aa58e3ef79510bab Mon Sep 17 00:00:00 2001 From: Hanlu Li Date: Sat, 12 Sep 2026 10:26:01 +0800 Subject: [PATCH 4/5] LATX, fix: Preserve soft x87 ownership after sigreturn A full x87 stack of negative NaNs or infinities has the same tags and exponents as MMX. Inferring MMX mode lets syscalls overwrite softfpu=2 x87 writes with stale host MMX registers and lets a second signal corrupt softfpu=1 x87 state. Keep restored soft-float state env-owned until MMX/EMMS explicitly selects a mode. Full softfpu=2 reentry reloads the MMX view without allowing it to overwrite env; partial helper reloads leave the restored state alone. Softfpu=1 already reloads its host register view unconditionally. Add explicit integration cases for negative NaNs/infinities, consecutive signals, all eight MMX registers, handler initialization and rounding restore across softfpu=0/1/2 and TB/TU execution. Native x86 passes all five fixtures. LoongArch master passes the negative-NaN regression; unmodified PR436 exits 22 after getpid changes 1.0 to 1.508888840675354. Signed-off-by: Hanlu Li --- target/i386/cpu.h | 11 +- target/i386/latx/translator/translate.c | 10 +- target/i386/tcg/fpu_helper.c | 16 +- tests/README.md | 27 +++ .../registrations/process/meson.build | 9 + tests/integration/test-x87-signal-mode.sh | 47 ++++++ tests/integration/x87-signal-mode.S | 159 ++++++++++++++++++ 7 files changed, 275 insertions(+), 4 deletions(-) create mode 100755 tests/integration/test-x87-signal-mode.sh create mode 100644 tests/integration/x87-signal-mode.S diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 19529e95810..26aa3111527 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1211,6 +1211,15 @@ typedef union { MMXReg mmx; } FPReg; +#ifdef CONFIG_LATX +enum { + LATX_FPU_MODE_MMX, + LATX_FPU_MODE_X87, + /* Reload the MMX view on reentry; the restored env stays authoritative. */ + LATX_FPU_MODE_RESTORED, +}; +#endif + typedef struct { uint64_t base; uint64_t mask; @@ -1424,7 +1433,7 @@ typedef struct CPUX86State { int func_index; int last_func_index; #endif - bool mode_fpu; + uint8_t mode_fpu; bool fpu_clobber; #endif /* standard registers */ diff --git a/target/i386/latx/translator/translate.c b/target/i386/latx/translator/translate.c index 0125e1c6ab0..fe0d812312e 100644 --- a/target/i386/latx/translator/translate.c +++ b/target/i386/latx/translator/translate.c @@ -3870,8 +3870,14 @@ void tr_load_registers_from_env(uint8 gpr_to_load, uint8 fpr_to_load, /* check current mode(mmx/fpu) */ if (option_softfpu == 2) { - la_ld_wu(mode_fpu, env_ir2_opnd, lsenv_offset_of_mode_fpu(lsenv)); - la_bne(mode_fpu, zero_ir2_opnd, label_fpu); + la_ld_bu(mode_fpu, env_ir2_opnd, lsenv_offset_of_mode_fpu(lsenv)); + if (fpr_to_load == 0xff) { + /* A signal restore must initialize MMX without selecting it. */ + la_xori(mode_fpu, mode_fpu, LATX_FPU_MODE_X87); + la_beq(mode_fpu, zero_ir2_opnd, label_fpu); + } else { + la_bne(mode_fpu, zero_ir2_opnd, label_fpu); + } } for (i = 0; i < 8; i++) { diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c index a7b526e81d2..b7312190038 100644 --- a/target/i386/tcg/fpu_helper.c +++ b/target/i386/tcg/fpu_helper.c @@ -3284,7 +3284,21 @@ void cpu_x86_sync_latx_fcsr(CPUX86State *env) void cpu_x86_sync_latx_fpu_mode(CPUX86State *env) { - env->mode_fpu = !latx_x87_state_is_mmx(env); + /* + * MMX and a full x87 stack of negative NaNs/infinities have identical + * tag/exponent encodings. In softfpu=2 the architectural state lives + * in env, whereas MMX uses host registers. Load the latter on reentry + * without allowing their stale contents to overwrite subsequent x87 + * writes. Keep this state until MMX/EMMS explicitly selects a mode: + * translation/dispatch may clobber host MMX before the first guest use. + * Softfpu=1 already reloads MMX on every reentry, but must also avoid + * canonicalizing a negative-NaN x87 stack on a subsequent signal. + */ + if (option_softfpu) { + env->mode_fpu = LATX_FPU_MODE_RESTORED; + } else { + env->mode_fpu = !latx_x87_state_is_mmx(env); + } } #endif diff --git a/tests/README.md b/tests/README.md index 568cecf6a94..9fb43b4f4a2 100644 --- a/tests/README.md +++ b/tests/README.md @@ -104,6 +104,33 @@ and then run tests with the bundled `meson/meson.py`, or vice versa. To run the integration suite, replace `lat-pr-fast` with `latx-integration`. +The `test-x87-signal-mode` integration test builds five static x86-64 guests +with Clang/LLD only when explicitly run. On a target without that compiler, +build the same source on an x86-64 Linux host: + +```sh +mkdir -p x87-guests +for case_id in 0 1 2 3 4; do + gcc -nostdlib -static -no-pie -DCASE=$case_id \ + tests/integration/x87-signal-mode.S \ + -o x87-guests/x87-signal-mode-$case_id +done +``` + +Copy `x87-guests` to the LoongArch target, then run: + +```sh +LATX_X87_SIGNAL_GUEST_DIR=/absolute/path/to/x87-guests \ + meson test -C build64-tests --suite latx-integration \ + test-x87-signal-mode --print-errorlogs +``` + +The cases cover full x87 stacks of negative NaNs and infinities, a second +signal after an x87 write, MMX restoration, and x87 handler initialization +and rounding restoration. Each runs in hard-float and softfpu=1/2, with +both TB and TU translation. Compile the fixtures from the same checkout +being tested; a supplied directory with a missing executable is a failure. + Before submitting a new test target, verify both of these: 1. A normal product build without `--enable-tests` does not build the test. diff --git a/tests/integration/registrations/process/meson.build b/tests/integration/registrations/process/meson.build index 0513ccc7c13..93c24cd0bfe 100644 --- a/tests/integration/registrations/process/meson.build +++ b/tests/integration/registrations/process/meson.build @@ -1,4 +1,13 @@ if 'x86_64-linux-user' in target_dirs + latx_integration_tests += [{ + 'name': 'test-x87-signal-mode', + 'runner': find_program('../../test-x87-signal-mode.sh'), + 'args': [ + emulators['latx-x86_64'], + files('../../x87-signal-mode.S'), + ], + 'timeout': 120, + }] latx_integration_tests += [{ 'name': 'test-proc-readdir', 'runner': find_program('../../test-proc-readdir.sh'), diff --git a/tests/integration/test-x87-signal-mode.sh b/tests/integration/test-x87-signal-mode.sh new file mode 100755 index 00000000000..d3be0ce6ce4 --- /dev/null +++ b/tests/integration/test-x87-signal-mode.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-only +set -eu + +emulator=$(readlink -f "$1") +source_file=$(readlink -f "$2") +workdir=$(mktemp -d) +trap 'rm -rf "$workdir"' EXIT HUP INT TERM + +guest_dir=${LATX_X87_SIGNAL_GUEST_DIR:-$workdir} +if [ -n "${LATX_X87_SIGNAL_GUEST_DIR:-}" ]; then + : # Allow guests built from this source on an x86 build host. +elif command -v clang-19 >/dev/null 2>&1; then + clang=clang-19 +elif command -v clang >/dev/null 2>&1; then + clang=clang +else + echo "SKIP: clang is required to build the x86_64 guest" + exit 77 +fi + +for case_id in 0 1 2 3 4; do + guest="$guest_dir/x87-signal-mode-$case_id" + if [ -z "${LATX_X87_SIGNAL_GUEST_DIR:-}" ]; then + "$clang" --target=x86_64-linux-gnu -fuse-ld=lld -nostdlib -static \ + -Wl,--build-id=none -DCASE=$case_id "$source_file" -o "$guest" + fi + if [ ! -x "$guest" ]; then + echo "FAIL: guest executable missing: $guest" >&2 + exit 1 + fi + for softfpu in 0 1 2; do + for tu in 0 1; do + if LATX_AOT=0 LATX_MT=0 LATX_TU=$tu LATX_SOFTFPU=$softfpu \ + timeout -s KILL 10 "$emulator" "$guest" \ + > "$workdir/result"; then + echo "PASS: x87 signal case=$case_id softfpu=$softfpu tu=$tu" + else + status=$? + printf 'FAIL: case=%s softfpu=%s tu=%s exit=%s\n' \ + "$case_id" "$softfpu" "$tu" "$status" >&2 + od -An -tx1 "$workdir/result" >&2 + exit "$status" + fi + done + done +done diff --git a/tests/integration/x87-signal-mode.S b/tests/integration/x87-signal-mode.S new file mode 100644 index 00000000000..f3f25c07acb --- /dev/null +++ b/tests/integration/x87-signal-mode.S @@ -0,0 +1,159 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * Static x86-64 Linux guest. + * Exit 0: fld1 survives getpid after SIGUSR1. Exit 22: value corrupted. + * stdout is two raw 80-bit values: before and after the getpid syscall. + * CASE: 0 = negative NaNs, 1 = negative infinities, 2 = second signal, + * 3 = MMX restore, 4 = x87 handler entry and rounding restore. + */ +#ifndef CASE +#define CASE 0 +#endif +.section .data +.balign 8 +action: + .quad handler, 0x04000000, restorer, 0 +negative_nan: +#if CASE == 1 + .quad 0x8000000000000000 +#else + .quad 0xc123450000000000 +#endif + .word 0xffff +mmx_value: + .quad 0x0123456789abcdef +round_down: .word 0x077f +fraction: .quad 0x3ffc000000000000 /* double 1.75 */ +.section .bss +.balign 16 +observed: .skip 20 +seen: .skip 4 +handler_cw: .skip 2 +handler_sw: .skip 2 +integer: .skip 4 +.section .text +.global _start +_start: + mov $13, %eax + mov $10, %edi + lea action(%rip), %rsi + xor %edx, %edx + mov $8, %r10d + syscall + test %rax, %rax + js setup_failed + mov $39, %eax + syscall + mov %eax, %r12d + fninit +#if CASE == 3 + movq mmx_value(%rip), %mm0 + movq %mm0, %mm1 + movq %mm0, %mm2 + movq %mm0, %mm3 + movq %mm0, %mm4 + movq %mm0, %mm5 + movq %mm0, %mm6 + movq %mm0, %mm7 +#elif CASE == 4 + fldcw round_down(%rip) + fld1 +#else + .rept 8 + fldt negative_nan(%rip) + .endr +#endif + mov $62, %eax + mov %r12d, %edi + mov $10, %esi + syscall + cmpl $1, seen(%rip) + jne setup_failed +#if CASE == 3 + mov mmx_value(%rip), %rdx + .irp n,0,1,2,3,4,5,6,7 + movq %mm\n, %rax + cmp %rdx, %rax + jne corrupted + .endr + emms + xor %edi, %edi + jmp finish +#elif CASE == 4 + cmpw $0x037f, handler_cw(%rip) + jne precheck_failed + cmpw $0, handler_sw(%rip) + jne precheck_failed + fstpt observed(%rip) + movabs $0x8000000000000000, %rax + cmp %rax, observed(%rip) + jne corrupted + cmpw $0x3fff, observed+8(%rip) + jne corrupted + fldl fraction(%rip) + fistpl integer(%rip) + cmpl $1, integer(%rip) + jne corrupted + xor %edi, %edi + jmp finish +#else + fstp %st(0) + fld1 + fstpt observed(%rip) + fldt observed(%rip) +#if CASE == 2 + mov $62, %eax + mov %r12d, %edi + mov $10, %esi + syscall + cmpl $2, seen(%rip) + jne setup_failed +#endif + mov $39, %eax + syscall + fstpt observed+10(%rip) + mov $1, %eax + mov $1, %edi + lea observed(%rip), %rsi + mov $20, %edx + syscall + movabs $0x8000000000000000, %rax + cmp %rax, observed(%rip) + jne precheck_failed + cmpw $0x3fff, observed+8(%rip) + jne precheck_failed + cmp %rax, observed+10(%rip) + jne corrupted + cmpw $0x3fff, observed+18(%rip) + jne corrupted + xor %edi, %edi + jmp finish +#endif +setup_failed: + mov $20, %edi + jmp finish +precheck_failed: + mov $21, %edi + jmp finish +corrupted: + mov $22, %edi +finish: + mov $60, %eax + syscall +handler: +#if CASE == 3 + .irp n,0,1,2,3,4,5,6,7 + pxor %mm\n, %mm\n + .endr + emms + fninit +#elif CASE == 4 + fnstcw handler_cw(%rip) + fnstsw handler_sw(%rip) + fninit +#endif + incl seen(%rip) + ret +restorer: + mov $15, %eax + syscall +.section .note.GNU-stack,"",@progbits From a39fa0d44e5dec66ba7787e50acc250ee82232ce Mon Sep 17 00:00:00 2001 From: Hanlu Li Date: Sat, 12 Sep 2026 11:00:22 +0800 Subject: [PATCH 5/5] LATX, fix: Guard 32-bit page-check temporaries required_flag and label_check_end are consumed only by the TARGET_ABI_BITS == 32 guest-page fast path. Their unconditional declarations make 64-bit release and debug builds fail with -Werror=unused-variable. Guard both declarations with the same ABI condition as their uses. Keep the 32-bit page permission checks unchanged. Tests: - LoongArch translate.c -O0/-O2 with -Werror: both fail before the guards and both pass after them - x86_64 product build with Meson werror=true: pass - Complete lat-pr-fast suite: 28/28 pass, no skips - x87 signal integration matrix: 30/30 pass, no skips Signed-off-by: Hanlu Li --- target/i386/latx/translator/translate.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target/i386/latx/translator/translate.c b/target/i386/latx/translator/translate.c index 170a015ff8d..5c70cacd114 100644 --- a/target/i386/latx/translator/translate.c +++ b/target/i386/latx/translator/translate.c @@ -4326,7 +4326,9 @@ static inline void helper_restore_reg(IR2_OPND opnd) void gen_test_page_flag(IR2_OPND mem_opnd, int mem_imm, uint32_t flag, unsigned int mem_size) { +#if TARGET_ABI_BITS == 32 uint32_t required_flag = flag & PAGE_WRITE ? PAGE_WRITE : PAGE_READ; +#endif if (!option_mem_test) { #if TARGET_ABI_BITS == 32 @@ -4357,7 +4359,9 @@ void gen_test_page_flag(IR2_OPND mem_opnd, int mem_imm, uint32_t flag, IR2_OPND label1 = ra_alloc_label(); IR2_OPND label2 = ra_alloc_label(); IR2_OPND label_fault = ra_alloc_label(); +#if TARGET_ABI_BITS == 32 IR2_OPND label_check_end = ra_alloc_label(); +#endif bool need_restore0 = false; bool need_restore1 = false; bool need_restore2 = false;