aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2026-05-25 18:12:35 +0000
committeriximeow <me@iximeow.net>2026-05-25 18:12:35 +0000
commit426d092da378cb271d084632a20865952da395c6 (patch)
tree295a81fef7d5cf34a60cdccf8963298b734b5e8c
parentcb58e32ca672b01e773e189671a6868c1d7ed9b1 (diff)
reject arpl in 16-bit decoding
-rw-r--r--CHANGELOG1
-rw-r--r--src/real_mode/mod.rs14
-rw-r--r--test/real_mode/mod.rs2
3 files changed, 3 insertions, 14 deletions
diff --git a/CHANGELOG b/CHANGELOG
index aa4f5de..53df411 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -54,6 +54,7 @@ like raw instruction bytes.
* correct swapped operand order of 0xD6-opcode movq. in 32/16-bit, fix this opcode being decoded as vmovd.
* some instructions (such as invept, invvpid) were accepted by uarch-specific
deocders when they should not have been.
+* reject `arpl` in 16-bit decoding.
* disallow 66-prefixed `sha1rnds4`.
* mov seg-to-reg has more careful destination GPR selection.
* 64-bit: use 32-bit GPRs for the destination rather than 16-bit.
diff --git a/src/real_mode/mod.rs b/src/real_mode/mod.rs
index 06b6c68..cc67de7 100644
--- a/src/real_mode/mod.rs
+++ b/src/real_mode/mod.rs
@@ -3966,7 +3966,6 @@ enum OperandCase {
Yb_AL,
Yb_Xb,
Yv_AX,
- Ew_Gw,
ES,
CS,
SS,
@@ -4319,7 +4318,6 @@ enum OperandCode {
Yb_AL = OperandCodeBuilder::new().operand_case(OperandCase::Yb_AL).bits(),
Yb_Xb = OperandCodeBuilder::new().operand_case(OperandCase::Yb_Xb).bits(),
Yv_AX = OperandCodeBuilder::new().operand_case(OperandCase::Yv_AX).bits(),
- Ew_Gw = OperandCodeBuilder::new().operand_case(OperandCase::Ew_Gw).bits(),
ES = OperandCodeBuilder::new().operand_case(OperandCase::ES).bits(),
CS = OperandCodeBuilder::new().operand_case(OperandCase::CS).bits(),
SS = OperandCodeBuilder::new().operand_case(OperandCase::SS).bits(),
@@ -4496,7 +4494,7 @@ const OPCODES: [OpcodeRecord; 256] = [
OpcodeRecord::new(Interpretation::Instruction(Opcode::PUSHA), OperandCode::Nothing),
OpcodeRecord::new(Interpretation::Instruction(Opcode::POPA), OperandCode::Nothing),
OpcodeRecord::new(Interpretation::Instruction(Opcode::BOUND), OperandCode::ModRM_0x62),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::ARPL), OperandCode::Ew_Gw),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord::new(Interpretation::Prefix, OperandCode::Nothing),
OpcodeRecord::new(Interpretation::Prefix, OperandCode::Nothing),
OpcodeRecord::new(Interpretation::Prefix, OperandCode::Nothing),
@@ -9067,16 +9065,6 @@ fn read_operands<
instruction.imm = read_num(words, addr_size)?;
instruction.disp = read_num(words, 2)? as u16 as u32;
}
- OperandCase::Ew_Gw => {
- let modrm = read_modrm(words)?;
-
- instruction.regs[0] =
- RegSpec { bank: RegisterBank::W, num: (modrm >> 3) & 7 };
- instruction.operands[0] = read_E(words, instruction, modrm, RegisterBank::W, sink)?;
- instruction.operands[1] = OperandSpec::RegRRR;
- instruction.mem_size = 2;
- instruction.operand_count = 2;
- },
OperandCase::CXZ => {
if instruction.prefixes.address_size() {
// address-size overridden from 16-bit to 32-bit
diff --git a/test/real_mode/mod.rs b/test/real_mode/mod.rs
index bce199b..33ac3d2 100644
--- a/test/real_mode/mod.rs
+++ b/test/real_mode/mod.rs
@@ -16854,7 +16854,7 @@ fn test_real_mode() {
test_invalid(&[0x62, 0xf3, 0xfd, 0x18, 0x44, 0x0a, 0xcc]); //
test_invalid(&[0x62, 0xf3, 0xfd, 0x88, 0x44, 0x0a, 0xcc]); //
test_invalid(&[0x62, 0xf3, 0xfd, 0xbd, 0x66, 0x0a, 0xcc]); // no zero mask-merge
- test_display(&[0x63, 0xc1], "arpl cx, ax");
+ test_invalid(&[0x63, 0xc1]); // no arpl in real mode
test_display(&[0x65, 0x66, 0x0f, 0x01, 0xdc], "stgi");
test_display(&[0x65, 0x66, 0x66, 0x64, 0x0f, 0x38, 0xdb, 0x0f], "aesimc xmm1, xmmword fs:[bx]");
test_display(&[0x65, 0x67, 0x65, 0x65, 0x0f, 0x0e], "femms");