aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2020-02-22 15:38:41 -0800
committeriximeow <me@iximeow.net>2020-02-22 15:38:41 -0800
commit802679e4f8362d3c819b83223854c638cc8f2b7f (patch)
tree8a2d4025db995e71f36aa9e8131dda333e8fc8ab
parentd1787896dacc4821ebf399508472b3985ab2a232 (diff)
fix {jmp,call} <reg>, as well as jmpf/callf
also support vmxon to finish out the f30f opcode map add tests for forms of inc/dec, as well as TODOs, as yaxpeax-x86 doesn't provide a way to distinguish different operand sizes (yet)
-rw-r--r--src/long_mode/display.rs2
-rw-r--r--src/long_mode/mod.rs26
-rw-r--r--test/test.rs17
3 files changed, 45 insertions, 0 deletions
diff --git a/src/long_mode/display.rs b/src/long_mode/display.rs
index d45a98a..3025c16 100644
--- a/src/long_mode/display.rs
+++ b/src/long_mode/display.rs
@@ -652,6 +652,7 @@ impl fmt::Display for Opcode {
&Opcode::BLSMSK => write!(f, "blsmsk"),
&Opcode::BLSR => write!(f, "blsr"),
&Opcode::VMCLEAR => write!(f, "vmclear"),
+ &Opcode::VMXON => write!(f, "vmxon"),
&Opcode::VMCALL => write!(f, "vmcall"),
&Opcode::VMLAUNCH => write!(f, "vmlaunch"),
&Opcode::VMRESUME => write!(f, "vmresume"),
@@ -1855,6 +1856,7 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color
Opcode::VMREAD |
Opcode::VMWRITE |
Opcode::VMCLEAR |
+ Opcode::VMXON |
Opcode::VMCALL |
Opcode::VMLAUNCH |
Opcode::VMRESUME |
diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs
index 79e5b39..73570c1 100644
--- a/src/long_mode/mod.rs
+++ b/src/long_mode/mod.rs
@@ -659,6 +659,7 @@ pub enum Opcode {
BLSMSK,
BLSR,
VMCLEAR,
+ VMXON,
VMCALL,
VMLAUNCH,
VMRESUME,
@@ -5111,6 +5112,13 @@ fn read_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T,
Opcode::PUSH,
Opcode::Invalid
][((modrm >> 3) & 7) as usize];
+ if instruction.operands[0] == OperandSpec::RegMMM {
+ if opcode == Opcode::CALL || opcode == Opcode::JMP {
+ instruction.modrm_mmm.bank = RegisterBank::Q;
+ } else if opcode == Opcode::CALLF || opcode == Opcode::JMPF {
+ return Err(DecodeError::InvalidOperand);
+ }
+ }
instruction.opcode = opcode;
instruction.operand_count = 1;
}
@@ -5643,6 +5651,24 @@ fn unlikely_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter
}
}
},
+ OperandCode::ModRM_0xf30fc7 => {
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+
+ let r = (modrm >> 3) & 7;
+ match r {
+ 6 => {
+ instruction.opcode = Opcode::VMXON;
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 1 /* doesn't matter, something using this width is invalid */, length)?;
+ if instruction.operands[0] == OperandSpec::RegMMM {
+ return Err(DecodeError::InvalidOperand);
+ }
+ instruction.operand_count = 1;
+ }
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ },
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 fe6a898..28263ae 100644
--- a/test/test.rs
+++ b/test/test.rs
@@ -747,6 +747,11 @@ fn test_control_flow() {
test_display(&[0x74, 0x47], "jz 0x47");
test_display(&[0xff, 0x15, 0x7e, 0x72, 0x24, 0x00], "call [rip + 0x24727e]");
test_display(&[0xff, 0x24, 0xcd, 0x70, 0xa0, 0xbc, 0x01], "jmp [rcx * 8 + 0x1bca070]");
+ test_display(&[0xff, 0xe0], "jmp rax");
+ test_display(&[0x66, 0xff, 0xe0], "jmp rax");
+ test_display(&[0x67, 0xff, 0xe0], "jmp rax");
+ test_invalid(&[0xff, 0xd8]);
+ test_display(&[0xff, 0x18], "callf [rax]");
test_display(&[0xc3], "ret");
}
@@ -772,6 +777,9 @@ fn test_bmi1() {
let no_bmi1 = InstDecoder::minimal();
test_display_under(&bmi1, &[0x41, 0x0f, 0xbc, 0xd3], "tzcnt edx, r11d");
test_display_under(&no_bmi1, &[0x41, 0x0f, 0xbc, 0xd3], "bsf edx, r11d");
+
+ test_display_under(&bmi1, &[0xf3, 0x0f, 0xb8, 0xc1], "popcnt eax, ecx");
+ test_display_under(&bmi1, &[0xf3, 0x4f, 0x0f, 0xb8, 0xc1], "popcnt r8, r9");
}
#[test]
@@ -783,6 +791,13 @@ fn test_bitwise() {
#[test]
fn test_misc() {
+ // TODO
+// test_display(&[0xf2, 0x0f, 0x38, 0xf0, 0xc1], "crc32 eax, cl");
+// test_display(&[0xf2, 0x0f, 0x38, 0xf1, 0xc1], "crc32 eax, ecx");
+ test_display(&[0xfe, 0x00], "inc [rax]"); // TODO: inc byte [rax]
+ test_display(&[0xfe, 0x08], "dec [rax]"); // TODO: dec byte [rax]
+ test_display(&[0xff, 0x00], "inc [rax]"); // TODO: inc dword [rax]
+ test_display(&[0x48, 0xff, 0x00], "inc [rax]"); // TODO: inc qword [rax]
test_display(&[0xe4, 0x99], "in al, 0x99");
test_display(&[0xe5, 0x99], "in eax, 0x99");
test_display(&[0x67, 0xe5, 0x99], "in eax, 0x99");
@@ -815,6 +830,8 @@ fn test_misc() {
// test_invalid(&[0x66, 0x0f, 0xc7, 0x03]);
test_display(&[0x66, 0x4f, 0x0f, 0xc7, 0x33], "vmclear [r11]");
test_display(&[0x66, 0x0f, 0xc7, 0x33], "vmclear [rbx]");
+ test_display(&[0xf3, 0x4f, 0x0f, 0xc7, 0x33], "vmxon [r11]");
+ test_display(&[0xf3, 0x0f, 0xc7, 0x33], "vmxon [rbx]");
}
#[test]