aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2023-07-24 06:41:02 -0700
committeriximeow <me@iximeow.net>2023-07-24 06:41:02 -0700
commitab51fd1b2c7cf1b7bb6f84c5b07e06245f6b3d99 (patch)
tree80b2a81dfb805c49a5c3a43296835bd5195e422a
parent855fa08f1d2f4bc405a1cfc205b5e9321dd4ebf5 (diff)
fix handling of lar/lsl source register
-rw-r--r--CHANGELOG5
-rw-r--r--src/long_mode/mod.rs33
-rw-r--r--src/protected_mode/mod.rs37
-rw-r--r--src/real_mode/mod.rs37
-rw-r--r--test/long_mode/mod.rs18
-rw-r--r--test/protected_mode/mod.rs10
-rw-r--r--test/real_mode/mod.rs10
-rw-r--r--todo_notes1
8 files changed, 119 insertions, 32 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 81a1f46..091aa06 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -25,6 +25,11 @@
encodings and bitness
* in some cases, instructions loading a single-precision float reported 8-byte loads
* in some cases, instructions loading a double-precision float reported 4-byte loads
+* fix register sizes for lar/lsl
+ * 16 bits are read from the source register, but x86 docs state that the
+ source register is written as 16-bit, 32-bit, or 64-bit, as prefixes dictate.
+ memory is always written as `word [addr]`, which was correct before and
+ remains the case.
## 1.1.5
* fix several typos across crate docs - thank you Bruce! (aka github user waywardmonkeys)
diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs
index 71b2373..14f782c 100644
--- a/src/long_mode/mod.rs
+++ b/src/long_mode/mod.rs
@@ -5037,6 +5037,7 @@ enum OperandCase {
AX_Ib,
Ib_AL,
Ib_AX,
+ Gv_Ew_LAR,
Gv_Ew_LSL,
Gdq_Ev,
Gv_Ev_Ib,
@@ -5374,6 +5375,7 @@ enum OperandCode {
Zv_Ivq_R7 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Ivq_R, 7).bits(),
Gv_Eb = OperandCodeBuilder::new().read_E().operand_case(OperandCase::Gv_Eb).bits(),
Gv_Ew = OperandCodeBuilder::new().read_E().operand_case(OperandCase::Gv_Ew).bits(),
+ Gv_Ew_LAR = OperandCodeBuilder::new().read_E().operand_case(OperandCase::Gv_Ew_LAR).bits(),
Gv_Ew_LSL = OperandCodeBuilder::new().read_E().operand_case(OperandCase::Gv_Ew_LSL).bits(),
Gdq_Ed = OperandCodeBuilder::new().read_E().operand_case(OperandCase::Gdq_Ed).bits(),
Gd_Ed = OperandCodeBuilder::new().read_E().operand_case(OperandCase::Gd_Ed).bits(),
@@ -8009,11 +8011,30 @@ fn read_operands<
instruction.regs[1].bank = RegisterBank::MM;
instruction.regs[1].num &= 0b111;
},
+ OperandCase::Gv_Ew_LAR => {
+ instruction.operands[1] = mem_oper;
+ // lar is weird. a segment selector is taken from the source register, which means
+ // either we read the low 16-bits of a register or read 16 bits from a memory operand.
+ // for whatever reason, the intel manual writes a source register as a dword/qword for
+ // larger modes even though the upper 16 bits would be ignored.
+ //
+ // so the registers are correct by the time we're here, we might just need to override
+ // mem size as well.
+ if instruction.operands[1] != OperandSpec::RegMMM {
+ instruction.mem_size = 2;
+ }
+ instruction.regs[0].bank = self.vqp_size();
+ },
OperandCase::Gv_Ew_LSL => {
instruction.operands[1] = mem_oper;
- // lsl is weird. the full register width is written, but only the low 16 bits are used.
+ // lsl is weird. a segment selector is taken from the source register, which means
+ // either we read the low 16-bits of a register or read 16 bits from a memory operand.
+ // for whatever reason, the intel manual writes a source register as a dword for larger
+ // modes even though the upper 16 bits would be ignored.
if instruction.operands[1] == OperandSpec::RegMMM {
- instruction.regs[1].bank = RegisterBank::D;
+ if instruction.regs[1].bank == RegisterBank::Q {
+ instruction.regs[1].bank = RegisterBank::D;
+ }
} else {
instruction.mem_size = 2;
}
@@ -10869,7 +10890,7 @@ fn read_modrm<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_
const REPNZ_0F_CODES: [OpcodeRecord; 256] = [
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f00),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f01),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew_LAR),
OpcodeRecord::new(Interpretation::Instruction(Opcode::LSL), OperandCode::Gv_Ew_LSL),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord::new(Interpretation::Instruction(Opcode::SYSCALL), OperandCode::Nothing),
@@ -11145,7 +11166,7 @@ const REPNZ_0F_CODES: [OpcodeRecord; 256] = [
const REP_0F_CODES: [OpcodeRecord; 256] = [
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f00),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f01),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew_LAR),
OpcodeRecord::new(Interpretation::Instruction(Opcode::LSL), OperandCode::Gv_Ew_LSL),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord::new(Interpretation::Instruction(Opcode::SYSCALL), OperandCode::Nothing),
@@ -11421,7 +11442,7 @@ const REP_0F_CODES: [OpcodeRecord; 256] = [
const OPERAND_SIZE_0F_CODES: [OpcodeRecord; 256] = [
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f00),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f01),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew_LAR),
OpcodeRecord::new(Interpretation::Instruction(Opcode::LSL), OperandCode::Gv_Ew_LSL),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord::new(Interpretation::Instruction(Opcode::SYSCALL), OperandCode::Nothing),
@@ -11694,7 +11715,7 @@ const OPERAND_SIZE_0F_CODES: [OpcodeRecord; 256] = [
const NORMAL_0F_CODES: [OpcodeRecord; 256] = [
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f00),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f01),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew_LAR),
OpcodeRecord::new(Interpretation::Instruction(Opcode::LSL), OperandCode::Gv_Ew_LSL),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord::new(Interpretation::Instruction(Opcode::SYSCALL), OperandCode::Nothing),
diff --git a/src/protected_mode/mod.rs b/src/protected_mode/mod.rs
index f4e355f..200e12f 100644
--- a/src/protected_mode/mod.rs
+++ b/src/protected_mode/mod.rs
@@ -4936,6 +4936,7 @@ enum OperandCase {
AX_Ib,
Ib_AL,
Ib_AX,
+ Gv_Ew_LAR,
Gv_Ew_LSL,
// Gdq_Ev,
Gd_Ev,
@@ -5266,6 +5267,7 @@ enum OperandCode {
Zv_Iv_R7 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Iv_R, 7).bits(),
Gv_Eb = OperandCodeBuilder::new().read_E().operand_case(OperandCase::Gv_Eb).bits(),
Gv_Ew = OperandCodeBuilder::new().read_E().operand_case(OperandCase::Gv_Ew).bits(),
+ Gv_Ew_LAR = OperandCodeBuilder::new().read_E().operand_case(OperandCase::Gv_Ew_LAR).bits(),
Gv_Ew_LSL = OperandCodeBuilder::new().read_E().operand_case(OperandCase::Gv_Ew_LSL).bits(),
// Gdq_Ed = OperandCodeBuilder::new().read_E().operand_case(OperandCase::Gdq_Ed).bits(),
Gd_Ed = OperandCodeBuilder::new().read_E().operand_case(OperandCase::Gd_Ed).bits(),
@@ -7940,12 +7942,31 @@ fn read_operands<
instruction.regs[1].bank = RegisterBank::MM;
instruction.regs[1].num &= 0b111;
},
- OperandCase::Gv_Ew_LSL => {
+ OperandCase::Gv_Ew_LAR => {
instruction.operands[1] = mem_oper;
- // lsl is weird. the full register width is written, but only the low 16 bits are used.
- if instruction.operands[1] == OperandSpec::RegMMM {
- instruction.regs[1].bank = RegisterBank::D;
+ // lar is weird. a segment selector is taken from the source register, which means
+ // either we read the low 16-bits of a register or read 16 bits from a memory operand.
+ // for whatever reason, the intel manual writes a source register as a dword/qword for
+ // larger modes even though the upper 16 bits would be ignored.
+ //
+ // so the registers are correct by the time we're here, we might just need to override
+ // mem size as well.
+ if instruction.operands[1] != OperandSpec::RegMMM {
+ instruction.mem_size = 2;
+ }
+ instruction.regs[0].bank = if instruction.prefixes.operand_size() {
+ RegisterBank::W
} else {
+ RegisterBank::D
+ };
+ },
+ OperandCase::Gv_Ew_LSL => {
+ instruction.operands[1] = mem_oper;
+ // lsl is weird. a segment selector is taken from the source register, which means
+ // either we read the low 16-bits of a register or read 16 bits from a memory operand.
+ // for whatever reason, the intel manual writes a source register as a dword for larger
+ // modes even though the upper 16 bits would be ignored.
+ if instruction.operands[1] != OperandSpec::RegMMM {
instruction.mem_size = 2;
}
instruction.regs[0].bank = if instruction.prefixes.operand_size() {
@@ -10743,7 +10764,7 @@ fn read_modrm<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_
const REPNZ_0F_CODES: [OpcodeRecord; 256] = [
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f00),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f01),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew_LAR),
OpcodeRecord::new(Interpretation::Instruction(Opcode::LSL), OperandCode::Gv_Ew_LSL),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord::new(Interpretation::Instruction(Opcode::SYSCALL), OperandCode::Nothing),
@@ -11019,7 +11040,7 @@ const REPNZ_0F_CODES: [OpcodeRecord; 256] = [
const REP_0F_CODES: [OpcodeRecord; 256] = [
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f00),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f01),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew_LAR),
OpcodeRecord::new(Interpretation::Instruction(Opcode::LSL), OperandCode::Gv_Ew_LSL),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord::new(Interpretation::Instruction(Opcode::SYSCALL), OperandCode::Nothing),
@@ -11295,7 +11316,7 @@ const REP_0F_CODES: [OpcodeRecord; 256] = [
const OPERAND_SIZE_0F_CODES: [OpcodeRecord; 256] = [
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f00),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f01),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew_LAR),
OpcodeRecord::new(Interpretation::Instruction(Opcode::LSL), OperandCode::Gv_Ew_LSL),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord::new(Interpretation::Instruction(Opcode::SYSCALL), OperandCode::Nothing),
@@ -11568,7 +11589,7 @@ const OPERAND_SIZE_0F_CODES: [OpcodeRecord; 256] = [
const NORMAL_0F_CODES: [OpcodeRecord; 256] = [
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f00),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f01),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew_LAR),
OpcodeRecord::new(Interpretation::Instruction(Opcode::LSL), OperandCode::Gv_Ew_LSL),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord::new(Interpretation::Instruction(Opcode::SYSCALL), OperandCode::Nothing),
diff --git a/src/real_mode/mod.rs b/src/real_mode/mod.rs
index 924f46c..6765c1e 100644
--- a/src/real_mode/mod.rs
+++ b/src/real_mode/mod.rs
@@ -4936,6 +4936,7 @@ enum OperandCase {
AX_Ib,
Ib_AL,
Ib_AX,
+ Gv_Ew_LAR,
Gv_Ew_LSL,
// Gdq_Ev,
Gd_Ev,
@@ -5266,6 +5267,7 @@ enum OperandCode {
Zv_Iv_R7 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Iv_R, 7).bits(),
Gv_Eb = OperandCodeBuilder::new().read_E().operand_case(OperandCase::Gv_Eb).bits(),
Gv_Ew = OperandCodeBuilder::new().read_E().operand_case(OperandCase::Gv_Ew).bits(),
+ Gv_Ew_LAR = OperandCodeBuilder::new().read_E().operand_case(OperandCase::Gv_Ew_LAR).bits(),
Gv_Ew_LSL = OperandCodeBuilder::new().read_E().operand_case(OperandCase::Gv_Ew_LSL).bits(),
// Gdq_Ed = OperandCodeBuilder::new().read_E().operand_case(OperandCase::Gdq_Ed).bits(),
Gd_Ed = OperandCodeBuilder::new().read_E().operand_case(OperandCase::Gd_Ed).bits(),
@@ -7946,12 +7948,31 @@ fn read_operands<
instruction.regs[1].bank = RegisterBank::MM;
instruction.regs[1].num &= 0b111;
},
- OperandCase::Gv_Ew_LSL => {
+ OperandCase::Gv_Ew_LAR => {
instruction.operands[1] = mem_oper;
- // lsl is weird. the full register width is written, but only the low 16 bits are used.
- if instruction.operands[1] == OperandSpec::RegMMM {
- instruction.regs[1].bank = RegisterBank::W;
+ // lar is weird. a segment selector is taken from the source register, which means
+ // either we read the low 16-bits of a register or read 16 bits from a memory operand.
+ // for whatever reason, the intel manual writes a source register as a dword/qword for
+ // larger modes even though the upper 16 bits would be ignored.
+ //
+ // so the registers are correct by the time we're here, we might just need to override
+ // mem size as well.
+ if instruction.operands[1] != OperandSpec::RegMMM {
+ instruction.mem_size = 2;
+ }
+ instruction.regs[0].bank = if !instruction.prefixes.operand_size() {
+ RegisterBank::W
} else {
+ RegisterBank::D
+ };
+ },
+ OperandCase::Gv_Ew_LSL => {
+ instruction.operands[1] = mem_oper;
+ // lsl is weird. a segment selector is taken from the source register, which means
+ // either we read the low 16-bits of a register or read 16 bits from a memory operand.
+ // for whatever reason, the intel manual writes a source register as a dword for larger
+ // modes even though the upper 16 bits would be ignored.
+ if instruction.operands[1] != OperandSpec::RegMMM {
instruction.mem_size = 2;
}
instruction.regs[0].bank = if !instruction.prefixes.operand_size() {
@@ -10755,7 +10776,7 @@ fn read_modrm<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_
const REPNZ_0F_CODES: [OpcodeRecord; 256] = [
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f00),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f01),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew_LAR),
OpcodeRecord::new(Interpretation::Instruction(Opcode::LSL), OperandCode::Gv_Ew_LSL),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord::new(Interpretation::Instruction(Opcode::SYSCALL), OperandCode::Nothing),
@@ -11031,7 +11052,7 @@ const REPNZ_0F_CODES: [OpcodeRecord; 256] = [
const REP_0F_CODES: [OpcodeRecord; 256] = [
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f00),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f01),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew_LAR),
OpcodeRecord::new(Interpretation::Instruction(Opcode::LSL), OperandCode::Gv_Ew_LSL),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord::new(Interpretation::Instruction(Opcode::SYSCALL), OperandCode::Nothing),
@@ -11307,7 +11328,7 @@ const REP_0F_CODES: [OpcodeRecord; 256] = [
const OPERAND_SIZE_0F_CODES: [OpcodeRecord; 256] = [
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f00),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f01),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew_LAR),
OpcodeRecord::new(Interpretation::Instruction(Opcode::LSL), OperandCode::Gv_Ew_LSL),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord::new(Interpretation::Instruction(Opcode::SYSCALL), OperandCode::Nothing),
@@ -11580,7 +11601,7 @@ const OPERAND_SIZE_0F_CODES: [OpcodeRecord; 256] = [
const NORMAL_0F_CODES: [OpcodeRecord; 256] = [
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f00),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f01),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew_LAR),
OpcodeRecord::new(Interpretation::Instruction(Opcode::LSL), OperandCode::Gv_Ew_LSL),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord::new(Interpretation::Instruction(Opcode::SYSCALL), OperandCode::Nothing),
diff --git a/test/long_mode/mod.rs b/test/long_mode/mod.rs
index 9144dbe..3e6b700 100644
--- a/test/long_mode/mod.rs
+++ b/test/long_mode/mod.rs
@@ -2567,12 +2567,20 @@ fn strange_prefixing() {
#[test]
fn prefixed_0f() {
- test_display(&[0x0f, 0x02, 0xc0], "lar eax, ax");
- test_display(&[0x48, 0x0f, 0x02, 0xc0], "lar rax, ax");
- test_display(&[0x0f, 0x03, 0xc0], "lsl eax, eax");
- // capstone says `lsl rax, rax`, but xed says `rax, eax`. intel docs also say second reg should
+ test_display(&[0x0f, 0x02, 0x01], "lar eax, word [rcx]");
+ test_display(&[0x0f, 0x02, 0xc1], "lar eax, ecx");
+ test_display(&[0x4f, 0x0f, 0x02, 0x01], "lar r8, word [r9]");
+ test_display(&[0x4f, 0x0f, 0x02, 0xc1], "lar r8, r9");
+ test_display(&[0x66, 0x0f, 0x02, 0x01], "lar ax, word [rcx]");
+ test_display(&[0x66, 0x0f, 0x02, 0xc1], "lar ax, cx");
+ test_display(&[0x0f, 0x03, 0x01], "lsl eax, word [rcx]");
+ test_display(&[0x0f, 0x03, 0xc1], "lsl eax, ecx");
+ test_display(&[0x48, 0x0f, 0x03, 0x01], "lsl rax, word [rcx]");
+ // capstone says `lsl rax, rcx`, but xed says `rax, ecx`. intel docs also say second reg should
// be dword.
- test_display(&[0x48, 0x0f, 0x03, 0xc0], "lsl rax, eax");
+ test_display(&[0x48, 0x0f, 0x03, 0xc1], "lsl rax, ecx");
+ test_display(&[0x66, 0x0f, 0x03, 0x01], "lsl ax, word [rcx]");
+ test_display(&[0x66, 0x0f, 0x03, 0xc1], "lsl ax, cx");
test_display(&[0x0f, 0x05], "syscall");
test_display(&[0x48, 0x0f, 0x05], "syscall");
test_display(&[0x66, 0x0f, 0x05], "syscall");
diff --git a/test/protected_mode/mod.rs b/test/protected_mode/mod.rs
index 5229617..85d92ce 100644
--- a/test/protected_mode/mod.rs
+++ b/test/protected_mode/mod.rs
@@ -2270,8 +2270,14 @@ fn strange_prefixing() {
#[test]
fn prefixed_0f() {
- test_display(&[0x0f, 0x02, 0xc0], "lar eax, ax");
- test_display(&[0x0f, 0x03, 0xc0], "lsl eax, eax");
+ test_display(&[0x0f, 0x02, 0x01], "lar eax, word [ecx]");
+ test_display(&[0x0f, 0x02, 0xc1], "lar eax, ecx");
+ test_display(&[0x66, 0x0f, 0x02, 0x01], "lar ax, word [ecx]");
+ test_display(&[0x66, 0x0f, 0x02, 0xc1], "lar ax, cx");
+ test_display(&[0x0f, 0x03, 0x01], "lsl eax, word [ecx]");
+ test_display(&[0x0f, 0x03, 0xc1], "lsl eax, ecx");
+ test_display(&[0x66, 0x0f, 0x03, 0x01], "lsl ax, word [ecx]");
+ test_display(&[0x66, 0x0f, 0x03, 0xc1], "lsl ax, cx");
test_display(&[0x0f, 0x05], "syscall");
test_display(&[0x66, 0x0f, 0x05], "syscall");
test_display(&[0x0f, 0x06], "clts");
diff --git a/test/real_mode/mod.rs b/test/real_mode/mod.rs
index 7cf5fc2..2ae52d8 100644
--- a/test/real_mode/mod.rs
+++ b/test/real_mode/mod.rs
@@ -162,8 +162,10 @@ fn test_real_mode() {
test_display(&[0x0f, 0x01, 0xfb], "mwaitx");
test_display(&[0x0f, 0x01, 0xfc], "clzero");
test_display(&[0x0f, 0x01, 0xfd], "rdpru ecx");
- test_display(&[0x0f, 0x02, 0xc0], "lar ax, ax");
- test_display(&[0x0f, 0x03, 0xc0], "lsl ax, ax");
+ test_display(&[0x0f, 0x02, 0x01], "lar ax, word [bx + di * 1]");
+ test_display(&[0x0f, 0x02, 0xc1], "lar ax, cx");
+ test_display(&[0x0f, 0x03, 0x01], "lsl ax, word [bx + di * 1]");
+ test_display(&[0x0f, 0x03, 0xc1], "lsl ax, cx");
test_display(&[0x0f, 0x05], "syscall");
test_display(&[0x0f, 0x06], "clts");
test_display(&[0x0f, 0x07], "sysret");
@@ -16715,6 +16717,10 @@ fn test_real_mode() {
test_display(&[0x65, 0x89, 0x04], "mov word gs:[si], ax");
test_display(&[0x65, 0xf0, 0x87, 0x0f], "lock xchg word gs:[bx], cx");
test_display(&[0x66, 0x0f, 0x01, 0xd8], "vmrun ax");
+ test_display(&[0x66, 0x0f, 0x02, 0x01], "lar eax, word [bx + di * 1]");
+ test_display(&[0x66, 0x0f, 0x02, 0xc1], "lar eax, ecx");
+ test_display(&[0x66, 0x0f, 0x03, 0x01], "lsl eax, word [bx + di * 1]");
+ test_display(&[0x66, 0x0f, 0x03, 0xc1], "lsl eax, ecx");
test_display(&[0x66, 0x0f, 0x05], "syscall");
test_display(&[0x66, 0x0f, 0x0f, 0xc6, 0xb7], "pmulhrw mm0, mm6");
test_display(&[0x66, 0x0f, 0x10, 0xc0], "movupd xmm0, xmm0");
diff --git a/todo_notes b/todo_notes
deleted file mode 100644
index f0785d7..0000000
--- a/todo_notes
+++ /dev/null
@@ -1 +0,0 @@
-lsl seems just... wrong. check alternate prefixes in 32-/61-bit