/* dhae_sdk.c - definitions of the Dhaedalida virtualization markers.
 *
 * Each marker is a non-inlinable function whose body puts the 8 magic bytes of
 * dhae_marker_sig.h verbatim into .text. Neither the compiler (/O2) nor the
 * linker (/GL LTCG, /OPT:ICF) may elide the `call` at the call site or fold the
 * two markers into one address. That surviving `call RabbitStart` / `call RabbitEnd` is
 * exactly the signature the Dhaedalida GUI scans for to identify a tagged
 * function.
 *
 * BOTH bitnesses live in this one file, so a consumer's build line never changes:
 *     cl /O2 yourapp.c dhae_sdk.c        (x64 dev prompt -> PE32+ marker)
 *     cl /O2 yourapp.c dhae_sdk.c        (x86 dev prompt -> PE32  marker)
 * - no other dependency.
 *
 * The two arms are preprocessor-exclusive, and MSVC's __declspec(naked) is
 * x86/ARM-only and rejected outright on x64, so the 32-bit arm can never be taken
 * there even by accident.
 *
 * ⚠ THIS PARAGRAPH USED TO ADD "so the object this file contributes to the CLI
 * (Dhaedalida.vcxproj) is byte-identical by construction rather than by inspection",
 * AND THAT HALF IS NOW FALSE. Withdrawing a marker pair removed two functions from
 * each arm, so the x64 object genuinely changes in this version. The exclusivity
 * above is still true and still worth stating; the byte-identity claim was a sentence
 * riding on it, and a sentence is not a measurement. If the question is whether the
 * unreferenced marker bodies survive the link at all, tools/dhae-marker-scan answers
 * it against the built binary.
 */
#include "dhae_sdk.h"
#include "dhae_marker_sig.h"

/* Observable sink: volatile writes cannot be optimized away, which is what
 * forces the marker calls to survive. Distinct increments keep the markers from
 * being folded together by identical-COMDAT folding (/OPT:ICF). (Used by the
 * x64 arm; defined unconditionally so the symbol never disappears.)
 *
 * The increment is 1 << (ordinal - 1), so the sink's final value is also a bitmask
 * of which markers were compiled in, at no cost. What matters for correctness is
 * only that every pair of increments differs: two markers that folded to one address
 * would make the scanner see a single magic, and one marker silently becoming another
 * is a protection-MODE change nothing else would report. NEVER reuse an increment.
 *
 * ⚠ THE SET IS 1, 2, 16, 32 -- THE GAP AT 4 AND 8 IS DERIVED, NOT AN OVERSIGHT.
 * Ordinals 3 and 4 are reserved (dhae_marker_sig.h), and because the increment is
 * a function of the ordinal, reserving the ordinals reserves the increments too --
 * a derivation rather than a convention someone has to remember. Do NOT close the
 * gap by renumbering the Bear markers down.
 *
 * ⚠ AND THE INCREMENTS ARE A BELT OVER A BRACE, WHICH IS WHY THEY LOOK REDUNDANT.
 * The x64 bodies already differ from one another by the magic each stores, so ICF
 * could not fold them even with equal increments, and the x86 arm never touches this
 * sink at all. Defence in depth working is indistinguishable from dead code; delete
 * them and nothing observable changes until the day the magics move. */
volatile unsigned long _dhae_vm_marker_sink = 0;

/* Each marker stores its magic to a volatile 64-bit local. The volatile store
 * cannot be optimized away and MSVC x64 emits it as `movabs reg, imm64`, so the
 * 8 magic bytes land verbatim in this function's .text - the signature the GUI
 * scans for to find the markers without a PDB (see dhae_marker_sig.h). */
