feat(relinker): lower CLZERO for --to-intel

Lower CLZERO out of line instead of failing the relink: the 64-byte line
containing rAX (EAX with 67h) is cleared with four MOVNTDQ stores of
zero, the same non-temporal, weakly ordered store. The line address is
masked in xmm0 so RFLAGS stays untouched; xmm0 and rcx are spilled below
the red zone. Short sites share stubs through MatchSequence. CLZERO with
LOCK, an FS/GS override, a 66/F2/F3 prefix or longer than 15 bytes fails
the relink.

The decoder splits a REX followed by another prefix into a separate
instruction, which would hide a prefix that changes what CLZERO or the
next instruction does. The converter now fails the relink when such a
prefix-only fragment directly precedes an AMD-only instruction or would
be moved into a stub as a trailing instruction.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
ljkxandClaude Opus 5.5 committed 2026-10-01 12:30:35 +02:00
1 parent c7fb2575a3
commit 09cb86b076
10 files changed
+447 -13

No files matched your search

@@ -0,0 +1,19 @@
#ifndef CODEGEN_X86_CLZEROLOWERING_HPP
#define CODEGEN_X86_CLZEROLOWERING_HPP
#include <codegen/x86/ClzeroOperands.hpp>
#include <codegen/x86/StubBodyBuilder.hpp>
#include <cstdint>
#include <span>
namespace Codegen {
class ClzeroLowering {
public:
void EmitOutOfLine(StubBodyBuilder& body, const ClzeroOperands& operands) const;
[[nodiscard]] LoweredBody LowerOutOfLine(const ClzeroOperands& operands, std::span<const std::uint8_t> trailing = {}) const;
};
}
#endif
@@ -0,0 +1,17 @@
#ifndef CODEGEN_X86_CLZEROOPERANDS_HPP
#define CODEGEN_X86_CLZEROOPERANDS_HPP
#include <cstddef>
#include <cstdint>
namespace Codegen {
struct ClzeroOperands {
bool AddressSize32;
};
[[nodiscard]] ClzeroOperands DecodeClzero(const std::uint8_t* data, std::size_t length);
}
#endif