Commit 50732fe0a5 for qemu.org

commit 50732fe0a56a30db5bbff83899cb9d5b0025ceb5
Author: Max Chou <max.chou@sifive.com>
Date:   Thu Sep 10 20:38:51 2026 +0000

    tcg/riscv64: Validate AUIPC relocation range

    reloc_call splits a PC-relative offset into a signed 12-bit low
    immediate and an AUIPC contribution. When the low immediate carries
    into bit 31, the existing 32-bit arithmetic can accept an unencodable
    positive 0x80000000 AUIPC contribution.

    Keep the split in pointer-width arithmetic and reject it unless the
    rounded upper contribution is representable as signed 32-bit. Factor
    this validation into split_auipc_offset so reloc_call retains its
    existing failure contract.

    Fixes: dfa8e74f9463 ("tcg/riscv: Add the relocation functions")
    Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
    Signed-off-by: Max Chou <max.chou@sifive.com>
    [rth: Pass target as intptr_t to split_auipc_offset.]
    Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

diff --git a/tcg/riscv64/tcg-target.c.inc b/tcg/riscv64/tcg-target.c.inc
index d6c52323c3..99c81dc652 100644
--- a/tcg/riscv64/tcg-target.c.inc
+++ b/tcg/riscv64/tcg-target.c.inc
@@ -640,14 +640,28 @@ static bool reloc_jimm20(tcg_insn_unit *src_rw, const tcg_insn_unit *target)
     return encode_jimm20(src_rw, offset);
 }

-static bool reloc_call(tcg_insn_unit *src_rw, const tcg_insn_unit *target)
+static bool split_auipc_offset(tcg_insn_unit *src_rw, intptr_t target,
+                               int32_t *ret_hi, int32_t *ret_lo)
 {
     const tcg_insn_unit *src_rx = tcg_splitwx_to_rx(src_rw);
-    intptr_t offset = (intptr_t)target - (intptr_t)src_rx;
-    int32_t lo = sextreg(offset, 0, 12);
-    int32_t hi = offset - lo;
+    intptr_t offset = target - (intptr_t)src_rx;
+    int32_t lo = sextract32(offset, 0, 12);
+    intptr_t hi = offset - lo;
+
+    /* AUIPC sign-extends its 20-bit immediate after shifting by 12. */
+    if (hi == (int32_t)hi) {
+        *ret_lo = lo;
+        *ret_hi = hi;
+        return true;
+    }
+    return false;
+}
+
+static bool reloc_call(tcg_insn_unit *src_rw, const tcg_insn_unit *target)
+{
+    int32_t lo, hi;

-    if (offset == hi + lo) {
+    if (split_auipc_offset(src_rw, (intptr_t)target, &hi, &lo)) {
         src_rw[0] |= encode_uimm20(hi);
         src_rw[1] |= encode_imm12(lo);
         return true;