diff --git a/core/relinker/codegen/src/x86/X64InstructionDecoder.cpp b/core/relinker/codegen/src/x86/X64InstructionDecoder.cpp index 0e5ebec82..7a0b2a001 100644 --- a/core/relinker/codegen/src/x86/X64InstructionDecoder.cpp +++ b/core/relinker/codegen/src/x86/X64InstructionDecoder.cpp @@ -481,6 +481,12 @@ DecodedInstructionInfo X64InstructionDecoder::DecodeInstruction( info.FlowKind = ControlFlowKind::Trap; return info; } + if (op == TwoByteUd1) { + if (pos < info.Length) + readModRm(pos, false); + info.FlowKind = ControlFlowKind::Trap; + return info; + } if (op >= TwoByteJccRel32Min && op <= TwoByteJccRel32Max) { std::int32_t disp = 0; std::memcpy(&disp, data + pos, 4); diff --git a/core/relinker/codegen/tests/Amd64OnlyConverterTests.cpp b/core/relinker/codegen/tests/Amd64OnlyConverterTests.cpp index f94034c19..87ed32b77 100644 --- a/core/relinker/codegen/tests/Amd64OnlyConverterTests.cpp +++ b/core/relinker/codegen/tests/Amd64OnlyConverterTests.cpp @@ -168,6 +168,9 @@ void decoderRipRelative() { } for (const auto& instruction : kRegisterVectorOperations) require(!decoder.DecodeInstruction(instruction.data(), instruction.size()).HasRipRelativeDisp, "Vector instruction without a RIP-relative operand was reported as RIP-relative"); + const Bytes ud1 = {0x0F, 0xB9, 0x05, 0x10, 0x00, 0x00, 0x00}; + const auto trap = decoder.DecodeInstruction(ud1.data(), ud1.size()); + require(trap.Length == ud1.size() && trap.FlowKind == Codegen::ControlFlowKind::Trap && trap.HasRipRelativeDisp && read(ud1, trap.RipRelativeDispOffset) == 0x10, "UD1 was not decoded as a trap with its RIP-relative operand"); } void decoderTwoByteOpcodeLengths() { diff --git a/core/relinker/relinker/tests/StrictNidFilterTests.cpp b/core/relinker/relinker/tests/StrictNidFilterTests.cpp index 63fbdac61..77d77d3f7 100644 --- a/core/relinker/relinker/tests/StrictNidFilterTests.cpp +++ b/core/relinker/relinker/tests/StrictNidFilterTests.cpp @@ -68,6 +68,17 @@ void deadTailAndExplicitEntry() { require(live.ImportSlots == std::set{0x2000}, "Explicit entry after UD2 lost its import"); } +void ud1DeadTail() { + auto input = fixture(); + emit(input, 0, {0x0F, 0xB9, 0xC0}); + importThunk(input, 16, 0x2000); + require(AnalyzeStrictReachability(input).ImportSlots.empty(), "UD1 fallthrough retained a dead import"); + input = fixture(); + ripOperand(input, 0, {0x0F, 0xB9, 0x05}, 0x3000); + importThunk(input, 16, 0x2000); + require(AnalyzeStrictReachability(input).ImportSlots.empty(), "UD1 with a RIP-relative operand retained a dead import"); +} + void conditionalTailCall() { auto input = fixture(); emit(input, 0, {0x75, 0x0E, 0xC3}); @@ -283,6 +294,7 @@ void filterAndPltCompaction() { int main() { try { deadTailAndExplicitEntry(); + ud1DeadTail(); conditionalTailCall(); callbackAndRelocationRoots(); registerImportCall();