diff options
author | iximeow <me@iximeow.net> | 2021-10-21 15:19:09 -0700 |
---|---|---|
committer | iximeow <me@iximeow.net> | 2021-10-21 15:22:29 -0700 |
commit | 4a03599767c0ebac12e730a837abe1d15ac800e5 (patch) | |
tree | 424cb49217ac9a6799e257ed61941c9da18ea613 | |
parent | eadc1ab0ceb5b3cd5f88b696d72b5c0592a63da5 (diff) |
data processing instructions (one source)
-rw-r--r-- | src/armv8/a64.rs | 62 | ||||
-rw-r--r-- | test/armv8/a64.rs | 19 |
2 files changed, 80 insertions, 1 deletions
diff --git a/src/armv8/a64.rs b/src/armv8/a64.rs index 16a4116..60bbbed 100644 --- a/src/armv8/a64.rs +++ b/src/armv8/a64.rs @@ -647,6 +647,24 @@ impl Display for Instruction { Opcode::CCMP => { write!(fmt, "ccmp")?; } + Opcode::RBIT => { + write!(fmt, "rbit")?; + } + Opcode::REV16 => { + write!(fmt, "rev16")?; + } + Opcode::REV => { + write!(fmt, "rev")?; + } + Opcode::REV32 => { + write!(fmt, "rev32")?; + } + Opcode::CLZ => { + write!(fmt, "clz")?; + } + Opcode::CLS => { + write!(fmt, "cls")?; + } }; if self.operands[0] != Operand::Nothing { @@ -816,6 +834,12 @@ pub enum Opcode { PACIZA, CCMN, CCMP, + RBIT, + REV16, + REV, + REV32, + CLZ, + CLS, } #[derive(Copy, Clone, Debug, PartialEq)] @@ -1304,6 +1328,9 @@ impl Decoder<ARMv8> for InstDecoder { } else { // X1X11010_110XXXXX_XXXXXXXX_XXXXXXXX // Data-processing (1 source) + let sf = ((word >> 31) & 0x01) as u8; + let S = ((word >> 29) & 0x01) as u8; + let Rd = (word & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let opcode = ((word >> 10) & 0x3f) as u8; @@ -1313,9 +1340,42 @@ impl Decoder<ARMv8> for InstDecoder { // however, PAC (added in v8.3) says otherwise. match opcode2 { 0b00000 => { - return Err(DecodeError::IncompleteDecoder); + if S != 0 { + return Err(DecodeError::InvalidOpcode); + } + + let (opcode, size) = match (opcode << 1) | sf { + 0b000000_0 => (Opcode::RBIT, SizeCode::W), + 0b000000_1 => (Opcode::RBIT, SizeCode::X), + 0b000001_0 => (Opcode::REV16, SizeCode::W), + 0b000001_1 => (Opcode::REV16, SizeCode::X), + 0b000010_0 => (Opcode::REV, SizeCode::W), + 0b000010_1 => (Opcode::REV, SizeCode::X), + 0b000011_0 => (Opcode::Invalid, SizeCode::W), + 0b000011_1 => (Opcode::REV32, SizeCode::X), + 0b000100_0 => (Opcode::CLZ, SizeCode::W), + 0b000100_1 => (Opcode::CLZ, SizeCode::X), + 0b000101_0 => (Opcode::CLS, SizeCode::W), + 0b000101_1 => (Opcode::CLS, SizeCode::X), + _ => (Opcode::Invalid, SizeCode::W), + }; + + inst.opcode = opcode; + inst.operands = [ + Operand::Register(size, Rd), + Operand::Register(size, Rn), + Operand::Nothing, + Operand::Nothing, + ]; + + if opcode == Opcode::Invalid { + return Err(DecodeError::InvalidOpcode); + } } 0b00001 => { + if S != 0 || sf != 1 { + return Err(DecodeError::InvalidOpcode); + } match opcode { 0b000000 => { inst.opcode = Opcode::PACIA; diff --git a/test/armv8/a64.rs b/test/armv8/a64.rs index 5b480df..feb878a 100644 --- a/test/armv8/a64.rs +++ b/test/armv8/a64.rs @@ -295,6 +295,25 @@ fn test_decode_ccm() { } #[test] +fn test_decode_data_processing_one_source() { + const TESTS: &[([u8; 4], &'static str)] = &[ + ([0x14, 0x02, 0xc0, 0x5a], "rbit w20, w16"), + ([0x14, 0x06, 0xc0, 0x5a], "rev16 w20, w16"), + ([0x14, 0x12, 0xc0, 0x5a], "clz w20, w16"), + ([0x14, 0x12, 0xc0, 0x5a], "clz w20, w16"), + ([0x14, 0x16, 0xc0, 0x5a], "cls w20, w16"), + ([0x14, 0x16, 0xc0, 0xda], "cls x20, x16"), + ([0x14, 0x0a, 0xc0, 0xda], "rev32 x20, x16"), + ]; + + for (bytes, instr) in TESTS { + test_display(*bytes, instr); + } + + test_err([0x14, 0x0e, 0xc0, 0x5a], DecodeError::InvalidOpcode); +} + +#[test] fn test_decode_chrome_entrypoint() { // 1400 instructions from the entrypoint of a chrome binary, sorted by // instruction word for no good reason. |