#ifdef __cplusplus
extern "C" {
#endif

#if defined(_M_X64)

__declspec(noinline) void RabbitStart(void) {
    volatile unsigned long long sig = DHAE_SIG_RABBITSTART;
    (void)sig;
    _dhae_vm_marker_sink += 1ul;
}

__declspec(noinline) void RabbitEnd(void) {
    volatile unsigned long long sig = DHAE_SIG_RABBITEND;
    (void)sig;
    _dhae_vm_marker_sink += 2ul;
}

__declspec(noinline) void BearStart(void) {
    volatile unsigned long long sig = DHAE_SIG_BEARSTART;
    (void)sig;
    _dhae_vm_marker_sink += 16ul;
}

__declspec(noinline) void BearEnd(void) {
    volatile unsigned long long sig = DHAE_SIG_BEAREND;
    (void)sig;
    _dhae_vm_marker_sink += 32ul;
}

#elif defined(_M_IX86)

/* 32-bit x86 has NO 64-bit immediate, so the magic cannot come out of a store:
 * a `volatile unsigned long long` compiles to two `mov dword` halves with an
 * opcode byte between them, and MarkerScan's contiguous 8-byte search finds
 * nothing. The magic is therefore emitted as inline DATA, jumped over:
 *
 *     EB 08                          jmp short $+10   -> the `ret` below
 *     01 54 76 DE C0 E5 1A D1        DHAE_SIG_RABBITSTART, little-endian
 *     C3                             ret              <- the jump target
 *
 * __declspec(naked) is what makes this exact: MSVC emits no prolog/epilog, so
 * those 11 bytes ARE the function and the magic sits at offset +2, mirroring
 * x64's `48 B8 <magic> C3`. Three deliberate choices:
 *
 *  - `ret` is written as a MNEMONIC, not `_emit 0C3h`, so the compiler sees a
 *    real return (no missing-return diagnostics); it assembles to the single
 *    byte C3 that EB 08 targets.
 *  - `EB 08` is hand-encoded rather than `jmp SHORT lbl`, so the displacement
 *    cannot depend on the inline assembler's label pass over `_emit` bytes.
 *  - no __declspec(noinline): `naked` already guarantees non-inlinability (it
 *    beats even __forceinline), so adding it would only introduce an unverified
 *    declspec combination.
 *
 * `ret` (C3) is correct for __cdecl, __stdcall AND __fastcall here because the
 * markers take no arguments - there is nothing for a callee-cleanup convention
 * to pop. DHAE_CALL pins __cdecl anyway so the symbol is `_RabbitStart` under /Gz
 * and /Gr too.
 *
 * The bytes below MUST equal DHAE_SIG_RABBITSTART / DHAE_SIG_RABBITEND /
 * DHAE_SIG_BEARSTART / DHAE_SIG_BEAREND (little-endian) in dhae_marker_sig.h. This
 * arm is the ONE place in the whole SDK where they are hand-typed rather than
 * macro-derived, which is why examples/markers32/verify-bindings32.ps1 proves them
 * from the source tokens on a machine with no 32-bit toolchain installed.
 *
 * ⚠ AND WHY THIS COMMENT SPELLS NO BYTE VALUES. That verifier tokenizes hex over the
 * WHOLE file and has no idea what a comment is, so an example written here in the
 * 0xNN form would be read as part of the proof stream. Where bytes must be named in
 * prose here, they are written bare. */
__declspec(naked) void DHAE_CALL RabbitStart(void) {
    __asm {
        _emit 0xEB
        _emit 0x08
        _emit 0x01
        _emit 0x54
        _emit 0x76
        _emit 0xDE
        _emit 0xC0
        _emit 0xE5
        _emit 0x1A
        _emit 0xD1
        ret
    }
}

__declspec(naked) void DHAE_CALL RabbitEnd(void) {
    __asm {
        _emit 0xEB
        _emit 0x08
        _emit 0x02
        _emit 0x54
        _emit 0x76
        _emit 0xDE
        _emit 0xC0
        _emit 0xE5
        _emit 0x1A
        _emit 0xD1
        ret
    }
}

__declspec(naked) void DHAE_CALL BearStart(void) {
    __asm {
        _emit 0xEB
        _emit 0x08
        _emit 0x05
        _emit 0x54
        _emit 0x76
        _emit 0xDE
        _emit 0xC0
        _emit 0xE5
        _emit 0x1A
        _emit 0xD1
        ret
    }
}

__declspec(naked) void DHAE_CALL BearEnd(void) {
    __asm {
        _emit 0xEB
        _emit 0x08
        _emit 0x06
        _emit 0x54
        _emit 0x76
        _emit 0xDE
        _emit 0xC0
        _emit 0xE5
        _emit 0x1A
        _emit 0xD1
        ret
    }
}

#else
#error "Dhaedalida markers require x86-64 (PE32+) or 32-bit x86 (PE32)."
#endif

#ifdef __cplusplus
}
#endif
