aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2026-06-10 06:26:42 +0000
committeriximeow <me@iximeow.net>2026-07-05 00:09:22 +0000
commit6e2976bda74148e0c3cd50788b603c4933f9f50b (patch)
treee89a780a4882e0132250784b14266c9a22757f0b
parent1862b315950a477390435a52b6061bf5948977c4 (diff)
protected/real mode lfs/lgs/lss
-rw-r--r--CHANGELOG4
-rw-r--r--src/protected_mode/mod.rs23
-rw-r--r--src/real_mode/mod.rs19
-rw-r--r--test/protected_mode/mod.rs4
4 files changed, 30 insertions, 20 deletions
diff --git a/CHANGELOG b/CHANGELOG
index a437a4f..ae3baf7 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -24,6 +24,10 @@
these instructions consume 8 bit of immediate as several fields compressed into 8 bits, rather
than as a numeric value, so sign extension is not useful. further, extending the immediate makes
it more difficult to round-trip disassembly through other assemblers.
+* fix vmread/vmwrite reporting 8-byte accesses outside long mode; they are 4-byte accesses in
+ protected and real modes.
+* fix lfs/lgs/lss loading into dword registers when operating with a short (16-bit segment/offset) pointer.
+ in these cases, the offset is loaded into a 16-bit register, not 32-bit. the upper 32 bits are unchanged.
testing instruction round-tripping through `masm` found a few bugs, which are also fixed in this release:
diff --git a/src/protected_mode/mod.rs b/src/protected_mode/mod.rs
index 8bf15a4..a3e6a96 100644
--- a/src/protected_mode/mod.rs
+++ b/src/protected_mode/mod.rs
@@ -3915,8 +3915,8 @@ enum OperandCase {
G_mm_U_mm,
G_Mq_mm,
G_mm_Ew_Ib,
- G_E_q,
- E_G_q,
+ G_E_d,
+ E_G_d,
CVT_AA,
CVT_DA,
Rq_Cq_0,
@@ -4268,8 +4268,8 @@ enum OperandCode {
G_mm_U_mm = OperandCodeBuilder::new().read_E().reg_mem().operand_case(OperandCase::G_mm_U_mm).bits(),
G_Mq_mm = OperandCodeBuilder::new().read_E().reg_mem().operand_case(OperandCase::G_Mq_mm).bits(),
G_mm_Ew_Ib = OperandCodeBuilder::new().read_E().operand_case(OperandCase::G_mm_Ew_Ib).bits(),
- G_E_q = OperandCodeBuilder::new().read_E().operand_case(OperandCase::G_E_q).bits(),
- E_G_q = OperandCodeBuilder::new().read_E().operand_case(OperandCase::E_G_q).bits(),
+ G_E_d = OperandCodeBuilder::new().read_E().operand_case(OperandCase::G_E_d).bits(),
+ E_G_d = OperandCodeBuilder::new().read_E().operand_case(OperandCase::E_G_d).bits(),
CVT_AA = OperandCodeBuilder::new().operand_case(OperandCase::CVT_AA).bits(),
CVT_DA = OperandCodeBuilder::new().operand_case(OperandCase::CVT_DA).bits(),
Rq_Cq_0 = OperandCodeBuilder::new().operand_case(OperandCase::Rq_Cq_0).bits(),
@@ -6664,6 +6664,7 @@ fn read_operands<
instruction.operands[1] = mem_oper;
if [Opcode::LFS, Opcode::LGS, Opcode::LSS].contains(&instruction.opcode) {
if instruction.prefixes.operand_size() {
+ instruction.regs[0].bank = RegisterBank::W;
instruction.mem_size = 4;
} else {
instruction.mem_size = 6;
@@ -7104,7 +7105,7 @@ fn read_operands<
instruction.mem_size = 8;
instruction.operand_count = 2;
},
- OperandCase::E_G_q => {
+ OperandCase::E_G_d => {
if instruction.prefixes.operand_size() {
return Err(DecodeError::InvalidOpcode);
}
@@ -7114,12 +7115,13 @@ fn read_operands<
instruction.regs[0].bank = RegisterBank::D;
instruction.operand_count = 2;
if instruction.operands[0] != OperandSpec::RegMMM {
- instruction.mem_size = 8;
+ // outside 64-bit mode the memory access is four bytes as well.
+ instruction.mem_size = 4;
} else {
instruction.regs[1].bank = RegisterBank::D;
}
}
- OperandCase::G_E_q => {
+ OperandCase::G_E_d => {
if instruction.prefixes.operand_size() {
return Err(DecodeError::InvalidOpcode);
}
@@ -7129,7 +7131,8 @@ fn read_operands<
instruction.regs[0].bank = RegisterBank::D;
instruction.operand_count = 2;
if instruction.operands[1] != OperandSpec::RegMMM {
- instruction.mem_size = 8;
+ // outside 64-bit mode the memory access is four bytes as well.
+ instruction.mem_size = 4;
} else {
instruction.regs[1].bank = RegisterBank::D;
}
@@ -10811,8 +10814,8 @@ const NORMAL_0F_CODES: [OpcodeRecord; 256] = [
OpcodeRecord::new(Interpretation::Instruction(Opcode::PCMPEQW), OperandCode::G_E_mm),
OpcodeRecord::new(Interpretation::Instruction(Opcode::PCMPEQD), OperandCode::G_E_mm),
OpcodeRecord::new(Interpretation::Instruction(Opcode::EMMS), OperandCode::Nothing),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::VMREAD), OperandCode::E_G_q),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::VMWRITE), OperandCode::G_E_q),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::VMREAD), OperandCode::E_G_d),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::VMWRITE), OperandCode::G_E_d),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
diff --git a/src/real_mode/mod.rs b/src/real_mode/mod.rs
index 8d4e4dd..ba50394 100644
--- a/src/real_mode/mod.rs
+++ b/src/real_mode/mod.rs
@@ -3942,8 +3942,8 @@ enum OperandCase {
G_mm_U_mm,
G_Mq_mm,
G_mm_Ew_Ib,
- G_E_q,
- E_G_q,
+ G_E_d,
+ E_G_d,
CVT_AA,
CVT_DA,
Rq_Cq_0,
@@ -4294,8 +4294,8 @@ enum OperandCode {
G_mm_U_mm = OperandCodeBuilder::new().read_E().reg_mem().operand_case(OperandCase::G_mm_U_mm).bits(),
G_Mq_mm = OperandCodeBuilder::new().read_E().reg_mem().operand_case(OperandCase::G_Mq_mm).bits(),
G_mm_Ew_Ib = OperandCodeBuilder::new().read_E().operand_case(OperandCase::G_mm_Ew_Ib).bits(),
- G_E_q = OperandCodeBuilder::new().read_E().operand_case(OperandCase::G_E_q).bits(),
- E_G_q = OperandCodeBuilder::new().read_E().operand_case(OperandCase::E_G_q).bits(),
+ G_E_d = OperandCodeBuilder::new().read_E().operand_case(OperandCase::G_E_d).bits(),
+ E_G_d = OperandCodeBuilder::new().read_E().operand_case(OperandCase::E_G_d).bits(),
CVT_AA = OperandCodeBuilder::new().operand_case(OperandCase::CVT_AA).bits(),
CVT_DA = OperandCodeBuilder::new().operand_case(OperandCase::CVT_DA).bits(),
Rq_Cq_0 = OperandCodeBuilder::new().operand_case(OperandCase::Rq_Cq_0).bits(),
@@ -6704,6 +6704,7 @@ fn read_operands<
instruction.operands[1] = mem_oper;
if [Opcode::LFS, Opcode::LGS, Opcode::LSS].contains(&instruction.opcode) {
if !instruction.prefixes.operand_size() {
+ instruction.regs[0].bank = RegisterBank::W;
instruction.mem_size = 4;
} else {
instruction.mem_size = 6;
@@ -7146,7 +7147,7 @@ fn read_operands<
instruction.mem_size = 8;
instruction.operand_count = 2;
},
- OperandCase::E_G_q => {
+ OperandCase::E_G_d => {
if instruction.prefixes.operand_size() {
return Err(DecodeError::InvalidOpcode);
}
@@ -7156,12 +7157,13 @@ fn read_operands<
instruction.regs[0].bank = RegisterBank::D;
instruction.operand_count = 2;
if instruction.operands[0] != OperandSpec::RegMMM {
+ // outside 64-bit mode the memory access is four bytes as well.
instruction.mem_size = 4;
} else {
instruction.regs[1].bank = RegisterBank::D;
}
}
- OperandCase::G_E_q => {
+ OperandCase::G_E_d => {
if instruction.prefixes.operand_size() {
return Err(DecodeError::InvalidOpcode);
}
@@ -7171,6 +7173,7 @@ fn read_operands<
instruction.regs[0].bank = RegisterBank::D;
instruction.operand_count = 2;
if instruction.operands[1] != OperandSpec::RegMMM {
+ // outside 64-bit mode the memory access is four bytes as well.
instruction.mem_size = 4;
} else {
instruction.regs[1].bank = RegisterBank::D;
@@ -10870,8 +10873,8 @@ const NORMAL_0F_CODES: [OpcodeRecord; 256] = [
OpcodeRecord::new(Interpretation::Instruction(Opcode::PCMPEQW), OperandCode::G_E_mm),
OpcodeRecord::new(Interpretation::Instruction(Opcode::PCMPEQD), OperandCode::G_E_mm),
OpcodeRecord::new(Interpretation::Instruction(Opcode::EMMS), OperandCode::Nothing),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::VMREAD), OperandCode::E_G_q),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::VMWRITE), OperandCode::G_E_q),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::VMREAD), OperandCode::E_G_d),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::VMWRITE), OperandCode::G_E_d),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
diff --git a/test/protected_mode/mod.rs b/test/protected_mode/mod.rs
index 6cf4cc5..7fb3b77 100644
--- a/test/protected_mode/mod.rs
+++ b/test/protected_mode/mod.rs
@@ -3673,9 +3673,9 @@ mod svm {
testcase!(&[0x0f, 0x01, 0xd8], "vmrun eax"),
testcase!(&[0x0f, 0x78, 0xc4], "vmread esp, eax"),
testcase!(&[0x0f, 0x79, 0xc5], "vmwrite eax, ebp"),
- testcase!(&[0x0f, 0x78, 0x0b], "vmread qword [ebx], ecx"),
+ testcase!(&[0x0f, 0x78, 0x0b], "vmread dword [ebx], ecx"),
testcase!(invalid: &[0x66, 0x0f, 0x78, 0x03]),
- testcase!(&[0x0f, 0x79, 0x0b], "vmwrite ecx, qword [ebx]"),
+ testcase!(&[0x0f, 0x79, 0x0b], "vmwrite ecx, dword [ebx]"),
testcase!(invalid: &[0x66, 0x0f, 0x79, 0x03]),
];