aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2019-12-16 01:02:56 -0800
committeriximeow <me@iximeow.net>2020-01-12 16:10:14 -0800
commita245487fa29f7e132f6f2c42d84bdaf5fc099922 (patch)
treed900102ad44671fddc0df8db1fb585ade4adc9b4
parentf23d12996aeb4f6e1dbf65e4c8e39376303425c8 (diff)
support aesni
this includes respecting ModRM_XXXX-style operand codes from alternate 0f opcode maps. this MAY introduce bugs where an opcode 0fXX is valid by the 0f map, invalid by the 660f map, and we see a sequence like 660fXXYY. if YY results in 0fXX being invalid by 660f, we may have to fall back to reading opcode XX as an 0f opcode, where YY needs to be re-read with the correct operand code. hopefully this doesn't actually happen...
-rw-r--r--src/lib.rs58
-rw-r--r--test/test.rs32
2 files changed, 86 insertions, 4 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 15cee14..c583031 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2344,6 +2344,8 @@ pub enum OperandCode {
ModRM_0x0fba,
ModRM_0xf238,
ModRM_0xf30fc7,
+ ModRM_0x660f38,
+ ModRM_0x660f3a,
CVT_AA,
CVT_DA,
Rq_Cq_0,
@@ -2578,9 +2580,9 @@ const OPCODE_660F_MAP: [OpcodeRecord; 256] = [
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x660f38),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
- OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
- OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x660f3a),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
@@ -3689,7 +3691,7 @@ enum Interpretation {
Prefix,
}
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, PartialEq)]
// this should be a 32-byte struct..
struct OpcodeRecord(Interpretation, OperandCode);
@@ -4222,7 +4224,7 @@ pub fn read_instr<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T
read_opcode_f30f_map(&mut bytes_iter, &mut length)?
},
};
- if rec.0 == Interpretation::Instruction(Opcode::Invalid) {
+ if rec == OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing) {
escapes_are_prefixes_actually(&mut prefixes, &mut Some(opcode_map));
OPCODE_0F_MAP[opcode_byte as usize]
} else {
@@ -4997,6 +4999,54 @@ fn unlikely_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter
instruction.imm = read_imm_signed(&mut bytes_iter, 1, length)? as u64;
instruction.operands[1] = OperandSpec::ImmI8;
},
+ OperandCode::ModRM_0x660f38 => {
+ let op = bytes_iter.next().map(|b| { *length += 1; b }).ok_or(())?;
+ match op {
+ 0xdb => { instruction.opcode = Opcode::AESIMC; }
+ 0xdc => { instruction.opcode = Opcode::AESENC; }
+ 0xdd => { instruction.opcode = Opcode::AESENCLAST; }
+ 0xde => { instruction.opcode = Opcode::AESDEC; }
+ 0xdf => { instruction.opcode = Opcode::AESDECLAST; }
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(());
+ }
+ };
+ // all these SO FAR are G_E_xmm
+ let modrm = read_modrm(&mut bytes_iter, instruction, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.rex().r(), RegisterBank::X);
+
+
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = read_E_xmm(&mut bytes_iter, instruction, modrm, length)?;
+ instruction.operand_count = 2;
+ }
+ OperandCode::ModRM_0x660f3a => {
+ let op = bytes_iter.next().map(|b| { *length += 1; b }).ok_or(())?;
+ match op {
+ 0xdf => {
+ instruction.opcode = Opcode::AESKEYGENASSIST;
+ // read operands right here right now
+
+ let modrm = read_modrm(&mut bytes_iter, instruction, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.rex().r(), RegisterBank::X);
+
+
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = read_E_xmm(&mut bytes_iter, instruction, modrm, length)?;
+ instruction.imm =
+ read_imm_unsigned(&mut bytes_iter, 1)?;
+ instruction.operands[2] = OperandSpec::ImmU8;
+ instruction.operand_count = 3;
+ }
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(());
+ }
+ };
+ }
OperandCode::G_mm_Edq => {
instruction.operands[1] = mem_oper;
instruction.modrm_rrr.bank = RegisterBank::MM;
diff --git a/test/test.rs b/test/test.rs
index e2c52fe..cd2f6c0 100644
--- a/test/test.rs
+++ b/test/test.rs
@@ -98,6 +98,38 @@ fn test_cvt() {
}
#[test]
+fn test_aesni() {
+ fn test_instr(bytes: &[u8], text: &'static str) {
+ test_display_under(&InstDecoder::minimal().with_aesni(), bytes, text);
+ test_display_under(&InstDecoder::default(), bytes, text);
+ test_invalid_under(&InstDecoder::minimal(), bytes);
+ }
+
+ fn test_instr_invalid(bytes: &[u8]) {
+ test_invalid_under(&InstDecoder::minimal().with_aesni(), bytes);
+ test_invalid_under(&InstDecoder::default(), bytes);
+ }
+
+ test_instr(&[0x66, 0x0f, 0x38, 0xdb, 0x0f], "aesimc xmm1, [rdi]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x38, 0xdb, 0xcf], "aesimc xmm9, xmm15");
+
+ test_instr(&[0x66, 0x0f, 0x38, 0xdc, 0x0f], "aesenc xmm1, [rdi]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x38, 0xdc, 0xcf], "aesenc xmm9, xmm15");
+
+ test_instr(&[0x66, 0x0f, 0x38, 0xdd, 0x0f], "aesenclast xmm1, [rdi]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x38, 0xdd, 0xcf], "aesenclast xmm9, xmm15");
+
+ test_instr(&[0x66, 0x0f, 0x38, 0xde, 0x0f], "aesdec xmm1, [rdi]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x38, 0xde, 0xcf], "aesdec xmm9, xmm15");
+
+ test_instr(&[0x66, 0x0f, 0x38, 0xdf, 0x0f], "aesdeclast xmm1, [rdi]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x38, 0xdf, 0xcf], "aesdeclast xmm9, xmm15");
+
+ test_instr(&[0x66, 0x0f, 0x3a, 0xdf, 0x0f, 0xaa], "aeskeygenassist xmm1, [rdi], 0xaa");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x3a, 0xdf, 0xcf, 0xaa], "aeskeygenassist xmm9, xmm15, 0xaa");
+}
+
+#[test]
fn test_sse3() {
fn test_instr(bytes: &[u8], text: &'static str) {
test_display_under(&InstDecoder::minimal().with_sse3(), bytes, text);