#pragma once
#pragma section( ".xmp2" )
#pragma comment( linker, "/section:.xmp2,RWE" )

using u8 = unsigned char;
using u16 = unsigned short;
using u32 = unsigned int;
using u64 = unsigned long long;
using __vmcall_t = void *( * )( ... );

namespace vm
{
    constexpr auto entry_rva = 0x1000;

    enum class calls : u32
    {
        get_world = 0xBFFD6FE9,
        get_hello = 0xBFFD6FDD
    };

    template < class T, class U > struct _pair_t
    {
        T first;
        U second;
    };

    inline _pair_t< u8, calls > call_map[ 2 ] = { { 0, calls::get_world }, { 1, calls::get_hello } };

    struct _gen_data
    {
        u8 bin[ 0x100000 ]; // this will the vmp binary...
        u8 __vmcall_shell_code[ 2 ][ 15 ] = { {
                                                  0x68, 0xE9, 0xD6, 0xFF, 0x0B, // push xxxx
                                                  0x68, 0xE9, 0xD6, 0xFF, 0x0B, // push xxxx
                                                  0xE9, 0x00, 0x00, 0x00, 0x00  // jmp rip+xxxx
                                              },

                                              {
                                                  0x68, 0xE9, 0xD6, 0xFF, 0x0B, // push xxxx
                                                  0x68, 0xE9, 0xD6, 0xFF, 0x0B, // push xxxx
                                                  0xE9, 0x00, 0x00, 0x00, 0x00  // jmp rip+xxxx
                                              } };

        bool init()
        {
            for ( auto idx = 0u; idx < ( sizeof( __vmcall_shell_code ) / 15 ); ++idx )
            {
                *reinterpret_cast< u32 * >( &__vmcall_shell_code[ idx ][ 1 ] ) =
                    static_cast< u32 >( call_map[ idx ].second );

                *reinterpret_cast< u32 * >( &__vmcall_shell_code[ idx ][ 6 ] ) =
                    static_cast< u32 >( call_map[ idx ].second );

                *reinterpret_cast< u32 * >( &__vmcall_shell_code[ idx ][ 11 ] ) = reinterpret_cast< u32 >(
                    ( bin - ( reinterpret_cast< u64 >( &__vmcall_shell_code[ idx ] ) + 15 ) ) + entry_rva );
            }

            return true; // only a bool so i can use static/call once...
        }
    };

    __declspec( allocate( ".xmp2" ) ) inline _gen_data gen_data;

    template < calls e_call, class T, class... Ts > auto call( Ts... args ) -> T
    {
        static auto __init_result = gen_data.init();

        __vmcall_t vmcall = nullptr;
        for ( auto idx = 0u; idx < sizeof( call_map ) / sizeof( _pair_t< u8, calls > ); ++idx )
            if ( call_map[ idx ].second == e_call )
                vmcall = reinterpret_cast< __vmcall_t >( &gen_data.__vmcall_shell_code[ idx ] );

        return reinterpret_cast< T >( vmcall( args... ) );
    }
} // namespace vm

int main()
{
    vm::call< vm::calls::get_hello, void * >( "hello world" );
}