aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2026-06-10 06:27:44 +0000
committeriximeow <me@iximeow.net>2026-07-05 00:09:22 +0000
commitb4ac152946d3a1dd0f4e0d48b8b73f2152a1e2e0 (patch)
tree4d5eaa7023c39da54c32fcb38e1c45cbb5dd326b
parent6e2976bda74148e0c3cd50788b603c4933f9f50b (diff)
fix some forms of lss/lfs/lgs having incorrectly-small memory sizes
-rw-r--r--CHANGELOG3
-rw-r--r--src/protected_mode/mod.rs6
-rw-r--r--src/real_mode/mod.rs6
-rw-r--r--test/long_mode/mod.rs10
-rw-r--r--test/protected_mode/mod.rs9
5 files changed, 26 insertions, 8 deletions
diff --git a/CHANGELOG b/CHANGELOG
index ae3baf7..888017b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -28,6 +28,9 @@
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.
+* fix 32/16-bit unprefixed lfs/lgs/lss reporting too-small memory read. in both modes
+ these instructions could be decoded as reading only an offset, rather than an offset (into the
+ destination register) and segment (into ss)
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 a3e6a96..6c0e674 100644
--- a/src/protected_mode/mod.rs
+++ b/src/protected_mode/mod.rs
@@ -10599,10 +10599,10 @@ const OPERAND_SIZE_0F_CODES: [OpcodeRecord; 256] = [
// 0xb0
OpcodeRecord::new(Interpretation::Instruction(Opcode::CMPXCHG), OperandCode::Eb_Gb),
OpcodeRecord::new(Interpretation::Instruction(Opcode::CMPXCHG), OperandCode::Ev_Gv),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::LSS), OperandCode::Gv_M),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::LSS), OperandCode::INV_Gv_M),
OpcodeRecord::new(Interpretation::Instruction(Opcode::BTR), OperandCode::Ev_Gv),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::LFS), OperandCode::Gv_M),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::LGS), OperandCode::Gv_M),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::LFS), OperandCode::INV_Gv_M),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::LGS), OperandCode::INV_Gv_M),
OpcodeRecord::new(Interpretation::Instruction(Opcode::MOVZX), OperandCode::Gv_Eb),
OpcodeRecord::new(Interpretation::Instruction(Opcode::MOVZX), OperandCode::Gv_Ew),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
diff --git a/src/real_mode/mod.rs b/src/real_mode/mod.rs
index ba50394..274d472 100644
--- a/src/real_mode/mod.rs
+++ b/src/real_mode/mod.rs
@@ -10658,10 +10658,10 @@ const OPERAND_SIZE_0F_CODES: [OpcodeRecord; 256] = [
// 0xb0
OpcodeRecord::new(Interpretation::Instruction(Opcode::CMPXCHG), OperandCode::Eb_Gb),
OpcodeRecord::new(Interpretation::Instruction(Opcode::CMPXCHG), OperandCode::Ev_Gv),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::LSS), OperandCode::Gv_M),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::LSS), OperandCode::INV_Gv_M),
OpcodeRecord::new(Interpretation::Instruction(Opcode::BTR), OperandCode::Ev_Gv),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::LFS), OperandCode::Gv_M),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::LGS), OperandCode::Gv_M),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::LFS), OperandCode::INV_Gv_M),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::LGS), OperandCode::INV_Gv_M),
OpcodeRecord::new(Interpretation::Instruction(Opcode::MOVZX), OperandCode::Gv_Eb),
OpcodeRecord::new(Interpretation::Instruction(Opcode::MOVZX), OperandCode::Gv_Ew),
OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
diff --git a/test/long_mode/mod.rs b/test/long_mode/mod.rs
index fb38840..de113d3 100644
--- a/test/long_mode/mod.rs
+++ b/test/long_mode/mod.rs
@@ -1893,11 +1893,21 @@ mod system {
use crate::long_mode::{TestCase, run_test};
const CASES: &'static [TestCase] = &[
+ testcase!(&[0x0f, 0xb2, 0x00], "lss eax, far [rax]"),
+ testcase!(&[0x0f, 0xb4, 0x00], "lfs eax, far [rax]"),
+ testcase!(&[0x0f, 0xb5, 0x00], "lgs eax, far [rax]"),
+ testcase!(&[0x48, 0x0f, 0xb2, 0x00], "lss rax, mword [rax]"),
+ testcase!(&[0x48, 0x0f, 0xb4, 0x00], "lfs rax, mword [rax]"),
+ testcase!(&[0x48, 0x0f, 0xb5, 0x00], "lgs rax, mword [rax]"),
testcase!(&[0x66, 0x4f, 0x0f, 0xb2, 0x00], "lss r8, mword [r8]"),
testcase!(&[0x67, 0x4f, 0x0f, 0xb2, 0x00], "lss r8, mword [r8d]"),
testcase!(&[0x4f, 0x0f, 0xb2, 0x00], "lss r8, mword [r8]"),
+ testcase!(&[0x4f, 0x0f, 0xb4, 0x00], "lfs r8, mword [r8]"),
+ testcase!(&[0x4f, 0x0f, 0xb5, 0x00], "lgs r8, mword [r8]"),
testcase!(&[0x0f, 0xb2, 0x00], "lss eax, far [rax]"),
testcase!(&[0x66, 0x0f, 0xb2, 0x00], "lss ax, dword [rax]"),
+ testcase!(&[0x66, 0x0f, 0xb4, 0x00], "lfs ax, dword [rax]"),
+ testcase!(&[0x66, 0x0f, 0xb5, 0x00], "lgs ax, dword [rax]"),
testcase!(invalid: &[0x45, 0x0f, 0x22, 0xc8]),
testcase!(invalid: &[0x45, 0x0f, 0x20, 0xc8]),
testcase!(&[0x40, 0x0f, 0x22, 0xd0], "mov cr2, rax"),
diff --git a/test/protected_mode/mod.rs b/test/protected_mode/mod.rs
index 7fb3b77..2b1cc70 100644
--- a/test/protected_mode/mod.rs
+++ b/test/protected_mode/mod.rs
@@ -1829,12 +1829,17 @@ mod system {
use crate::protected_mode::{TestCase, run_test};
const CASES: &'static [TestCase] = &[
+ testcase!(&[0x0f, 0xb2, 0x00], "lss eax, far [eax]"),
+ testcase!(&[0x0f, 0xb4, 0x00], "lfs eax, far [eax]"),
+ testcase!(&[0x0f, 0xb5, 0x00], "lgs eax, far [eax]"),
testcase!(&[0x63, 0xc1], "arpl cx, ax"),
testcase!(&[0x63, 0x04, 0xba], "arpl word [edx + edi * 4], ax"),
- testcase!(&[0x66, 0x0f, 0xb2, 0x00], "lss ax, word [eax]"),
+ testcase!(&[0x66, 0x0f, 0xb2, 0x00], "lss ax, dword [eax]"),
+ testcase!(&[0x66, 0x0f, 0xb4, 0x00], "lfs ax, dword [eax]"),
+ testcase!(&[0x66, 0x0f, 0xb5, 0x00], "lgs ax, dword [eax]"),
testcase!(&[0x67, 0x0f, 0xb2, 0x00], "lss eax, far [bx + si * 1]"),
testcase!(&[0x0f, 0xb2, 0x00], "lss eax, far [eax]"),
- testcase!(&[0x66, 0x0f, 0xb2, 0x00], "lss ax, word [eax]"),
+ testcase!(&[0x66, 0x0f, 0xb2, 0x00], "lss ax, dword [eax]"),
testcase!(invalid: &[0x0f, 0x22, 0xc8]),
testcase!(invalid: &[0x0f, 0x20, 0xc8]),
testcase!(&[0x0f, 0x22, 0xd0], "mov cr2, eax"),