mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-23 09:03:22 -05:00
In 64-bit mode a REX prefix only takes effect when it immediately precedes the opcode; a REX followed by a legacy prefix or another REX is ignored. The instruction decoder, the rewriter's reference classifier, DecodedInstruction and the SSE4a, SHA-256 and CLZERO operand decoders read legacy prefixes and then at most one REX. `48 F3 0F 2B 00` (MOVNTSS) was therefore scanned as `[48 F3][0F 2B 00]` and kept, and `48 67 0F 01 FC` lost its address-size prefix. All of them now accept REX bytes among the prefixes and keep only one that directly precedes the opcode. The converter's guard against prefix-only fragments is removed, since the decoder no longer produces them, and the TechnicalDebt entry describing the split is dropped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
54 lines
1.5 KiB
C++
54 lines
1.5 KiB
C++
#include <codegen/x86/ClzeroOperands.hpp>
|
|
#include <codegen/x86/X64OpcodeConstants.hpp>
|
|
#include <codegen/CodegenException.hpp>
|
|
|
|
namespace Codegen {
|
|
|
|
using namespace X64OpcodeConstants;
|
|
|
|
namespace {
|
|
|
|
constexpr std::size_t kMaxInstructionLength = 15;
|
|
|
|
}
|
|
|
|
ClzeroOperands DecodeClzero(const std::uint8_t* data, const std::size_t length) {
|
|
if (length > kMaxInstructionLength) {
|
|
throw CodegenException("CLZERO longer than 15 bytes");
|
|
}
|
|
|
|
ClzeroOperands operands{};
|
|
std::size_t pos = 0;
|
|
|
|
while (pos < length) {
|
|
const std::uint8_t b = data[pos];
|
|
if (b >= RexMin && b <= RexMax) {
|
|
pos += 1;
|
|
continue;
|
|
}
|
|
if (b == PrefixLock) {
|
|
throw CodegenException("CLZERO with a LOCK prefix");
|
|
}
|
|
if (b == PrefixSegFs || b == PrefixSegGs) {
|
|
throw CodegenException("CLZERO with an FS or GS segment override");
|
|
}
|
|
if (b == PrefixOperandSize || b == PrefixRepne || b == PrefixRep) {
|
|
throw CodegenException("Not a CLZERO instruction");
|
|
}
|
|
if (b == PrefixAddressSize) {
|
|
operands.AddressSize32 = true;
|
|
} else if (b != PrefixSegCs && b != PrefixSegSs && b != PrefixSegDs && b != PrefixSegEs) {
|
|
break;
|
|
}
|
|
pos += 1;
|
|
}
|
|
|
|
if (pos + 3 != length || data[pos] != TwoByteOpcodeEscape || data[pos + 1] != TwoByteGrp7 || data[pos + 2] != 0xFC) {
|
|
throw CodegenException("Not a CLZERO instruction");
|
|
}
|
|
|
|
return operands;
|
|
}
|
|
|
|
}
|