From 4cd679679bb00bbdc170a8e74d31126b11c312c7 Mon Sep 17 00:00:00 2001 From: Ledmington Date: Sat, 9 May 2026 16:02:36 +0200 Subject: [PATCH 1/2] Renamed InstructionPrefix -> LegacyPrefix --- .../ledmington/cpu/InstructionDecoder.java | 30 +++++----- .../ledmington/cpu/InstructionEncoder.java | 8 +-- .../cpu/x86/GeneralInstruction.java | 14 ++--- .../com/ledmington/cpu/x86/Instruction.java | 8 +-- .../cpu/x86/InstructionBuilder.java | 4 +- ...structionPrefix.java => LegacyPrefix.java} | 8 +-- .../java/com/ledmington/cpu/x86/Prefixes.java | 2 +- .../java/com/ledmington/cpu/X64Encodings.java | 60 +++++++++---------- 8 files changed, 67 insertions(+), 67 deletions(-) rename id/src/main/java/com/ledmington/cpu/x86/{InstructionPrefix.java => LegacyPrefix.java} (90%) diff --git a/id/src/main/java/com/ledmington/cpu/InstructionDecoder.java b/id/src/main/java/com/ledmington/cpu/InstructionDecoder.java index 0a37fc44..b0b2082e 100644 --- a/id/src/main/java/com/ledmington/cpu/InstructionDecoder.java +++ b/id/src/main/java/com/ledmington/cpu/InstructionDecoder.java @@ -45,7 +45,7 @@ import com.ledmington.cpu.x86.IndirectOperandBuilder; import com.ledmington.cpu.x86.Instruction; import com.ledmington.cpu.x86.InstructionBuilder; -import com.ledmington.cpu.x86.InstructionPrefix; +import com.ledmington.cpu.x86.LegacyPrefix; import com.ledmington.cpu.x86.MaskRegister; import com.ledmington.cpu.x86.ModRM; import com.ledmington.cpu.x86.NullRegister; @@ -144,7 +144,7 @@ public static Instruction fromIntelSyntax(final String input) { String opcodeString = readUntilWhitespace(it); if ("lock".equals(opcodeString) || "rep".equals(opcodeString) || "repnz".equals(opcodeString)) { final String finalOpcodeString = opcodeString; - ib.prefix(Arrays.stream(InstructionPrefix.values()) + ib.prefix(Arrays.stream(LegacyPrefix.values()) .filter(p -> p.name().toLowerCase(Locale.US).equals(finalOpcodeString)) .findAny() .orElseThrow()); @@ -599,7 +599,7 @@ yield isIndirectOperandNeeded(modrm) !pref.hasAddressSizeOverridePrefix(), pref.rex().hasModRMRMExtension(), pref.hasOperandSizeOverridePrefix())); - if (pref.p1().isPresent() && pref.p1().orElseThrow() == InstructionPrefix.REPNZ) { + if (pref.p1().isPresent() && pref.p1().orElseThrow() == LegacyPrefix.REPNZ) { ib.opcode(Opcode.BND_JMP); } else { ib.opcode(Opcode.JMP); @@ -1356,7 +1356,7 @@ private static Instruction parse2BytesOpcode( yield Instruction.builder().opcode(Opcode.ENDBR64).build(); } else if (x == (byte) 0xfb) { yield Instruction.builder().opcode(Opcode.ENDBR32).build(); - } else if (pref.p1().isPresent() && pref.p1().orElseThrow() == InstructionPrefix.REP) { + } else if (pref.p1().isPresent() && pref.p1().orElseThrow() == LegacyPrefix.REP) { final ModRM modrm = new ModRM(x); yield Instruction.builder() .opcode(Opcode.RDSSPQ) @@ -1515,7 +1515,7 @@ private static Instruction parse2BytesOpcode( } case BSF_OPCODE -> { final ModRM modrm = modrm(b); - final boolean hasRepPrefix = pref.p1().isPresent() && pref.p1().orElseThrow() == InstructionPrefix.REP; + final boolean hasRepPrefix = pref.p1().isPresent() && pref.p1().orElseThrow() == LegacyPrefix.REP; yield Instruction.builder() .opcode(hasRepPrefix ? Opcode.TZCNT : Opcode.BSF) .op(Registers.fromCode( @@ -1642,7 +1642,7 @@ yield new GeneralInstruction( final byte r1 = getByteFromReg(pref.rex(), modrm); final byte r2 = getByteFromRM(pref, modrm); final boolean movdqa = pref.hasOperandSizeOverridePrefix(); - final boolean movdqu = pref.p1().isPresent() && pref.p1().orElseThrow() == InstructionPrefix.REP; + final boolean movdqu = pref.p1().isPresent() && pref.p1().orElseThrow() == LegacyPrefix.REP; yield Instruction.builder() .opcode(movdqa ? Opcode.MOVDQA : (movdqu ? Opcode.MOVDQU : Opcode.MOVQ)) .op((movdqa || movdqu) ? RegisterXMM.fromByte(r1) : RegisterMMX.fromByte(modrm.reg())) @@ -2015,7 +2015,7 @@ yield new GeneralInstruction( final ModRM modrm = modrm(b); final InstructionBuilder ib = Instruction.builder(); ib.op(RegisterXMM.fromByte(getByteFromReg(pref.rex(), modrm))); - if (pref.p1().isPresent() && pref.p1().orElseThrow() == InstructionPrefix.REP) { + if (pref.p1().isPresent() && pref.p1().orElseThrow() == LegacyPrefix.REP) { ib.opcode(Opcode.DIVSS) .op( isIndirectOperandNeeded(modrm) @@ -2023,7 +2023,7 @@ yield new GeneralInstruction( .pointer(PointerSize.DWORD_PTR) .build() : RegisterXMM.fromByte(getByteFromRM(pref, modrm))); - } else if (pref.p1().isPresent() && pref.p1().orElseThrow() == InstructionPrefix.REPNZ) { + } else if (pref.p1().isPresent() && pref.p1().orElseThrow() == LegacyPrefix.REPNZ) { ib.opcode(Opcode.DIVSD) .op( isIndirectOperandNeeded(modrm) @@ -2196,7 +2196,7 @@ yield new GeneralInstruction( case MOVSD_OPCODE -> { final ModRM modrm = modrm(b); final boolean hasRepnePrefix = - pref.p1().isPresent() && pref.p1().orElseThrow() == InstructionPrefix.REPNZ; + pref.p1().isPresent() && pref.p1().orElseThrow() == LegacyPrefix.REPNZ; yield Instruction.builder() .opcode(hasRepnePrefix ? Opcode.MOVSD : Opcode.MOVUPS) .op(RegisterXMM.fromByte(getByteFromReg(pref.rex(), modrm))) @@ -2431,7 +2431,7 @@ private static Instruction parseExtendedOpcodeGroup9( }; } - if (pref.p1().isPresent() && pref.p1().orElseThrow() == InstructionPrefix.REP) { + if (pref.p1().isPresent() && pref.p1().orElseThrow() == LegacyPrefix.REP) { notImplemented(); } @@ -4415,7 +4415,7 @@ private static void invalidValue() { } private static Prefixes parsePrefixes(final ReadOnlyByteBuffer b) { - Optional p1 = Optional.empty(); // Legacy Prefix Group 1 + Optional p1 = Optional.empty(); // Legacy Prefix Group 1 Optional p2 = Optional.empty(); // Legacy Prefix Group 2 boolean hasOperandSizeOverridePrefix = false; boolean hasAddressSizeOverridePrefix = false; @@ -4426,7 +4426,7 @@ private static Prefixes parsePrefixes(final ReadOnlyByteBuffer b) { final byte x = b.read1(); if (isLegacyPrefixGroup1(x)) { - p1 = Optional.of(InstructionPrefix.fromByte(x)); + p1 = Optional.of(LegacyPrefix.fromByte(x)); } else if (isLegacyPrefixGroup2(x)) { p2 = Optional.of(x); } else if (isOperandSizeOverridePrefix(x)) { @@ -4662,9 +4662,9 @@ private static void notImplemented() { } private static boolean isLegacyPrefixGroup1(final byte prefix) { - return prefix == InstructionPrefix.LOCK.getCode() - || prefix == InstructionPrefix.REPNZ.getCode() - || prefix == InstructionPrefix.REP.getCode(); + return prefix == LegacyPrefix.LOCK.getCode() + || prefix == LegacyPrefix.REPNZ.getCode() + || prefix == LegacyPrefix.REP.getCode(); } private static boolean isLegacyPrefixGroup2(final byte prefix) { diff --git a/id/src/main/java/com/ledmington/cpu/InstructionEncoder.java b/id/src/main/java/com/ledmington/cpu/InstructionEncoder.java index 57d59bf7..67a3f2e6 100644 --- a/id/src/main/java/com/ledmington/cpu/InstructionEncoder.java +++ b/id/src/main/java/com/ledmington/cpu/InstructionEncoder.java @@ -33,7 +33,7 @@ import com.ledmington.cpu.x86.Immediate; import com.ledmington.cpu.x86.IndirectOperand; import com.ledmington.cpu.x86.Instruction; -import com.ledmington.cpu.x86.InstructionPrefix; +import com.ledmington.cpu.x86.LegacyPrefix; import com.ledmington.cpu.x86.MaskRegister; import com.ledmington.cpu.x86.Opcode; import com.ledmington.cpu.x86.Operand; @@ -330,7 +330,7 @@ private static void encodePrefixes(final WriteOnlyByteBuffer wb, final Instructi wb.write(OPERAND_SIZE_OVERRIDE_PREFIX); } if (inst.hasLockPrefix()) { - wb.write(InstructionPrefix.LOCK.getCode()); + wb.write(LegacyPrefix.LOCK.getCode()); } if (inst.hasRepPrefix() || (inst.opcode() == Opcode.RDSSPQ @@ -341,7 +341,7 @@ private static void encodePrefixes(final WriteOnlyByteBuffer wb, final Instructi || (((inst.opcode() == Opcode.MOVQ || inst.opcode() == Opcode.MOVDQU) && isFirstXMM(inst) && isSecondM(inst)))) { - wb.write(InstructionPrefix.REP.getCode()); + wb.write(LegacyPrefix.REP.getCode()); } if (inst.hasRepnzPrefix() || ((inst.opcode() == Opcode.MOVSD && isFirstXMM(inst) && isSecondM(inst)) @@ -350,7 +350,7 @@ && isSecondM(inst)))) { || (inst.opcode() == Opcode.ADDSD) || (inst.opcode() == Opcode.LDDQU) || (inst.opcode() == Opcode.BND_JMP))) { - wb.write(InstructionPrefix.REPNZ.getCode()); + wb.write(LegacyPrefix.REPNZ.getCode()); } // TODO: maybe refactor this into 'checkRequiredPrefix'? diff --git a/id/src/main/java/com/ledmington/cpu/x86/GeneralInstruction.java b/id/src/main/java/com/ledmington/cpu/x86/GeneralInstruction.java index ae099b24..0dd77b47 100644 --- a/id/src/main/java/com/ledmington/cpu/x86/GeneralInstruction.java +++ b/id/src/main/java/com/ledmington/cpu/x86/GeneralInstruction.java @@ -22,7 +22,7 @@ /** Most general implementation of an x86 instruction. */ public final class GeneralInstruction implements Instruction { - private final InstructionPrefix prefix; + private final LegacyPrefix prefix; private final Opcode code; private final MaskRegister destinationMask; private final boolean destinationMaskZero; @@ -32,7 +32,7 @@ public final class GeneralInstruction implements Instruction { private final Operand op4; /* default */ GeneralInstruction( - final InstructionPrefix prefix, + final LegacyPrefix prefix, final Opcode opcode, final MaskRegister destinationMask, final boolean destinationMaskZero, @@ -73,7 +73,7 @@ public final class GeneralInstruction implements Instruction { * @param secondOperand The second operand of the Instruction. */ public GeneralInstruction( - final InstructionPrefix prefix, + final LegacyPrefix prefix, final Opcode opcode, final Operand firstOperand, final Operand secondOperand) { @@ -103,7 +103,7 @@ public GeneralInstruction( * @param thirdOperand The third operand of the Instruction. */ public GeneralInstruction( - final InstructionPrefix prefix, + final LegacyPrefix prefix, final Opcode opcode, final Operand firstOperand, final Operand secondOperand, @@ -147,7 +147,7 @@ public GeneralInstruction(final Opcode opcode, final Operand firstOperand, final * @param opcode The opcode of the Instruction. * @param firstOperand The first operand of the Instruction. */ - public GeneralInstruction(final InstructionPrefix prefix, final Opcode opcode, final Operand firstOperand) { + public GeneralInstruction(final LegacyPrefix prefix, final Opcode opcode, final Operand firstOperand) { this(prefix, opcode, null, false, firstOperand, null, null, null); } @@ -157,7 +157,7 @@ public GeneralInstruction(final InstructionPrefix prefix, final Opcode opcode, f * @param prefix The prefix of the Instruction. * @param opcode The opcode of the Instruction. */ - public GeneralInstruction(final InstructionPrefix prefix, final Opcode opcode) { + public GeneralInstruction(final LegacyPrefix prefix, final Opcode opcode) { this(prefix, opcode, null, false, null, null, null, null); } @@ -186,7 +186,7 @@ public boolean hasPrefix() { } @Override - public InstructionPrefix getPrefix() { + public LegacyPrefix getPrefix() { if (!hasPrefix()) { throw new IllegalArgumentException("No prefix."); } diff --git a/id/src/main/java/com/ledmington/cpu/x86/Instruction.java b/id/src/main/java/com/ledmington/cpu/x86/Instruction.java index 2042d918..55f1a7d5 100644 --- a/id/src/main/java/com/ledmington/cpu/x86/Instruction.java +++ b/id/src/main/java/com/ledmington/cpu/x86/Instruction.java @@ -138,7 +138,7 @@ default Operand operand(final int operandIndex) { * * @return The prefix of this instruction. */ - InstructionPrefix getPrefix(); + LegacyPrefix getPrefix(); /** * Checks whether this instruction has a LOCK prefix. @@ -146,7 +146,7 @@ default Operand operand(final int operandIndex) { * @return True if this instruction has a LOCK prefix, false otherwise. */ default boolean hasLockPrefix() { - return hasPrefix() && getPrefix() == InstructionPrefix.LOCK; + return hasPrefix() && getPrefix() == LegacyPrefix.LOCK; } /** @@ -155,7 +155,7 @@ default boolean hasLockPrefix() { * @return True if this instruction has a REP prefix, false otherwise. */ default boolean hasRepPrefix() { - return hasPrefix() && getPrefix() == InstructionPrefix.REP; + return hasPrefix() && getPrefix() == LegacyPrefix.REP; } /** @@ -164,7 +164,7 @@ default boolean hasRepPrefix() { * @return True if this instruction has a REPNZ prefix, false otherwise. */ default boolean hasRepnzPrefix() { - return hasPrefix() && getPrefix() == InstructionPrefix.REPNZ; + return hasPrefix() && getPrefix() == LegacyPrefix.REPNZ; } /** diff --git a/id/src/main/java/com/ledmington/cpu/x86/InstructionBuilder.java b/id/src/main/java/com/ledmington/cpu/x86/InstructionBuilder.java index 9100871d..aedbb032 100644 --- a/id/src/main/java/com/ledmington/cpu/x86/InstructionBuilder.java +++ b/id/src/main/java/com/ledmington/cpu/x86/InstructionBuilder.java @@ -24,7 +24,7 @@ /** A builder for constructing {@link Instruction} objects. */ public final class InstructionBuilder { - private InstructionPrefix prefix = null; + private LegacyPrefix prefix = null; private Opcode opcode = null; private MaskRegister destinationMask = null; private boolean destinationMaskZero = false; @@ -49,7 +49,7 @@ private void assertNotBuilt() { * @param prefix The prefix to set. * @return This builder. */ - public InstructionBuilder prefix(final InstructionPrefix prefix) { + public InstructionBuilder prefix(final LegacyPrefix prefix) { assertNotBuilt(); if (this.prefix != null) { throw new IllegalArgumentException("Cannot set prefix twice."); diff --git a/id/src/main/java/com/ledmington/cpu/x86/InstructionPrefix.java b/id/src/main/java/com/ledmington/cpu/x86/LegacyPrefix.java similarity index 90% rename from id/src/main/java/com/ledmington/cpu/x86/InstructionPrefix.java rename to id/src/main/java/com/ledmington/cpu/x86/LegacyPrefix.java index 071d2047..411f3757 100644 --- a/id/src/main/java/com/ledmington/cpu/x86/InstructionPrefix.java +++ b/id/src/main/java/com/ledmington/cpu/x86/LegacyPrefix.java @@ -18,7 +18,7 @@ package com.ledmington.cpu.x86; /** A prefix for an x86 instruction which changes its behavior. */ -public enum InstructionPrefix { +public enum LegacyPrefix { /** Executes this instruction atomically. */ LOCK((byte) 0xf0), @@ -31,7 +31,7 @@ public enum InstructionPrefix { private final byte code; - InstructionPrefix(final byte code) { + LegacyPrefix(final byte code) { this.code = code; } @@ -41,7 +41,7 @@ public enum InstructionPrefix { * @param x The byte with the prefix. * @return The InstructionPrefix object. */ - public static InstructionPrefix fromByte(final byte x) { + public static LegacyPrefix fromByte(final byte x) { return switch (x) { case (byte) 0xf0 -> LOCK; case (byte) 0xf2 -> REPNZ; @@ -61,6 +61,6 @@ public byte getCode() { @Override public String toString() { - return "InstructionPrefix(code=" + code + ')'; + return "LegacyPrefix(code=" + code + ')'; } } diff --git a/id/src/main/java/com/ledmington/cpu/x86/Prefixes.java b/id/src/main/java/com/ledmington/cpu/x86/Prefixes.java index 19792728..108816bf 100644 --- a/id/src/main/java/com/ledmington/cpu/x86/Prefixes.java +++ b/id/src/main/java/com/ledmington/cpu/x86/Prefixes.java @@ -34,7 +34,7 @@ * @param evex The EVEX prefix of the instruction. */ public record Prefixes( - Optional p1, + Optional p1, Optional p2, boolean hasOperandSizeOverridePrefix, boolean hasAddressSizeOverridePrefix, diff --git a/id/src/test/java/com/ledmington/cpu/X64Encodings.java b/id/src/test/java/com/ledmington/cpu/X64Encodings.java index d7191f35..2e607d77 100644 --- a/id/src/test/java/com/ledmington/cpu/X64Encodings.java +++ b/id/src/test/java/com/ledmington/cpu/X64Encodings.java @@ -163,7 +163,7 @@ import com.ledmington.cpu.x86.Immediate; import com.ledmington.cpu.x86.IndirectOperand; import com.ledmington.cpu.x86.Instruction; -import com.ledmington.cpu.x86.InstructionPrefix; +import com.ledmington.cpu.x86.LegacyPrefix; import com.ledmington.cpu.x86.Opcode; import com.ledmington.cpu.x86.SegmentedAddress; import com.ledmington.utils.BitUtils; @@ -7056,7 +7056,7 @@ private static List others() { "67 66 a5"), test( new GeneralInstruction( - InstructionPrefix.REP, + LegacyPrefix.REP, Opcode.MOVS, IndirectOperand.builder() .pointer(BYTE_PTR) @@ -7072,7 +7072,7 @@ private static List others() { "67 f3 a4"), test( new GeneralInstruction( - InstructionPrefix.REP, + LegacyPrefix.REP, Opcode.MOVS, IndirectOperand.builder() .pointer(DWORD_PTR) @@ -7088,7 +7088,7 @@ private static List others() { "67 f3 a5"), test( new GeneralInstruction( - InstructionPrefix.REP, + LegacyPrefix.REP, Opcode.MOVS, IndirectOperand.builder() .pointer(DWORD_PTR) @@ -7104,7 +7104,7 @@ private static List others() { "f3 a5"), test( new GeneralInstruction( - InstructionPrefix.REP, + LegacyPrefix.REP, Opcode.MOVS, IndirectOperand.builder() .pointer(WORD_PTR) @@ -7120,7 +7120,7 @@ private static List others() { "67 66 f3 a5"), test( new GeneralInstruction( - InstructionPrefix.REP, + LegacyPrefix.REP, Opcode.MOVS, IndirectOperand.builder() .pointer(WORD_PTR) @@ -7136,7 +7136,7 @@ private static List others() { "66 f3 a5"), test( new GeneralInstruction( - InstructionPrefix.REPNZ, + LegacyPrefix.REPNZ, Opcode.MOVS, IndirectOperand.builder() .pointer(BYTE_PTR) @@ -7152,7 +7152,7 @@ private static List others() { "67 f2 a4"), test( new GeneralInstruction( - InstructionPrefix.REPNZ, + LegacyPrefix.REPNZ, Opcode.MOVS, IndirectOperand.builder() .pointer(DWORD_PTR) @@ -7168,7 +7168,7 @@ private static List others() { "67 f2 a5"), test( new GeneralInstruction( - InstructionPrefix.REPNZ, + LegacyPrefix.REPNZ, Opcode.MOVS, IndirectOperand.builder() .pointer(WORD_PTR) @@ -7185,7 +7185,7 @@ private static List others() { // Rep stos test( new GeneralInstruction( - InstructionPrefix.REP, + LegacyPrefix.REP, Opcode.STOS, IndirectOperand.builder() .pointer(BYTE_PTR) @@ -7197,7 +7197,7 @@ private static List others() { "67 f3 aa"), test( new GeneralInstruction( - InstructionPrefix.REP, + LegacyPrefix.REP, Opcode.STOS, IndirectOperand.builder() .pointer(BYTE_PTR) @@ -7209,7 +7209,7 @@ private static List others() { "f3 aa"), test( new GeneralInstruction( - InstructionPrefix.REP, + LegacyPrefix.REP, Opcode.STOS, IndirectOperand.builder() .pointer(DWORD_PTR) @@ -7221,7 +7221,7 @@ private static List others() { "f3 ab"), test( new GeneralInstruction( - InstructionPrefix.REP, + LegacyPrefix.REP, Opcode.STOS, IndirectOperand.builder() .pointer(QWORD_PTR) @@ -7233,7 +7233,7 @@ private static List others() { "67 f3 48 ab"), test( new GeneralInstruction( - InstructionPrefix.REP, + LegacyPrefix.REP, Opcode.STOS, IndirectOperand.builder() .pointer(QWORD_PTR) @@ -9291,7 +9291,7 @@ Opcode.MOVABS, new SegmentedAddress(DS, new Immediate(0x12345678deadbeefL)), EAX "66 0f b1 16"), test( new GeneralInstruction( - InstructionPrefix.LOCK, + LegacyPrefix.LOCK, Opcode.CMPXCHG, IndirectOperand.builder() .pointer(BYTE_PTR) @@ -9305,7 +9305,7 @@ Opcode.MOVABS, new SegmentedAddress(DS, new Immediate(0x12345678deadbeefL)), EAX "f0 0f b0 b4 98 78 56 34 12"), test( new GeneralInstruction( - InstructionPrefix.LOCK, + LegacyPrefix.LOCK, Opcode.CMPXCHG, IndirectOperand.builder() .pointer(BYTE_PTR) @@ -9316,7 +9316,7 @@ Opcode.MOVABS, new SegmentedAddress(DS, new Immediate(0x12345678deadbeefL)), EAX "f0 40 0f b0 2e"), test( new GeneralInstruction( - InstructionPrefix.LOCK, + LegacyPrefix.LOCK, Opcode.CMPXCHG, IndirectOperand.builder() .pointer(DWORD_PTR) @@ -9330,7 +9330,7 @@ Opcode.MOVABS, new SegmentedAddress(DS, new Immediate(0x12345678deadbeefL)), EAX "f0 44 0f b1 94 98 78 56 34 12"), test( new GeneralInstruction( - InstructionPrefix.LOCK, + LegacyPrefix.LOCK, Opcode.CMPXCHG, IndirectOperand.builder() .pointer(DWORD_PTR) @@ -9341,7 +9341,7 @@ Opcode.MOVABS, new SegmentedAddress(DS, new Immediate(0x12345678deadbeefL)), EAX "f0 0f b1 0e"), test( new GeneralInstruction( - InstructionPrefix.LOCK, + LegacyPrefix.LOCK, Opcode.CMPXCHG, IndirectOperand.builder() .pointer(QWORD_PTR) @@ -9355,7 +9355,7 @@ Opcode.MOVABS, new SegmentedAddress(DS, new Immediate(0x12345678deadbeefL)), EAX "f0 48 0f b1 bc 98 78 56 34 12"), test( new GeneralInstruction( - InstructionPrefix.LOCK, + LegacyPrefix.LOCK, Opcode.CMPXCHG, IndirectOperand.builder() .pointer(QWORD_PTR) @@ -9366,7 +9366,7 @@ Opcode.MOVABS, new SegmentedAddress(DS, new Immediate(0x12345678deadbeefL)), EAX "f0 4c 0f b1 0e"), test( new GeneralInstruction( - InstructionPrefix.LOCK, + LegacyPrefix.LOCK, Opcode.CMPXCHG, IndirectOperand.builder() .pointer(WORD_PTR) @@ -9380,7 +9380,7 @@ Opcode.MOVABS, new SegmentedAddress(DS, new Immediate(0x12345678deadbeefL)), EAX "66 f0 44 0f b1 bc 98 78 56 34 12"), test( new GeneralInstruction( - InstructionPrefix.LOCK, + LegacyPrefix.LOCK, Opcode.CMPXCHG, IndirectOperand.builder() .pointer(WORD_PTR) @@ -9392,7 +9392,7 @@ Opcode.MOVABS, new SegmentedAddress(DS, new Immediate(0x12345678deadbeefL)), EAX // Xadd test( new GeneralInstruction( - InstructionPrefix.LOCK, + LegacyPrefix.LOCK, Opcode.XADD, IndirectOperand.builder() .pointer(BYTE_PTR) @@ -9406,7 +9406,7 @@ Opcode.MOVABS, new SegmentedAddress(DS, new Immediate(0x12345678deadbeefL)), EAX "f0 0f c0 b4 98 78 56 34 12"), test( new GeneralInstruction( - InstructionPrefix.LOCK, + LegacyPrefix.LOCK, Opcode.XADD, IndirectOperand.builder() .pointer(BYTE_PTR) @@ -9417,7 +9417,7 @@ Opcode.MOVABS, new SegmentedAddress(DS, new Immediate(0x12345678deadbeefL)), EAX "f0 40 0f c0 2e"), test( new GeneralInstruction( - InstructionPrefix.LOCK, + LegacyPrefix.LOCK, Opcode.XADD, IndirectOperand.builder() .pointer(DWORD_PTR) @@ -9431,7 +9431,7 @@ Opcode.MOVABS, new SegmentedAddress(DS, new Immediate(0x12345678deadbeefL)), EAX "f0 44 0f c1 94 98 78 56 34 12"), test( new GeneralInstruction( - InstructionPrefix.LOCK, + LegacyPrefix.LOCK, Opcode.XADD, IndirectOperand.builder() .pointer(DWORD_PTR) @@ -9442,7 +9442,7 @@ Opcode.MOVABS, new SegmentedAddress(DS, new Immediate(0x12345678deadbeefL)), EAX "f0 0f c1 0e"), test( new GeneralInstruction( - InstructionPrefix.LOCK, + LegacyPrefix.LOCK, Opcode.XADD, IndirectOperand.builder() .pointer(QWORD_PTR) @@ -9456,7 +9456,7 @@ Opcode.MOVABS, new SegmentedAddress(DS, new Immediate(0x12345678deadbeefL)), EAX "f0 48 0f c1 bc 98 78 56 34 12"), test( new GeneralInstruction( - InstructionPrefix.LOCK, + LegacyPrefix.LOCK, Opcode.XADD, IndirectOperand.builder() .pointer(QWORD_PTR) @@ -9467,7 +9467,7 @@ Opcode.MOVABS, new SegmentedAddress(DS, new Immediate(0x12345678deadbeefL)), EAX "f0 4c 0f c1 0e"), test( new GeneralInstruction( - InstructionPrefix.LOCK, + LegacyPrefix.LOCK, Opcode.XADD, IndirectOperand.builder() .pointer(WORD_PTR) @@ -9481,7 +9481,7 @@ Opcode.MOVABS, new SegmentedAddress(DS, new Immediate(0x12345678deadbeefL)), EAX "66 f0 44 0f c1 bc 98 78 56 34 12"), test( new GeneralInstruction( - InstructionPrefix.LOCK, + LegacyPrefix.LOCK, Opcode.XADD, IndirectOperand.builder() .pointer(WORD_PTR) From c19bbdeb94977762f46273a96013e198d60fa511 Mon Sep 17 00:00:00 2001 From: Ledmington Date: Sat, 9 May 2026 16:07:17 +0200 Subject: [PATCH 2/2] Added new interface InstructionPrefix --- .../com/ledmington/cpu/x86/EvexPrefix.java | 2 +- .../cpu/x86/GeneralInstruction.java | 5 +- .../ledmington/cpu/x86/InstructionPrefix.java | 98 +++++++++++++++++++ .../com/ledmington/cpu/x86/RexPrefix.java | 7 +- .../com/ledmington/cpu/x86/Vex2Prefix.java | 17 +++- .../com/ledmington/cpu/x86/Vex3Prefix.java | 2 +- 6 files changed, 123 insertions(+), 8 deletions(-) create mode 100644 id/src/main/java/com/ledmington/cpu/x86/InstructionPrefix.java diff --git a/id/src/main/java/com/ledmington/cpu/x86/EvexPrefix.java b/id/src/main/java/com/ledmington/cpu/x86/EvexPrefix.java index 66ff36c6..336942d3 100644 --- a/id/src/main/java/com/ledmington/cpu/x86/EvexPrefix.java +++ b/id/src/main/java/com/ledmington/cpu/x86/EvexPrefix.java @@ -22,7 +22,7 @@ /** The extended VEX prefix (EVEX): 0x62 + 3 bytes. */ @SuppressWarnings("PMD.UnusedPrivateField") -public final class EvexPrefix { +public final class EvexPrefix implements InstructionPrefix { private final boolean r; private final boolean x; diff --git a/id/src/main/java/com/ledmington/cpu/x86/GeneralInstruction.java b/id/src/main/java/com/ledmington/cpu/x86/GeneralInstruction.java index 0dd77b47..b39da80c 100644 --- a/id/src/main/java/com/ledmington/cpu/x86/GeneralInstruction.java +++ b/id/src/main/java/com/ledmington/cpu/x86/GeneralInstruction.java @@ -73,10 +73,7 @@ public final class GeneralInstruction implements Instruction { * @param secondOperand The second operand of the Instruction. */ public GeneralInstruction( - final LegacyPrefix prefix, - final Opcode opcode, - final Operand firstOperand, - final Operand secondOperand) { + final LegacyPrefix prefix, final Opcode opcode, final Operand firstOperand, final Operand secondOperand) { this(prefix, opcode, null, false, firstOperand, secondOperand, null, null); } diff --git a/id/src/main/java/com/ledmington/cpu/x86/InstructionPrefix.java b/id/src/main/java/com/ledmington/cpu/x86/InstructionPrefix.java new file mode 100644 index 00000000..21828f88 --- /dev/null +++ b/id/src/main/java/com/ledmington/cpu/x86/InstructionPrefix.java @@ -0,0 +1,98 @@ +/* + * emu - Processor Emulator + * Copyright (C) 2023-2026 Filippo Barbari + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.ledmington.cpu.x86; + +/** + * Common interface for x86_64 instruction prefixes that extend register encoding: REX (0x4X), VEX2 (0xc5), VEX3 (0xc4), + * and EVEX (0x62). + * + *

All four prefix types share a common set of extension bits that expand the register namespace beyond the 3-bit + * limit of the base x86 encoding. The methods here expose those bits under consistent semantic names, regardless of + * which prefix type is in use. + * + *

Bits that do not exist in a given prefix type (e.g. {@link #x()} in VEX2) must be implemented to return + * {@code false} — their logical absence is equivalent to the extension bit being clear. + */ +public interface InstructionPrefix { + + /** + * Returns the R extension bit, which extends the REG field of the ModR/M byte from 3 bits to 4 bits (REX, VEX2, + * VEX3) or to 5 bits combined with R' in EVEX ({@link #r1()}). + * + *

Equivalent to REX.R, VEX.R, EVEX.R. + * + * @return {@code true} if the R extension bit is set. + */ + boolean r(); + + /** + * Returns the X extension bit, which extends the Index field of the SIB byte from 3 bits to 4 bits. + * + *

Equivalent to REX.X, VEX.X, EVEX.X. Returns {@code false} for prefix types that do not encode this bit (VEX2). + * + * @return {@code true} if the X extension bit is set. + */ + boolean x(); + + /** + * Returns the B extension bit, which extends one of the following fields depending on instruction encoding context: + * + *

    + *
  • the RM field of the ModR/M byte, + *
  • the Base field of the SIB byte, + *
  • the register field embedded in the opcode byte. + *
+ * + *

Equivalent to REX.B, VEX.B, EVEX.B. Returns {@code false} for prefix types that do not encode this bit (VEX2). + * + * @return {@code true} if the B extension bit is set. + */ + boolean b(); + + /** + * Returns the W bit, which typically selects between 32-bit and 64-bit operand size, though its exact meaning is + * opcode-dependent for VEX/EVEX. + * + *

Equivalent to REX.W, VEX.W, EVEX.W. Returns {@code false} for prefix types that do not encode this bit (VEX2). + * + * @return {@code true} if the W bit is set. + */ + boolean w(); + + /** + * Returns the V field, a 4-bit value encoding an additional source register operand (in one's complement). Used by + * VEX and EVEX instructions with three or four operands. + * + *

Equivalent to VEX.vvvv, EVEX.vvvv. Returns {@code 0} for prefix types that do not encode this field (REX). + * + * @return The 4-bit V field, in the range [0, 15]. + */ + byte v(); + + /** + * Returns the R' (R1) extension bit, which combines with {@link #r()} to extend the REG field of the ModR/M byte to + * 5 bits, allowing access to all 32 EVEX registers. + * + *

Only meaningful in EVEX. All other prefix types must return {@code false}. + * + * @return {@code true} if the R' extension bit is set. + */ + default boolean r1() { + return false; + } +} diff --git a/id/src/main/java/com/ledmington/cpu/x86/RexPrefix.java b/id/src/main/java/com/ledmington/cpu/x86/RexPrefix.java index f1689fa9..4e5c5ae7 100644 --- a/id/src/main/java/com/ledmington/cpu/x86/RexPrefix.java +++ b/id/src/main/java/com/ledmington/cpu/x86/RexPrefix.java @@ -27,7 +27,7 @@ * @param x The X bit, an extension for the Index field of the SIB byte. * @param b The B bit, an extension for the Base field of the SIB byte, the RM field of the ModR/M byte or the opcode. */ -public record RexPrefix(boolean w, boolean r, boolean x, boolean b) { +public record RexPrefix(boolean w, boolean r, boolean x, boolean b) implements InstructionPrefix { private static final byte REX_PREFIX_MASK = (byte) 0b11110000; private static final byte REX_PREFIX = (byte) 0b01000000; @@ -118,4 +118,9 @@ public boolean hasModRMRMExtension() { public boolean hasOpcodeRegExtension() { return b; } + + @Override + public byte v() { + return 0; + } } diff --git a/id/src/main/java/com/ledmington/cpu/x86/Vex2Prefix.java b/id/src/main/java/com/ledmington/cpu/x86/Vex2Prefix.java index 719c033c..c76d7f34 100644 --- a/id/src/main/java/com/ledmington/cpu/x86/Vex2Prefix.java +++ b/id/src/main/java/com/ledmington/cpu/x86/Vex2Prefix.java @@ -21,7 +21,7 @@ /** The VEX2 prefix (0xc5 + 1 byte). */ @SuppressWarnings("PMD.UnusedPrivateField") -public final class Vex2Prefix { +public final class Vex2Prefix implements InstructionPrefix { private final boolean r; private final byte v; @@ -75,6 +75,21 @@ public boolean r() { return r; } + @Override + public boolean x() { + return false; + } + + @Override + public boolean b() { + return false; + } + + @Override + public boolean w() { + return false; + } + /** * Returns the value of the V field in this VEX2 prefix. * diff --git a/id/src/main/java/com/ledmington/cpu/x86/Vex3Prefix.java b/id/src/main/java/com/ledmington/cpu/x86/Vex3Prefix.java index d6aee665..8ac045e9 100644 --- a/id/src/main/java/com/ledmington/cpu/x86/Vex3Prefix.java +++ b/id/src/main/java/com/ledmington/cpu/x86/Vex3Prefix.java @@ -21,7 +21,7 @@ /** The VEX3 prefix (0xc4 + 2 bytes). */ @SuppressWarnings("PMD.UnusedPrivateField") -public final class Vex3Prefix { +public final class Vex3Prefix implements InstructionPrefix { private final boolean r; private final boolean x;