feat(relinker): lower SHA-256 instructions with a memory operand

SHA256RNDS2/MSG1/MSG2 with a memory source made `--to-intel` fail the
whole relink. The stub now spills a scratch xmm, loads the operand into
it with MOVDQU (AMD does not fault on a misaligned SHA operand, so the
unaligned load keeps that behaviour) and runs the register-form
lowering. RSP-based operands get the spill depth added to their
displacement. RIP-relative operands still fail: the stub runs at a
different address.

Co-Authored-By: Claude <[email protected]>
This commit is contained in:
Adrià FranchandClaude committed 2026-10-04 08:21:40 +02:00
1 parent 870bdd814f
commit 5fc16a9548
6 files changed
+127 -8

No files matched your search

@@ -1,8 +1,10 @@
#ifndef CODEGEN_X86_SHA256OPERANDS_HPP
#define CODEGEN_X86_SHA256OPERANDS_HPP
#include <codegen/x86/StubBodyBuilder.hpp>
#include <cstddef>
#include <cstdint>
#include <optional>
namespace Codegen {
@@ -16,6 +18,7 @@ struct Sha256Operands {
Sha256Operation Operation;
std::uint8_t Destination;
std::uint8_t Source;
std::optional<MemoryOperand> Memory;
};
[[nodiscard]] Sha256Operands DecodeSha256(const std::uint8_t* data, std::size_t length);
@@ -17,6 +17,18 @@ struct LoweredBody {
using StubConstant = std::array<std::uint8_t, 16>;
struct MemoryOperand {
std::vector<std::uint8_t> Prefixes;
std::uint8_t RexIndexBase;
std::uint8_t Mod;
std::uint8_t Rm;
std::uint8_t Sib;
std::int32_t Displacement;
bool StackBase;
};
[[nodiscard]] MemoryOperand DecodeMemoryOperand(const std::uint8_t* data, std::size_t length, std::size_t modRmOffset, std::uint8_t rex, std::vector<std::uint8_t> prefixes);
void EmitSse(std::vector<std::uint8_t>& out, std::uint8_t prefix, std::initializer_list<std::uint8_t> opcode, std::uint8_t dst, std::uint8_t src);
void EmitShiftImm(std::vector<std::uint8_t>& out, std::uint8_t extension, std::uint8_t reg, std::uint8_t imm);
@@ -28,6 +40,7 @@ public:
void ShiftImm(std::uint8_t extension, std::uint8_t reg, std::uint8_t imm);
void ShiftDwordImm(std::uint8_t extension, std::uint8_t reg, std::uint8_t imm);
void RipOperand(std::initializer_list<std::uint8_t> opcode, std::uint8_t reg, const StubConstant& constant);
void Load(std::uint8_t reg, const MemoryOperand& operand);
void Spill(std::uint8_t reg);
void Restore(std::uint8_t reg);
void Raw(std::span<const std::uint8_t> bytes);
@@ -43,6 +56,7 @@ private:
std::vector<std::uint8_t> _bytes;
std::vector<Fixup> _fixups;
std::vector<StubConstant> _constants;
std::size_t _stackDepth = 0;
};
}