task 3.1-3.2: IAssembler interface + StubAssembler emit primitives

Add IAssembler seam (Assemble(text, origin)) with StubAssembler default
backend. StubAssembler provides EmitU8/EmitU32/EmitU64 little-endian
byte emitters (zero dep, no FASM). Assemble throws NotSupportedException
on StubAssembler (text assembly deferred to IcedAssembler, Phase 8).

7 new tests: EmitU8, EmitU32 x2, EmitU64 x2, IS-A check,
Assemble throws. All passing (total: 64).
This commit is contained in:
kbe
2026-07-21 19:35:11 +02:00
parent 68255f907c
commit 855595837f
3 changed files with 144 additions and 0 deletions
+17
View File
@@ -0,0 +1,17 @@
namespace WhiteMagic.Assembly;
/// <summary>
/// Abstraction over an x86/x64 assembler. The default <see cref="StubAssembler"/>
/// hand-emits calling-convention trampolines (no parsing, zero dep). An optional
/// <see cref="IcedAssembler"/> (Phase 8) handles arbitrary mnemonics via the Iced
/// library.
/// </summary>
public interface IAssembler
{
/// <summary>
/// Assembles text mnemonics into machine code.
/// </summary>
/// <param name="assemblyText">The assembly text (Intel syntax).</param>
/// <param name="origin">The base address for relative encodings.</param>
byte[] Assemble(string assemblyText, ulong origin = 0);
}
+49
View File
@@ -0,0 +1,49 @@
namespace WhiteMagic.Assembly;
/// <summary>
/// The default <see cref="IAssembler"/> backend. Hand-emits calling-convention
/// trampolines and injection stubs using deterministic byte emitters
/// (<see cref="EmitU8"/>, <see cref="EmitU32"/>, <see cref="EmitU64"/>). Has
/// no native or third-party dependency — no FASM, no Iced.
/// </summary>
/// <remarks>
/// <see cref="Assemble"/> is not supported by this backend (it is a parse-free
/// emitter, not a text assembler). Use <see cref="IcedAssembler"/> (Phase 8) for
/// arbitrary mnemonics.
/// </remarks>
public class StubAssembler : IAssembler
{
/// <inheritdoc />
/// <exception cref="NotSupportedException">Always thrown. StubAssembler does
/// not parse text assembly; use IcedAssembler for that.</exception>
public byte[] Assemble(string assemblyText, ulong origin = 0)
{
throw new NotSupportedException(
"StubAssembler does not parse text assembly. " +
"Use IcedAssembler (Phase 8) for arbitrary mnemonics.");
}
// ── Emit primitives ────────────────────────────────────────────────────
/// <summary>Appends a single byte to <paramref name="buffer"/>.</summary>
public void EmitU8(List<byte> buffer, byte value)
{
buffer.Add(value);
}
/// <summary>Appends <paramref name="value"/> as 4 little-endian bytes.</summary>
public void EmitU32(List<byte> buffer, uint value)
{
buffer.Add((byte)value);
buffer.Add((byte)(value >> 8));
buffer.Add((byte)(value >> 16));
buffer.Add((byte)(value >> 24));
}
/// <summary>Appends <paramref name="value"/> as 8 little-endian bytes.</summary>
public void EmitU64(List<byte> buffer, ulong value)
{
EmitU32(buffer, (uint)value);
EmitU32(buffer, (uint)(value >> 32));
}
}