From 222fe3258c1a39170bc1929a367c65068725f5d2 Mon Sep 17 00:00:00 2001 From: Corbin Crutchley Date: Fri, 24 Jul 2026 08:14:59 -0700 Subject: [PATCH] fix: preserve signed narrow load semantics --- crates/aarch64/src/lib.rs | 64 +++++++++++++++++++ .../ghidra-aarch64/languages/AARCH64base.sinc | 25 +++++--- 2 files changed, 80 insertions(+), 9 deletions(-) diff --git a/crates/aarch64/src/lib.rs b/crates/aarch64/src/lib.rs index 117f026..3e384df 100644 --- a/crates/aarch64/src/lib.rs +++ b/crates/aarch64/src/lib.rs @@ -2203,6 +2203,18 @@ mod tests { 0x08, 0x01, 0x93, 0x9a, // csel x8, x8, x19, eq 0x01, 0x15, 0x00, 0x38, // strb w1, [x8], #1 ]; + const CPYTHON_EXCEPTION_SELECTION_CODE: &[u8] = &[ + 0x5f, 0x01, 0x1a, 0x72, // tst w10, #0x40 + 0x60, 0x02, 0x89, 0x9a, // csel x0, x19, x9, eq + ]; + const CPYTHON_SIGNED_BYTE_LOAD_CODE: &[u8] = &[ + 0x2c, 0x01, 0xc0, 0x39, // ldrsb w12, [x9] + 0x2d, 0xf1, 0xdf, 0x38, // ldursb w13, [x9, #-1] + ]; + const CPYTHON_SIGNED_HALFWORD_LOAD_CODE: &[u8] = &[ + 0x2c, 0x01, 0xc0, 0x79, // ldrsh w12, [x9] + 0x2d, 0xe1, 0xdf, 0x78, // ldursh w13, [x9, #-2] + ]; const RUST_ATOMIC_CODE: &[u8] = &[ 0x40, 0x7c, 0x5f, 0xc8, // ldxr x0, [x2] 0x41, 0x7c, 0x11, 0xc8, // stxr w17, x1, [x2] @@ -2373,6 +2385,58 @@ mod tests { } } + #[test] + fn executes_cpython_exception_type_selection_semantics() { + for (type_flags, selected, nzcv) in [ + (0, 0x1919, 0x4000_0000), + (0x40, 0x0909, 0), + (0xc0, 0x0909, 0), + ] { + let mut memory = executable_memory(CPYTHON_EXCEPTION_SELECTION_CODE); + let mut state = Aarch64State::new(CODE_ADDRESS, GuestAddress::new(0x8000)); + state.set_x(9, 0x0909).unwrap(); + state.set_x(10, type_flags).unwrap(); + state.set_x(19, 0x1919).unwrap(); + let mut interpreter = Interpreter::new().unwrap(); + + interpreter.step(&mut state, &mut memory).unwrap(); + assert_eq!(state.nzcv(), nzcv); + interpreter.step(&mut state, &mut memory).unwrap(); + assert_eq!(state.x(0), Some(selected)); + } + } + + #[test] + fn sign_extends_narrow_loads_into_w_registers() { + let mut memory = executable_memory_with_stack(CPYTHON_SIGNED_BYTE_LOAD_CODE); + memory + .write(GuestAddress::new(0x7000), &[0xa1, 0xa2]) + .unwrap(); + let mut state = Aarch64State::new(CODE_ADDRESS, GuestAddress::new(0x8000)); + state.set_x(9, 0x7001).unwrap(); + let mut interpreter = Interpreter::new().unwrap(); + + interpreter.step(&mut state, &mut memory).unwrap(); + interpreter.step(&mut state, &mut memory).unwrap(); + + assert_eq!(state.x(12), Some(0xffff_ffa2)); + assert_eq!(state.x(13), Some(0xffff_ffa1)); + + let mut memory = executable_memory_with_stack(CPYTHON_SIGNED_HALFWORD_LOAD_CODE); + memory + .write(GuestAddress::new(0x7000), &[0x01, 0x80, 0x02, 0x80]) + .unwrap(); + let mut state = Aarch64State::new(CODE_ADDRESS, GuestAddress::new(0x8000)); + state.set_x(9, 0x7002).unwrap(); + let mut interpreter = Interpreter::new().unwrap(); + + interpreter.step(&mut state, &mut memory).unwrap(); + interpreter.step(&mut state, &mut memory).unwrap(); + + assert_eq!(state.x(12), Some(0xffff_8002)); + assert_eq!(state.x(13), Some(0xffff_8001)); + } + #[test] fn executes_rust_atomic_and_integer_semantics() { let mut memory = executable_memory_with_stack(RUST_ATOMIC_CODE); diff --git a/third_party/ghidra-aarch64/languages/AARCH64base.sinc b/third_party/ghidra-aarch64/languages/AARCH64base.sinc index 194b37a..392862f 100644 --- a/third_party/ghidra-aarch64/languages/AARCH64base.sinc +++ b/third_party/ghidra-aarch64/languages/AARCH64base.sinc @@ -3280,7 +3280,8 @@ is size.ldstr=1 & b_2729=7 & v=0 & b_2425=0 & b_23=0 & b_2222=1 & b_2121=1 & b_1 :ldrsb Rt_GPR32, addrIndexed is size.ldstr=0 & b_2729=7 & v=0 & b_2425=1 & b_2223=3 & addrIndexed & Rt_GPR32 & Rt_GPR64 { - Rt_GPR64 = sext(*:1 addrIndexed); + local tmp:4 = sext(*:1 addrIndexed); + Rt_GPR64 = zext(tmp); } # C6.2.174 LDRSB (immediate) page C6-1572 line 93336 MATCH x38800400/mask=xffa00c00 @@ -3293,7 +3294,8 @@ is size.ldstr=0 & b_2729=7 & v=0 & b_2425=1 & b_2223=3 & addrIndexed & Rt_GPR32 :ld^UnscPriv^"rsb" Rt_GPR32, addrIndexed is size.ldstr=0 & b_2729=7 & v=0 & b_2425=0 & b_2223=3 & b_2121=0 & UnscPriv & addrIndexed & Rt_GPR32 & Rt_GPR64 { - Rt_GPR64 = zext(*:1 addrIndexed); + local tmp:4 = sext(*:1 addrIndexed); + Rt_GPR64 = zext(tmp); } # C6.2.174 LDRSB (immediate) page C6-1572 line 93336 MATCH x38800400/mask=xffa00c00 @@ -3304,7 +3306,8 @@ is size.ldstr=0 & b_2729=7 & v=0 & b_2425=0 & b_2223=3 & b_2121=0 & UnscPriv & a :ldrsb Rt_GPR32, addrIndexed is size.ldstr=0 & b_2729=7 & v=0 & b_2425=0 & b_2223=3 & b_2121=0 & b_1010=1 & addrIndexed & Rt_GPR32 & Rt_GPR64 { - Rt_GPR64 = sext(*:1 addrIndexed); + local tmp:4 = sext(*:1 addrIndexed); + Rt_GPR64 = zext(tmp); } # C6.2.174 LDRSB (immediate) page C6-1572 line 93336 MATCH x39800000/mask=xff800000 @@ -3348,7 +3351,8 @@ is size.ldstr=0 & b_2729=7 & v=0 & b_2425=0 & b_2223=2 & b_2121=0 & b_1010=1 & a :ldrsb Rt_GPR32, addrIndexed is size.ldstr=0 & b_2729=7 & v=0 & b_2425=0 & b_2223=3 & b_2121=1 & b_1011=2 & addrIndexed & Rt_GPR32 & Rt_GPR64 { - Rt_GPR64 = sext(*:1 addrIndexed); + local tmp:4 = sext(*:1 addrIndexed); + Rt_GPR64 = zext(tmp); } # C6.2.175 LDRSB (register) page C6-1576 line 93573 MATCH x38a00800/mask=xffa00c00 @@ -3368,7 +3372,8 @@ is size.ldstr=0 & b_2729=7 & v=0 & b_2425=0 & b_2223=2 & b_2121=1 & b_1011=2 & a :ldrsh Rt_GPR32, addrUIMM is size.ldstr=1 & b_2729=7 & v=0 & b_2425=1 & b_2223=3 & addrUIMM & Rn_GPR64xsp & Rt_GPR32 & Rt_GPR64 { - Rt_GPR64 = sext(*:2 addrUIMM); + local tmp:4 = sext(*:2 addrUIMM); + Rt_GPR64 = zext(tmp); } # C6.2.176 LDRSH (immediate) page C6-1578 line 93714 MATCH x78800400/mask=xffa00c00 @@ -3381,7 +3386,8 @@ is size.ldstr=1 & b_2729=7 & v=0 & b_2425=1 & b_2223=3 & addrUIMM & Rn_GPR64xsp :ld^UnscPriv^"rsh" Rt_GPR32, addrIndexed is size.ldstr=1 & b_2729=7 & v=0 & b_2425=0 & b_2223=3 & b_2121=0 & UnscPriv & addrIndexed & Rt_GPR32 & Rt_GPR64 { - Rt_GPR64 = sext(*:2 addrIndexed); + local tmp:4 = sext(*:2 addrIndexed); + Rt_GPR64 = zext(tmp); } # C6.2.176 LDRSH (immediate) page C6-1578 line 93714 MATCH x78800400/mask=xffa00c00 @@ -3392,7 +3398,8 @@ is size.ldstr=1 & b_2729=7 & v=0 & b_2425=0 & b_2223=3 & b_2121=0 & UnscPriv & a :ldrsh Rt_GPR32, addrIndexed is size.ldstr=1 & b_2729=7 & v=0 & b_2425=0 & b_2223=3 & b_2121=0 & b_1010=1 & addrIndexed & Rt_GPR32 & Rt_GPR64 { - Rt_GPR64 = sext(*:2 addrIndexed); + local tmp:4 = sext(*:2 addrIndexed); + Rt_GPR64 = zext(tmp); } # C6.2.176 LDRSH (immediate) page C6-1578 line 93714 MATCH x79800000/mask=xff800000 @@ -3436,7 +3443,8 @@ is size.ldstr=1 & b_2729=7 & v=0 & b_2425=0 & b_2223=2 & b_2121=0 & b_1010=1 & a :ldrsh Rt_GPR32, addrIndexed is size.ldstr=1 & b_2729=7 & v=0 & b_2425=0 & b_2223=3 & b_2121=1 & b_1011=2 & addrIndexed & Rt_GPR32 & Rt_GPR64 { - Rt_GPR64 = sext(*:2 addrIndexed); + local tmp:4 = sext(*:2 addrIndexed); + Rt_GPR64 = zext(tmp); } # C6.2.177 LDRSH (register) page C6-1582 line 93951 MATCH x78a00800/mask=xffa00c00 @@ -8389,4 +8397,3 @@ is b_1231=0b11010101000000000100 & b_0007=0b00111111 OV = tmpOV; } - -- 2.51.2