fix(relinker): let REX.W override 0x66 when sizing decoder immediates

In 64-bit mode REX.W takes precedence over the 0x66 operand-size prefix,
so the immediate of 81, C7, 69, 68, A9, the 05..3D accumulator forms and
the F7 TEST form stays imm32. The decoder only applied this to B8+r and
returned a length two bytes short for the others.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Oguzhan OzdemirandClaude Opus 5.5 committed 2026-10-07 18:51:56 +03:00
1 parent 4e742835c0
commit d64c0605ea
2 files changed
+10 -4

No files matched your search

@@ -39,6 +39,9 @@ std::size_t X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t
pos += 1;
}
const bool rexW = rexPresent && (rex & RexWBit) != 0;
const std::size_t operandImmediateSize = operandSizeOverride && !rexW ? ImmSize16 : ImmSize32;
if (pos >= available) {
throw CodegenException("Instruction truncated after prefixes");
}
@@ -172,10 +175,9 @@ std::size_t X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t
opcode == OneByteTestEaxImm32 ||
(opcode >= OneByteMovImm32RegMin && opcode <= OneByteMovImm32RegMax)) {
if (opcode >= OneByteMovImm32RegMin && opcode <= OneByteMovImm32RegMax) {
immediateSize = (rexPresent && (rex & RexWBit) != 0) ? ImmSize64 :
(operandSizeOverride ? ImmSize16 : ImmSize32);
immediateSize = rexW ? ImmSize64 : operandImmediateSize;
} else {
immediateSize = operandSizeOverride ? ImmSize16 : ImmSize32;
immediateSize = operandImmediateSize;
}
} else if (opcode == OneByteImm8Grp1 || opcode == OneByteImulRm32Imm8) {
immediateSize = ImmSize8;
@@ -279,7 +281,7 @@ std::size_t X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t
reg <= Grp3RegTestMax) {
immediateSize = (opcode == OneByteTestGrp3Rm8)
? ImmSize8
: (operandSizeOverride ? ImmSize16 : ImmSize32);
: operandImmediateSize;
}
if (mod != ModRmModRegister && rm == ModRmRmSibPresent) {