aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2021-01-15 18:40:31 -0800
committeriximeow <me@iximeow.net>2021-01-15 18:41:16 -0800
commit6232e8b1daf7067cb2e8065687530d5f88ecb46d (patch)
tree864b839a32f0154579a6a4c79ca227045f1a202e
parentd8083b08dc987adeda73fb13298383c6cf519596 (diff)
support xchg AX/reg0.1.5
-rw-r--r--CHANGELOG1
-rw-r--r--src/long_mode/mod.rs14
-rw-r--r--src/protected_mode/mod.rs11
-rw-r--r--test/long_mode/mod.rs8
-rw-r--r--test/protected_mode/mod.rs7
5 files changed, 41 insertions, 0 deletions
diff --git a/CHANGELOG b/CHANGELOG
index c608941..0a707eb 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -5,6 +5,7 @@
- `rdpkru` and `wrpkru` were incorrectly decoded when modrm bits were not `11`
* small performance tweaks. read_imm_signed is now inline(always) and some
pre-decode initialization is a bit better-packed
+* `xchg {r,e,}ax, reg` was not supported! it's supported now.
## 0.1.4
* [long mode only]: fix decoding of rex-prefixed modrm+sib operands selecting index 0b100 and base 0b101
diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs
index f9be9ab..909157b 100644
--- a/src/long_mode/mod.rs
+++ b/src/long_mode/mod.rs
@@ -6079,6 +6079,20 @@ fn read_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T,
}
1 => {
// Zv_AX
+ let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes);
+ let bank = if opwidth == 4 {
+ RegisterBank::D
+ } else if opwidth == 2 {
+ RegisterBank::W
+ } else {
+ RegisterBank::Q
+ };
+ instruction.modrm_rrr =
+ RegSpec::from_parts(0, instruction.prefixes.rex().b(), bank);
+ instruction.operands[1] = OperandSpec::RegMMM;
+ instruction.modrm_mmm =
+ RegSpec::from_parts(reg, instruction.prefixes.rex().b(), bank);
+ instruction.operand_count = 2;
}
2 => {
// these are Zb_Ib_R
diff --git a/src/protected_mode/mod.rs b/src/protected_mode/mod.rs
index 9327f64..6394de0 100644
--- a/src/protected_mode/mod.rs
+++ b/src/protected_mode/mod.rs
@@ -5933,6 +5933,17 @@ fn read_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T,
}
1 => {
// Zv_AX
+ let bank = if !instruction.prefixes.operand_size() {
+ RegisterBank::D
+ } else {
+ RegisterBank::W
+ };
+ instruction.modrm_rrr =
+ RegSpec::from_parts(0, bank);
+ instruction.operands[1] = OperandSpec::RegMMM;
+ instruction.modrm_mmm =
+ RegSpec::from_parts(reg, bank);
+ instruction.operand_count = 2;
}
2 => {
// these are Zb_Ib_R
diff --git a/test/long_mode/mod.rs b/test/long_mode/mod.rs
index 0830c2d..c3933ab 100644
--- a/test/long_mode/mod.rs
+++ b/test/long_mode/mod.rs
@@ -1137,6 +1137,14 @@ fn test_mov() {
}
#[test]
+fn test_xchg() {
+ test_display(&[0x90], "nop");
+ test_display(&[0x91], "xchg eax, ecx");
+ test_display(&[0x4f, 0x91], "xchg r8, r9");
+ test_display(&[0x66, 0x91], "xchg ax, cx");
+}
+
+#[test]
fn test_stack() {
test_display(&[0x66, 0x41, 0x50], "push r8w");
}
diff --git a/test/protected_mode/mod.rs b/test/protected_mode/mod.rs
index e3c7975..88cf7ea 100644
--- a/test/protected_mode/mod.rs
+++ b/test/protected_mode/mod.rs
@@ -1030,6 +1030,13 @@ fn test_mov() {
}
#[test]
+fn test_xchg() {
+ test_display(&[0x90], "nop");
+ test_display(&[0x91], "xchg eax, ecx");
+ test_display(&[0x66, 0x91], "xchg ax, cx");
+}
+
+#[test]
fn test_stack() {
test_display(&[0x66, 0x50], "push ax");
}