From 7dd687d42293b75685fadda21ffafad1925a52de Mon Sep 17 00:00:00 2001 From: iximeow Date: Fri, 31 Dec 2021 02:18:09 -0800 Subject: pac, cfi, other misc cleanup, notes and todos --- src/armv8/a64.rs | 320 +++++++++++++++++++++++++++++++++++++++++++++--------- test/armv8/a64.rs | 36 ++++++ test/test.rs | 2 + 3 files changed, 304 insertions(+), 54 deletions(-) diff --git a/src/armv8/a64.rs b/src/armv8/a64.rs index 16709c2..f6b6f0a 100644 --- a/src/armv8/a64.rs +++ b/src/armv8/a64.rs @@ -280,6 +280,7 @@ impl Display for Instruction { if let Operand::Imm16(15) = self.operands[0] { return write!(fmt, "isb"); } + write!(fmt, "isb")?; } Opcode::SBC => { if let Operand::Register(_, 31) = self.operands[1] { @@ -370,8 +371,9 @@ impl Display for Instruction { } else if let Operand::RegisterOrSP(_, 31) = self.operands[1] { return write!(fmt, "mov {}, {}", self.operands[0], self.operands[1]); } - } else if let Operand::Register(_, 31) = self.operands[1] { - return write!(fmt, "mov {}, {}", self.operands[0], self.operands[2]); +// oh. add-with-zr does not alias mov +// } else if let Operand::Register(_, 31) = self.operands[1] { +// return write!(fmt, "mov {}, {}", self.operands[0], self.operands[2]); } else if let Operand::RegShift(ShiftStyle::LSL, 0, size, reg) = self.operands[2] { return write!(fmt, "add {}, {}, {}", self.operands[0], self.operands[1], Operand::Register(size, reg)); } @@ -402,6 +404,7 @@ impl Display for Instruction { write!(fmt, "sbcs")?; }, Opcode::UBFM => { + // TODO: handle ubfx alias if let Operand::Immediate(0) = self.operands[2] { let newdest = if let Operand::Register(_size, destnum) = self.operands[0] { Operand::Register(SizeCode::W, destnum) @@ -583,7 +586,24 @@ impl Display for Instruction { 3 => { write!(fmt, "wfi")?; }, 4 => { write!(fmt, "sev")?; }, 5 => { write!(fmt, "sevl")?; }, - _ => { write!(fmt, "hint({:#x})", v)?; } + 7 => { write!(fmt, "xpaclri")?; }, + 8 => { write!(fmt, "pacia1716")?; }, + 10 => { write!(fmt, "pacib1716")?; }, + 12 => { write!(fmt, "autia1716")?; }, + 14 => { write!(fmt, "autib1716")?; }, + 16 => { write!(fmt, "esb")?; }, + 17 => { write!(fmt, "psb csync")?; }, + 18 => { write!(fmt, "tsb csync")?; }, + 20 => { write!(fmt, "csdb")?; }, + 24 => { write!(fmt, "paciaz")?; }, + 25 => { write!(fmt, "paciasp")?; }, + 26 => { write!(fmt, "pacibz")?; }, + 27 => { write!(fmt, "pacibsp")?; }, + 28 => { write!(fmt, "autiaz")?; }, + 29 => { write!(fmt, "autiasp")?; }, + 30 => { write!(fmt, "autibz")?; }, + 31 => { write!(fmt, "autibsp")?; }, + _ => { write!(fmt, "hint #{:#x}", v)?; } } } Opcode::CSNEG => { @@ -1199,7 +1219,7 @@ pub enum Opcode { RET, ERET, DRPS, - MSR, + MSR, // TODO: handle aliases (like cfinv) MRS, SYS(SysOps), SYSL(SysOps), @@ -1214,8 +1234,6 @@ pub enum Opcode { CSNEG, CSINC, CSINV, - PACIA, - PACIZA, CCMN, CCMP, RBIT, @@ -1533,6 +1551,7 @@ pub enum Opcode { URSQRTE, PRFM, + PRFUM, AESE, AESD, @@ -1643,6 +1662,39 @@ pub enum Opcode { SHA256SU1, SHRN2, + + BLRAA, + BLRAAZ, + BLRAB, + BLRABZ, + BRAA, + BRAAZ, + BRAB, + BRABZ, + RETAA, + RETAB, + ERETAA, + ERETAB, + + PACIA, + PACIB, + PACDA, + PACDB, + AUTIA, + AUTIB, + AUTDA, + AUTDB, + PACIZA, + PACIZB, + PACDZA, + PACDZB, + AUTIZA, + AUTIZB, + AUTDZA, + AUTDZB, + XPACI, + XPACD, + } impl Display for Opcode { @@ -1740,8 +1792,6 @@ impl Display for Opcode { Opcode::SSSB => "sssb", Opcode::CLREX => "clrex", Opcode::CSEL => "csel", - Opcode::PACIA => "pacia", - Opcode::PACIZA => "paciza", Opcode::CCMN => "ccmn", Opcode::CCMP => "ccmp", Opcode::RBIT => "rbit", @@ -2036,6 +2086,7 @@ impl Display for Opcode { Opcode::FJCVTZS => "fjcvtzs", Opcode::URSQRTE => "ursqrte", Opcode::PRFM => "prfm", + Opcode::PRFUM => "prfum", Opcode::AESE => "aese", Opcode::AESD => "aesd", Opcode::AESMC => "aesmc", @@ -2435,6 +2486,38 @@ impl Display for Opcode { Opcode::SHA256H2 => "sha256h2", Opcode::SHA256SU1 => "sha256su1", + Opcode::BLRAA => "blraa", + Opcode::BLRAAZ => "blraaz", + Opcode::BLRAB => "blrab", + Opcode::BLRABZ => "blrabz", + Opcode::BRAA => "braa", + Opcode::BRAAZ => "braaz", + Opcode::BRAB => "brab", + Opcode::BRABZ => "brabz", + Opcode::ERETAA => "eretaa", + Opcode::ERETAB => "eretab", + Opcode::RETAA => "retaa", + Opcode::RETAB => "retab", + + Opcode::PACIA => "pacia", + Opcode::PACIB => "pacib", + Opcode::PACDA => "pacda", + Opcode::PACDB => "pacdb", + Opcode::AUTIA => "autia", + Opcode::AUTIB => "autib", + Opcode::AUTDA => "autda", + Opcode::AUTDB => "autdb", + Opcode::PACIZA => "paciza", + Opcode::PACIZB => "pacizb", + Opcode::PACDZA => "pacdza", + Opcode::PACDZB => "pacdzb", + Opcode::AUTIZA => "autiza", + Opcode::AUTIZB => "autizb", + Opcode::AUTDZA => "autdza", + Opcode::AUTDZB => "autdzb", + Opcode::XPACI => "xpaci", + Opcode::XPACD => "xpacd", + Opcode::Bcc(cond) => { return write!(fmt, "b.{}", Operand::ConditionCode(cond)); }, @@ -2681,6 +2764,9 @@ impl Display for Operand { Operand::SIMDRegisterElementsLane(_vector_width, reg, lane_width, lane) => { write!(fmt, "v{}.{}[{}]", reg, lane_width.name(), lane) } + Operand::SIMDRegisterElementsMultipleLane(_vector_width, reg, lane_width, lane, num_lanes) => { + write!(fmt, "v{}.{}{}[{}]", reg, num_lanes, lane_width.name(), lane) + } Operand::SIMDRegisterGroup(vector_width, reg, lane_width, group_size) => { let num_items = vector_width.width() / lane_width.width(); let format_reg = |f: &mut fmt::Formatter, reg, elems, lane_size: SIMDSizeCode| { @@ -2835,7 +2921,13 @@ impl Display for Operand { } } Operand::RegRegOffset(reg, index_reg, index_size, extend, amount) => { - write!(fmt, "[{}, {}, {} #{:#x}]", Operand::RegisterOrSP(SizeCode::X, *reg), Operand::Register(*index_size, *index_reg), extend, amount) + if ((extend == &ShiftStyle::UXTW && index_size == &SizeCode::W) || + (extend == &ShiftStyle::UXTX && index_size == &SizeCode::X)) && + *amount == 0 { + write!(fmt, "[{}, {}, {}]", Operand::RegisterOrSP(SizeCode::X, *reg), Operand::Register(*index_size, *index_reg), extend) + } else { + write!(fmt, "[{}, {}, {} #{:#x}]", Operand::RegisterOrSP(SizeCode::X, *reg), Operand::Register(*index_size, *index_reg), extend, amount) + } } Operand::RegPreIndex(reg, offset, wback_bit) => { let wback = if *wback_bit { @@ -2877,6 +2969,12 @@ impl Decoder for InstDecoder { words.next_n(&mut word_bytes)?; let word = u32::from_le_bytes(word_bytes); + inst.operands = [ + Operand::Nothing, + Operand::Nothing, + Operand::Nothing, + Operand::Nothing, + ]; #[derive(Copy, Clone, Debug)] enum Section { @@ -3464,7 +3562,7 @@ impl Decoder for InstDecoder { inst.opcode = Opcode::SQDMULH; inst.operands = [ - Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), + Operand::SIMDRegisterElements(Tb_vecsize, Rd as u16, Ta), Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), Operand::Nothing, @@ -3493,7 +3591,7 @@ impl Decoder for InstDecoder { inst.opcode = Opcode::SQRDMULH; inst.operands = [ - Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), + Operand::SIMDRegisterElements(Tb_vecsize, Rd as u16, Ta), Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), Operand::Nothing, @@ -4328,13 +4426,6 @@ impl Decoder for InstDecoder { Err(DecodeError::InvalidOperand), Err(DecodeError::InvalidOperand), ]; - const TABLE_D: &'static OperandSizeTable = &[ - Ok((D, B, D, B)), Ok((Q, H, Q, B)), - Ok((D, H, D, H)), Ok((Q, S, Q, H)), - Ok((D, S, D, S)), Ok((Q, D, Q, S)), - Err(DecodeError::InvalidOperand), Ok((Q, D, Q, D)), - ]; - const TABLE_E: &'static OperandSizeTable = &[ Ok((D, B, Q, H)), Ok((Q, B, Q, H)), Ok((D, H, Q, S)), Ok((Q, H, Q, S)), @@ -7207,12 +7298,12 @@ impl Decoder for InstDecoder { if combined_idx > 0b01_0000_0 { Operand::Register(SizeCode::W, Rd) } else { - Operand::Register(SizeCode::X, Rd) + Operand::Register(size, Rd) }, if combined_idx > 0b01_0000_0 { Operand::Register(SizeCode::W, Rn) } else { - Operand::Register(SizeCode::X, Rn) + Operand::Register(size, Rn) }, Operand::Register(size, Rm), Operand::Nothing, @@ -7268,35 +7359,40 @@ impl Decoder for InstDecoder { if S != 0 || sf != 1 { return Err(DecodeError::InvalidOpcode); } - match opcode { - 0b000000 => { - inst.opcode = Opcode::PACIA; - inst.operands = [ - Operand::Register(SizeCode::X, Rd), - Operand::RegisterOrSP(SizeCode::X, Rn), - Operand::Nothing, - Operand::Nothing, - ]; - } - 0b001000 => { - if Rn != 31 { - // technically this is undefined - do some - // cores do something with this? - inst.opcode = Opcode::Invalid; - return Err(DecodeError::InvalidOperand); - } - inst.opcode = Opcode::PACIZA; - inst.operands = [ - Operand::Register(SizeCode::X, Rd), - Operand::Nothing, - Operand::Nothing, - Operand::Nothing, - ]; - } - _ => { - inst.opcode = Opcode::Invalid; - } + + if opcode >= 0b001000 && Rn != 0b11111 { + return Err(DecodeError::InvalidOperand); } + + let opc = &[ + Ok(Opcode::PACIA), Ok(Opcode::PACIB), + Ok(Opcode::PACDA), Ok(Opcode::PACDB), + Ok(Opcode::AUTIA), Ok(Opcode::AUTIB), + Ok(Opcode::AUTDA), Ok(Opcode::AUTDB), + Ok(Opcode::PACIZA), Ok(Opcode::PACIZB), + Ok(Opcode::PACDZA), Ok(Opcode::PACDZB), + Ok(Opcode::AUTIZA), Ok(Opcode::AUTIZB), + Ok(Opcode::AUTDZA), Ok(Opcode::AUTDZB), + Ok(Opcode::XPACI), Ok(Opcode::XPACD), + Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), + Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), + Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), + Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), + Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), + Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), + Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), + ][opcode as usize]?; + inst.opcode = *opc; + inst.operands = [ + Operand::Register(SizeCode::X, Rd), + if opcode < 0b001000 { + Operand::RegisterOrSP(SizeCode::X, Rn) + } else { + Operand::Nothing + }, + Operand::Nothing, + Operand::Nothing, + ]; } _ => { // Data-processing (1 source), op2 > 0b00001 is (currently @@ -8763,6 +8859,7 @@ impl Decoder for InstDecoder { let w = (word >> 11) & 1; let imm9 = ((word >> 12) & 0b1_1111_1111) as i16; let imm9 = (imm9 << 7) >> 7; + let imm9 = imm9 << 3; // `simm` is stored as a multiple of 8 let m = (word >> 23) & 1; let size = (word >> 30) & 0b11; if size != 0b11 { @@ -8873,7 +8970,7 @@ impl Decoder for InstDecoder { Err(DecodeError::InvalidOpcode), Ok((Opcode::STUR, SizeCode::X)), Ok((Opcode::LDUR, SizeCode::X)), - Ok((Opcode::PRFM, SizeCode::X)), + Ok((Opcode::PRFUM, SizeCode::X)), Err(DecodeError::InvalidOpcode), ]; @@ -8906,7 +9003,7 @@ impl Decoder for InstDecoder { Ok((Opcode::LDTR, SizeCode::W)), Ok((Opcode::LDTRSW, SizeCode::X)), Err(DecodeError::InvalidOpcode), - Ok((Opcode::STUR, SizeCode::X)), + Ok((Opcode::STTR, SizeCode::X)), Ok((Opcode::LDTR, SizeCode::X)), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), @@ -10134,8 +10231,8 @@ impl Decoder for InstDecoder { let opc = (word >> 21) & 0x7; match opc { 0b000 => { + let Rn = (word >> 5) & 0x1f; if (word & 0x1ffc1f) == 0x1f0000 { - let Rn = (word >> 5) & 0x1f; inst.opcode = Opcode::BR; inst.operands = [ Operand::Register(SizeCode::X, Rn as u16), @@ -10143,13 +10240,30 @@ impl Decoder for InstDecoder { Operand::Nothing, Operand::Nothing ]; + } else if (word & 0x1fffff) == 0x1f081f { + inst.opcode = Opcode::BRAAZ; + inst.operands = [ + Operand::Register(SizeCode::X, Rn as u16), + Operand::Nothing, + Operand::Nothing, + Operand::Nothing, + ]; + } else if (word & 0x1fffff) == 0x1f0c1f { + inst.opcode = Opcode::BRABZ; + inst.operands = [ + Operand::Register(SizeCode::X, Rn as u16), + Operand::Nothing, + Operand::Nothing, + Operand::Nothing, + ]; } else { inst.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); } }, 0b001 => { + let Rn = (word >> 5) & 0x1f; if (word & 0x1ffc1f) == 0x1f0000 { - let Rn = (word >> 5) & 0x1f; inst.opcode = Opcode::BLR; inst.operands = [ Operand::Register(SizeCode::X, Rn as u16), @@ -10157,13 +10271,30 @@ impl Decoder for InstDecoder { Operand::Nothing, Operand::Nothing ]; + } else if (word & 0x1fffff) == 0x1f081f { + inst.opcode = Opcode::BLRAAZ; + inst.operands = [ + Operand::Register(SizeCode::X, Rn as u16), + Operand::Nothing, + Operand::Nothing, + Operand::Nothing, + ]; + } else if (word & 0x1fffff) == 0x1f0c1f { + inst.opcode = Opcode::BLRABZ; + inst.operands = [ + Operand::Register(SizeCode::X, Rn as u16), + Operand::Nothing, + Operand::Nothing, + Operand::Nothing, + ]; } else { inst.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); } }, 0b010 => { + let Rn = (word >> 5) & 0x1f; if (word & 0x1ffc1f) == 0x1f0000 { - let Rn = (word >> 5) & 0x1f; inst.opcode = Opcode::RET; inst.operands = [ Operand::Register(SizeCode::X, Rn as u16), @@ -10171,15 +10302,37 @@ impl Decoder for InstDecoder { Operand::Nothing, Operand::Nothing ]; + } else if (word & 0x1fffff) == 0x1f0bff { + inst.opcode = Opcode::RETAA; + inst.operands = [ + Operand::Nothing, + Operand::Nothing, + Operand::Nothing, + Operand::Nothing, + ]; + } else if (word & 0x1fffff) == 0x1f0fff { + inst.opcode = Opcode::RETAB; + inst.operands = [ + Operand::Nothing, + Operand::Nothing, + Operand::Nothing, + Operand::Nothing, + ]; } else { inst.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); } }, 0b100 => { if (word & 0x1fffff) == 0x1f03e0 { inst.opcode = Opcode::ERET; + } else if (word & 0x1fffff) == 0x1f0bff { + inst.opcode = Opcode::ERETAA; + } else if (word & 0x1fffff) == 0x1f0fff { + inst.opcode = Opcode::ERETAB; } else { inst.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); } }, 0b101 => { @@ -10187,17 +10340,76 @@ impl Decoder for InstDecoder { inst.opcode = Opcode::DRPS; } else { inst.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); } }, _ => { inst.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); } } } 0b11011 => { // unconditional branch (reg) // the last 1 is bit 24, which C3.2.7 indicates are // all invalid encodings (opc is b0101 or lower) - inst.opcode = Opcode::Invalid; + let opc = (word >> 21) & 0x7; + + if opc == 0b000 { + // implied leading bit means opc = 0b1000 + if word & 0xff_ff_fc_00 == 0xd7_1f_08_00 { + // op3 = 000011 + // register modifier variant + inst.opcode = Opcode::BRAA; + + inst.operands = [ + Operand::Register(SizeCode::X, ((word >> 5) & 0b11111) as u16), + Operand::RegisterOrSP(SizeCode::X, (word & 0b11111) as u16), + Operand::Nothing, + Operand::Nothing, + ]; + } else if word & 0xff_ff_fc_00 == 0xd7_1f_0c_00 { + // op3 = 000011 + inst.opcode = Opcode::BRAB; + + inst.operands = [ + Operand::Register(SizeCode::X, ((word >> 5) & 0b11111) as u16), + Operand::RegisterOrSP(SizeCode::X, (word & 0b11111) as u16), + Operand::Nothing, + Operand::Nothing, + ]; + } else { + return Err(DecodeError::InvalidOpcode); + } + } else if opc == 0b001 { + // implied leading bit means opc = 0b1001 + if word & 0xff_ff_fc_00 == 0xd7_1f_0c_00 { + // op3 = 000011 + // register modifier variant + inst.opcode = Opcode::BLRAA; + + inst.operands = [ + Operand::Register(SizeCode::X, ((word >> 5) & 0b11111) as u16), + Operand::RegisterOrSP(SizeCode::X, (word & 0b11111) as u16), + Operand::Nothing, + Operand::Nothing, + ]; + } else if word & 0xff_ff_fc_00 == 0xd7_1f_08_00 { + // op3 = 000011 + inst.opcode = Opcode::BLRAB; + + inst.operands = [ + Operand::Register(SizeCode::X, ((word >> 5) & 0b11111) as u16), + Operand::RegisterOrSP(SizeCode::X, (word & 0b11111) as u16), + Operand::Nothing, + Operand::Nothing, + ]; + } else { + return Err(DecodeError::InvalidOpcode); + } + } else { + inst.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } } _ => { // TODO: invalid diff --git a/test/armv8/a64.rs b/test/armv8/a64.rs index 8fad9e6..2b43284 100644 --- a/test/armv8/a64.rs +++ b/test/armv8/a64.rs @@ -4737,6 +4737,35 @@ fn test_vec_shift() { } #[test] +fn test_pac() { + const TESTS: &[([u8; 4], &'static str)] = &[ + ([0x00, 0x04, 0xc1, 0xda], "pacib x0, x0"), + ]; + let errs = run_tests(TESTS); + + for err in errs.iter() { + println!("{}", err); + } + + assert!(errs.is_empty()); +} + +#[test] +fn test_cfi() { + const TESTS: &[([u8; 4], &'static str)] = &[ + ([0x1f, 0x08, 0x1f, 0xd6], "braaz x0"), + ([0x00, 0x08, 0x1f, 0xd7], "braa x0, x0"), + ]; + let errs = run_tests(TESTS); + + for err in errs.iter() { + println!("{}", err); + } + + assert!(errs.is_empty()); +} + +#[test] fn test_sha() { const TESTS: &[([u8; 4], &'static str)] = &[ ([0x00, 0x00, 0x00, 0x5e], "sha1c q0, s0, v0.4s"), @@ -4803,6 +4832,13 @@ fn test_misc() { ([0x00, 0x00, 0x40, 0x9b], "smulh x0, x0, x0"), ([0x00, 0x08, 0x40, 0xce], "sm3ss1 v0.4s, v0.4s, v0.4s, v2.4s"), ([0x00, 0x1c, 0x40, 0xd3], "ubfx x0, x0, #0x0, #0x8"), + ([0x00, 0x08, 0x00, 0xf8], "sttr x0, [x0]"), + ([0x00, 0x14, 0x20, 0xf8], "ldraa x0, [x0, #0x8]"), + ([0x00, 0x00, 0x80, 0xf8], "prfum pldl1keep, [x0]"), + ([0x06, 0x48, 0xa0, 0xf8], "prfm 0x6, [x0, w0, uxtw]"), + ([0xe0, 0x03, 0x00, 0x0b], "add w0, wzr, w0"), + ([0x00, 0xc0, 0x40, 0x0f], "sqdmulh v0.4h, v0.4h, v0.h[0]"), + ([0x00, 0xd0, 0x40, 0x0f], "sqrdmulh v0.4h, v0.4h, v0.h[0]"), ]; let errs = run_tests(TESTS); diff --git a/test/test.rs b/test/test.rs index fb74520..81080cf 100644 --- a/test/test.rs +++ b/test/test.rs @@ -20,6 +20,7 @@ fn test_armv7_does_not_panic() { let res = armv7.decode(&mut U8Reader::new(&bytes)); if let Ok(instr) = res { let s = instr.to_string(); + drop(s); } } } @@ -33,6 +34,7 @@ fn test_armv7_thumb_does_not_panic() { let res = armv7_t.decode(&mut U8Reader::new(&bytes)); if let Ok(instr) = res { let s = instr.to_string(); + drop(s); } } } -- cgit v1.1