ZJIT: x86: Fix panic writing 32-bit number with top bit set
Previously, `asm.mov(m32, imm32)` panicked when `imm32 > 0x80000000`. It attempted to split imm32 into a register before doing the store, but then the register size didn't match the destination size. Instead of splitting, use the `MOV r/m32, imm32` form which works for all 32-bit values. Adjust asserts that assumed that all forms undergo sign extension, which is not true for this case. See: 54edc930f9f0a658da45cfcef46648d1b6f82467
This commit is contained in:
parent
e5c7f1695e
commit
59fad961b8
Notes:
git
2025-06-11 10:50:02 +00:00
@ -1024,7 +1024,10 @@ pub fn mov(cb: &mut CodeBlock, dst: X86Opnd, src: X86Opnd) {
|
||||
}
|
||||
|
||||
let output_num_bits:u32 = if mem.num_bits > 32 { 32 } else { mem.num_bits.into() };
|
||||
assert!(imm_num_bits(imm.value) <= (output_num_bits as u8));
|
||||
assert!(
|
||||
mem.num_bits < 64 || imm_num_bits(imm.value) <= (output_num_bits as u8),
|
||||
"immediate value should be small enough to survive sign extension"
|
||||
);
|
||||
cb.write_int(imm.value as u64, output_num_bits);
|
||||
},
|
||||
// M + UImm
|
||||
@ -1039,7 +1042,10 @@ pub fn mov(cb: &mut CodeBlock, dst: X86Opnd, src: X86Opnd) {
|
||||
}
|
||||
|
||||
let output_num_bits = if mem.num_bits > 32 { 32 } else { mem.num_bits.into() };
|
||||
assert!(imm_num_bits(uimm.value as i64) <= (output_num_bits as u8));
|
||||
assert!(
|
||||
mem.num_bits < 64 || imm_num_bits(uimm.value as i64) <= (output_num_bits as u8),
|
||||
"immediate value should be small enough to survive sign extension"
|
||||
);
|
||||
cb.write_int(uimm.value, output_num_bits);
|
||||
},
|
||||
// * + Imm/UImm
|
||||
|
@ -193,6 +193,7 @@ fn test_mov() {
|
||||
check_bytes("48c7470801000000", |cb| mov(cb, mem_opnd(64, RDI, 8), imm_opnd(1)));
|
||||
//check_bytes("67c7400411000000", |cb| mov(cb, mem_opnd(32, EAX, 4), imm_opnd(0x34))); // We don't distinguish between EAX and RAX here - that's probably fine?
|
||||
check_bytes("c7400411000000", |cb| mov(cb, mem_opnd(32, RAX, 4), imm_opnd(17)));
|
||||
check_bytes("c7400401000080", |cb| mov(cb, mem_opnd(32, RAX, 4), uimm_opnd(0x80000001)));
|
||||
check_bytes("41895814", |cb| mov(cb, mem_opnd(32, R8, 20), EBX));
|
||||
check_bytes("4d8913", |cb| mov(cb, mem_opnd(64, R11, 0), R10));
|
||||
check_bytes("48c742f8f4ffffff", |cb| mov(cb, mem_opnd(64, RDX, -8), imm_opnd(-12)));
|
||||
|
@ -298,19 +298,24 @@ impl Assembler
|
||||
let opnd1 = asm.load(*src);
|
||||
asm.mov(*dest, opnd1);
|
||||
},
|
||||
(Opnd::Mem(_), Opnd::UImm(value)) => {
|
||||
// 32-bit values will be sign-extended
|
||||
if imm_num_bits(*value as i64) > 32 {
|
||||
(Opnd::Mem(Mem { num_bits, .. }), Opnd::UImm(value)) => {
|
||||
// For 64 bit destinations, 32-bit values will be sign-extended
|
||||
if *num_bits == 64 && imm_num_bits(*value as i64) > 32 {
|
||||
let opnd1 = asm.load(*src);
|
||||
asm.mov(*dest, opnd1);
|
||||
} else {
|
||||
asm.mov(*dest, *src);
|
||||
}
|
||||
},
|
||||
(Opnd::Mem(_), Opnd::Imm(value)) => {
|
||||
if imm_num_bits(*value) > 32 {
|
||||
(Opnd::Mem(Mem { num_bits, .. }), Opnd::Imm(value)) => {
|
||||
// For 64 bit destinations, 32-bit values will be sign-extended
|
||||
if *num_bits == 64 && imm_num_bits(*value) > 32 {
|
||||
let opnd1 = asm.load(*src);
|
||||
asm.mov(*dest, opnd1);
|
||||
} else if uimm_num_bits(*value as u64) <= *num_bits {
|
||||
// If the bit string is short enough for the destination, use the unsigned representation.
|
||||
// Note that 64-bit and negative values are ruled out.
|
||||
asm.mov(*dest, Opnd::UImm(*value as u64));
|
||||
} else {
|
||||
asm.mov(*dest, *src);
|
||||
}
|
||||
@ -1294,4 +1299,19 @@ mod tests {
|
||||
0x13: mov qword ptr [rbx], rax
|
||||
"});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mov_m32_imm32() {
|
||||
let (mut asm, mut cb) = setup_asm();
|
||||
|
||||
let shape_opnd = Opnd::mem(32, C_RET_OPND, 0);
|
||||
asm.mov(shape_opnd, Opnd::UImm(0x8000_0001));
|
||||
asm.mov(shape_opnd, Opnd::Imm(0x8000_0001));
|
||||
|
||||
asm.compile_with_num_regs(&mut cb, 0);
|
||||
assert_disasm!(cb, "c70001000080c70001000080", {"
|
||||
0x0: mov dword ptr [rax], 0x80000001
|
||||
0x6: mov dword ptr [rax], 0x80000001
|
||||
"});
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user