[PATCH 2/2] tcg/mips64: Preserve the base of unaligned loads

Richard Henderson <[email protected]>
Newsgroups gmane.comp.emulators.qemu
Message-ID <[email protected]>
From: Quintin Kong <[email protected]>

The qemu_ld output constraint permits the output register to overlap a
dead address input. That is valid for a direct load, but a pre-R6 MIPS
host implements an unaligned 32-bit or 64-bit load with an LWR/LWL or
LDR/LDL pair. Both instructions require the original base address.

If lo and base overlap, the first instruction replaces the base with
part of the loaded value. The second instruction then accesses an
unrelated address.

Prior to eb664d0c527, the address register was always a temporary,
so this problem never occured.  Copy an overlapping base to TCG_TMP0.

Fixes: eb664d0c527 ("tcg/mips: Rationalize args to tcg_out_qemu_{ld,st}")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4102
Signed-off-by: Quintin Kong <[email protected]>
[rth: Move fixup into tcg_out_qemu_ld_unalign for qemu 10 series]
Signed-off-by: Richard Henderson <[email protected]>
Message-ID: <[email protected]>
---
 tcg/mips/tcg-target.c.inc | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc
index 29cf7fa0ab..a683bff625 100644
--- a/tcg/mips/tcg-target.c.inc
+++ b/tcg/mips/tcg-target.c.inc
@@ -1338,9 +1338,9 @@ static void tcg_out_qemu_ld_unalign(TCGContext *s, TCGReg lo, TCGReg hi,
     const MIPSInsn ld1 = HOST_BIG_ENDIAN ? OPC_LDL : OPC_LDR;
     const MIPSInsn ld2 = HOST_BIG_ENDIAN ? OPC_LDR : OPC_LDL;
     bool sgn = opc & MO_SIGN;
+    MemOp size = opc & MO_SIZE;
 
-    switch (opc & MO_SIZE) {
-    case MO_16:
+    if (size == MO_16) {
         if (HOST_BIG_ENDIAN) {
             tcg_out_opc_imm(s, sgn ? OPC_LB : OPC_LBU, TCG_TMP0, base, 0);
             tcg_out_opc_imm(s, OPC_LBU, lo, base, 1);
@@ -1360,8 +1360,16 @@ static void tcg_out_qemu_ld_unalign(TCGContext *s, TCGReg lo, TCGReg hi,
             tcg_out_opc_sa(s, OPC_SLL, TCG_TMP1, TCG_TMP1, 8);
             tcg_out_opc_reg(s, OPC_OR, lo, TCG_TMP0, TCG_TMP1);
         }
-        break;
+        return;
+    }
 
+    /* Both loads in the unaligned pair require the original base. */
+    if (lo == base) {
+        tcg_out_mov(s, TCG_TYPE_PTR, TCG_TMP0, base);
+        base = TCG_TMP0;
+    }
+
+    switch (size) {
     case MO_32:
         tcg_out_opc_imm(s, lw1, lo, base, 0);
         tcg_out_opc_imm(s, lw2, lo, base, 3);
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.