[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