C++プログラマのためのアセンブラ入門
はじめに
新人さんといわず中堅くらいになったプログラマでもアセンブラがわからないという人が最近は多いようです
「ポインタがわからない」「マルチスレッドがわからない」というようなことも結局はアセンブラを理解していないところが大きいように思います
動作の詳細としてのアセンブラ
C/C++ の動作の詳細としてのアセンブラ入門は「C/C++ ポインタ入門」に譲ります
アセンブラ
ここでは「アセンブラ」という言葉を CPU が解釈可能なバイナリコードの意味で使ったりアセンブリ言語の意味で使ったりソースファイルをアセンブルするアプリケーションであるアセンブラの意味で使ったりしています
CPU / MPU
プログラムを実行する主体であるハードウェアであるところの CPU ができることは、その CPU の 命令セットにあるものだけです
例えば intel の x86 / ia32 は、http://www.intel.com/jp/download/index.htm#ia32 にあるドキュメントに一覧があります
レジスタに値を入れる、レジスタに入っている値を操作する、メモリからレジスタに値を読み込む、レジスタからメモリに値を書き込む、条件によってフラグを立てる、指定のアドレスにジャンプする
CPU にできるのはたったこれだけです
たったこれだけのことがわからないはずがないですよね
わらないというのはただアセンブリ言語の文法や CPU の動作の仕組みを理解していないというだけのことではないでしょうか
プログラマであるなら分らないことがあったときの対処方法は簡単です
書いてみればいいのです
intdos, int86
昔々 MS-DOS の頃、C プログラマでアセンブラのわからない人は intdos や int86 などといった API を使うことでアセンブラに馴染むことができました
struct WORDREGS { unsigned short ax; unsigned short bx; unsigned short cx; unsigned short dx; unsigned short si; unsigned short di; unsigned short cflag; }; struct BYTEREGS { unsigned char al, ah; unsigned char bl, bh; unsigned char cl, ch; unsigned char dl, dh; }; union REGS { struct WORDREGS x; struct BYTEREGS h; }; int intdos( int no, union REGS* iregs, union REGS* oregs ); int int86( int no, union REGS* iregs, union REGS* oregs );
今はもうこんなのはありませんが、インラインアセンブラが使えますから同じようなものを自分で実装することも簡単です
インラインアセンブラ
インラインアセンブラなら C++ のコード中に本当にアセンブラで書いてみることも簡単です
実際に試してみるといいでしょう
アセンブラは使わずにと言いましたが、例えば CPUID 命令を使おうとするとこんな感じになるでしょうか
x86環境の場合
x86環境ではインラインアセンブラ __asm で eax にコマンド番号を指定して cpuid 命令を呼ぶだけです
inline bool cpuid32_issupported(){ DWORD _eax0 = 0; DWORD _eax1 = 0; __asm{ pushfd pop eax mov _eax0, eax xor eax, 00200000h push eax popfd pushfd pop eax mov _eax1, eax } return ( _eax0 != _eax1 ); } inline DWORD cpuid32( DWORD _eax, DWORD _ecx, LPDWORD peax = NULL, LPDWORD pebx = NULL, LPDWORD pecx = NULL, LPDWORD pedx = NULL ){ DWORD _ebx = 0; DWORD _edx = 0; __asm{ mov eax, _eax mov ecx, _ecx cpuid mov _eax, eax mov _ebx, ebx mov _ecx, ecx mov _edx, edx } if( peax ){ *peax = _eax; } if( pebx ){ *pebx = _ebx; } if( pecx ){ *pecx = _ecx; } if( pedx ){ *pedx = _edx; } return _eax; }
簡単ですよね
x64環境の場合
x64環境ではインラインアセンブラは使えないので別に .asmファイルを用意する必要があります
少し見た目が違うだけで随分難しそうになってしまいましたか?
でも命令自体は同じなのでやっている内容は x86環境のときと同じですよ
EXTERN_C bool __fastcall cpuid64_issupported();
EXTERN_C DWORD __fastcall cpuid64( DWORD _eax, DWORD _ecx, LPDWORD peax, LPDWORD pebx, LPDWORD pecx, LPDWORD pedx );
PUBLIC cpuid64_issupported PUBLIC cpuid64 .CODE ALIGN 8 ; bool cpuid64_issupported(); cpuid64_issupported PROC FRAME sub rsp, 20h .allocstack 20h .endprolog pushfq pop rax mov rcx, rax xor rax, 00200000h push rax popfq pushfq pop rdx xor rax, rax test rcx, rdx setne al add rsp, 20h ret ALIGN 8 cpuid64_issupported ENDP ALIGN 8 ; DWORD cpuid64( DWORD _eax, DWORD _ecx, LPDWORD peax, LPDWORD pebx, LPDWORD pecx, LPDWORD pedx ); cpuid64 PROC FRAME sub rsp, 20h .allocstack 20h push rbx .pushreg rbx push r10 .pushreg r10 push r11 .pushreg r11 .endprolog mov r11, QWORD PTR [rsp+68h] mov r10, QWORD PTR [rsp+60h] mov rax, rcx mov rcx, rdx cpuid test r8, r8 je @f mov DWORD PTR [r8], eax @@: test r9, r9 je @f mov DWORD PTR [r9], ebx @@: test r10, r10 je @f mov DWORD PTR [r10], ecx @@: test r11, r11 je @f mov DWORD PTR [r11], edx @@: pop r11 pop r10 pop rbx add rsp, 20h ret ALIGN 8 cpuid64 ENDP _TEXT ENDS END
カスタムビルドは例えばこんな感じ:
ml64.exe /c /nologo /Zi /Fo"$(IntDir)\$(InputName).obj" $(InputFileName)
使用例
当たり前のことですが、中身の実装が C++ でもアセンブラでも使う側にとってはただの関数です
#if defined( WIN64 ) || defined( _WIN64 ) #define cpuid_issupported cpuid64_issupported #define cpuid cpuid64 #else // WIN64 #define cpuid_issupported cpuid32_issupported #define cpuid cpuid32 #endif // WIN64 #define CPUID_GET_VERSION 0 #define CPUID_GET_SIGNATURE 1 #define CPUID_GET_CONFIGURATIONS 2 #define CPUID_GET_SERIAL_NUMBER 3 #define CPUID_GET_EX_VERSION 0x80000000 #define CPUID_GET_EX_SIGNATURE 0x80000001 #define CPUID_GET_EX_BRAND_STRING1 0x80000002 #define CPUID_GET_EX_BRAND_STRING2 0x80000003 #define CPUID_GET_EX_BRAND_STRING3 0x80000004 #define CPUID_VENDORID_MAX (3*sizeof(DWORD)) #define CPUID_EXVENDORID_MAX (3*sizeof(DWORD)) #define CPUID_EXBRANDSTRING_MAX (4*sizeof(DWORD)*3) #define CPUID_CONFIGURATIONS_MAX (4*sizeof(DWORD)-1) #define CPUID_FLAGS_EX 0x80000000 #define CPUID_FLAGS_SUPPORTED 0x00200000 #pragma pack( push ) #pragma pack( 1 ) typedef struct _CPUID_PROCESSOR_SERIAL_NUMBER { BYTE b[16]; } CPUID_PROCESSOR_SERIAL_NUMBER, FAR *LPCPUID_PROCESSOR_SERIAL_NUMBER; typedef struct _CPUID_INFORMATION { DWORD dwSize; DWORD dwFlags; DWORD dwLevels; BYTE bVendorId[CPUID_VENDORID_MAX+1]; DWORD dwSignature; DWORD dwFeatureFlags[3]; BYTE cConfigurations; BYTE bConfigurations[CPUID_CONFIGURATIONS_MAX]; CPUID_PROCESSOR_SERIAL_NUMBER bProcessorSerialNumber; } CPUID_INFORMATION, FAR* LPCPUID_INFORMATION; typedef struct _CPUID_INFORMATION_EX { // CPUID_INFORMATION compatible DWORD dwSize; DWORD dwFlags; DWORD dwLevels; BYTE bVendorId[CPUID_VENDORID_MAX+1]; DWORD dwSignature; DWORD dwFeatureFlags[3]; BYTE cConfigurations; BYTE bConfigurations[CPUID_CONFIGURATIONS_MAX]; CPUID_PROCESSOR_SERIAL_NUMBER bProcessorSerialNumber; // CPUID_INFORMATION_EX DWORD dwEXLevels; BYTE bEXVendorId[CPUID_EXVENDORID_MAX+1]; DWORD dwEXFeatureFlags[4]; BYTE bEXBrandString[CPUID_EXBRANDSTRING_MAX+1]; } CPUID_INFORMATION_EX, FAR* LPCPUID_INFORMATION_EX; #pragma pack( pop ) inline STDMETHODIMP cpuid_getinformation( LPCPUID_INFORMATION pinfo ){ HRESULT hresult = S_OK; if( !pinfo ||(( pinfo->dwSize != sizeof( CPUID_INFORMATION ))&&( pinfo->dwSize != sizeof( CPUID_INFORMATION_EX )))){ hresult = E_INVALIDARG; } if( SUCCEEDED( hresult )){ CPUID_INFORMATION_EX info = { sizeof( info ) }; if( cpuid_issupported()){ info.dwFlags |= CPUID_FLAGS_SUPPORTED; DWORD dwVendorId[3] = {}; DWORD dwLevels = cpuid( CPUID_GET_VERSION, 0, NULL, &dwVendorId[0], &dwVendorId[2], &dwVendorId[1] ); if(( dwLevels & 0xffff0000 ) == 0x00000000 ){ info.dwLevels = dwLevels & 0x0000ffff; if( dwLevels >= CPUID_GET_VERSION ){ for( size_t n = 0; n < elementsof( dwVendorId ); ++n ){ for( size_t m = 0; m < elementsizeof( dwVendorId ); ++m ){ info.bVendorId[n*4+m] = ( BYTE )(( dwVendorId[n] >> (8*m)) & 0x0000000ff ); } } } if( dwLevels >= CPUID_GET_SIGNATURE ){ cpuid( CPUID_GET_SIGNATURE, 0, &info.dwSignature, &info.dwFeatureFlags[0], &info.dwFeatureFlags[1], &info.dwFeatureFlags[2] ); } if( dwLevels >= CPUID_GET_CONFIGURATIONS ){ DWORD dwConfigurations[4] = {}; cpuid( CPUID_GET_CONFIGURATIONS, 0, &dwConfigurations[0], &dwConfigurations[1], &dwConfigurations[2], &dwConfigurations[3] ); LPBYTE pbConfigurations = &(( LPBYTE )dwConfigurations)[1]; info.cConfigurations = ( BYTE )( dwConfigurations[0] & 0x000000ff ); for( size_t n = 0; n < elementsof( info.bConfigurations ); ++n ){ info.bConfigurations[n] = pbConfigurations[n]; } } if( dwLevels >= CPUID_GET_SERIAL_NUMBER ){ DWORD dwProcessorSerialNumber[4] = {}; cpuid( CPUID_GET_SERIAL_NUMBER, 0, &dwProcessorSerialNumber[0], &dwProcessorSerialNumber[1], &dwProcessorSerialNumber[2], &dwProcessorSerialNumber[3] ); CopyMemory( &info.bProcessorSerialNumber, dwProcessorSerialNumber, sizeof( info.bProcessorSerialNumber )); } } DWORD dwEXVendorId[3] = {}; DWORD dwEXLevels = cpuid( CPUID_GET_EX_VERSION, 0, NULL, &dwEXVendorId[0], &dwEXVendorId[2], &dwEXVendorId[1] ); if(( dwEXLevels & 0xffff0000 ) == CPUID_FLAGS_EX ){ info.dwEXLevels = dwEXLevels & 0x0000ffff; info.dwFlags |= CPUID_FLAGS_EX; if( dwEXLevels >= CPUID_GET_EX_VERSION ){ for( size_t n = 0; n < elementsof( dwEXVendorId ); ++n ){ for( size_t m = 0; m < elementsizeof( dwEXVendorId ); ++m ){ info.bEXVendorId[n*4+m] = ( BYTE )(( dwEXVendorId[n] >> (8*m)) & 0x0000000ff ); } } } if( dwEXLevels >= CPUID_GET_EX_SIGNATURE ){ cpuid( CPUID_GET_EX_SIGNATURE, 0, &info.dwEXFeatureFlags[0], &info.dwEXFeatureFlags[1], &info.dwEXFeatureFlags[2], &info.dwEXFeatureFlags[3] ); } if( dwEXLevels >= CPUID_GET_EX_BRAND_STRING1 ){ LONG cParts = dwEXLevels - CPUID_GET_EX_BRAND_STRING1; if( cParts > 3 ){ cParts = 3; } for( LONG l = 0; l < cParts; ++l ){ DWORD dwEXBrandString[4] = {}; cpuid( CPUID_GET_EX_BRAND_STRING1+l, 0, &dwEXBrandString[0], &dwEXBrandString[1], &dwEXBrandString[2], &dwEXBrandString[3] ); for( size_t n = 0; n < elementsof( dwEXBrandString ); ++n ){ for( size_t m = 0; m < elementsizeof( dwEXBrandString ); ++m ){ info.bEXBrandString[4*sizeof( DWORD )*l+n*4+m] = ( BYTE )(( dwEXBrandString[n] >> (8*m)) & 0x0000000ff ); } } } } } } if( pinfo->dwSize == sizeof( CPUID_INFORMATION_EX )){ *( LPCPUID_INFORMATION_EX )pinfo = *( LPCPUID_INFORMATION_EX )&info; } else if( pinfo->dwSize == sizeof( CPUID_INFORMATION )){ *( LPCPUID_INFORMATION )pinfo = *( LPCPUID_INFORMATION )&info; } //else{ // hresult = E_UNEXPECTED; // 事前にチェックしてあるからここには来ないはず //} } return hresult; }
アセンブラと CPU を C++ で実装する
わからないなら書いてしまえばいいというのは、アセンブラを使ってみようということでもありますが、アセンブラと CPU を C++ で書いてしまおうという意味でもあります
アセンブラも CPU も書いてしまいましょう
なんのことかわかりませんか?
次のようなクラスを書いてみようということです
int main(){ vm_t vm; register8_t& al_ = vm.al_(); asm_t asm_; asm_.mov( al_, 3 ); signed_int32_t label0 = asm_.label(); asm_.dec( al_ ); asm_.jnz( label0 ); vm.exec( asm_ ); return 0; }
これはアセンブラではありませんが、見た目はアセンブラですよね
でも C++ ですから、何をやっているかなんていうのは簡単ですよね
こんなものを書いてみましょう
実装例
#if defined( _MSC_VER ) // C4351 : 新しい動作: 配列 '%1' の要素は既定で初期化されます #pragma warning( disable : 4351 ) #endif // _MSC_VER #include <stdio.h> #include <stdarg.h> #include <vector> typedef signed char signed_int8_t; typedef unsigned char unsigned_int8_t; typedef signed short signed_int16_t; typedef unsigned short unsigned_int16_t; typedef signed int signed_int32_t; typedef unsigned int unsigned_int32_t; union union_int16_t { unsigned_int16_t x; unsigned_int8_t h[2]; }; union union_int32_t { signed_int32_t e; unsigned_int16_t x[2]; unsigned_int8_t h[4]; }; enum register8_type { register8_type_al, register8_type_ah, register8_type_bl, register8_type_bh, register8_type_cl, register8_type_ch, register8_type_dl, register8_type_dh, register8_types }; enum register16_type { register16_type_ax, register16_type_bx, register16_type_cx, register16_type_dx, register16_type_si, register16_type_di, register16_type_bp, register16_type_sp, register16_type_cflags, register16_types }; enum register32_type { register32_type_eax, register32_type_ebx, register32_type_ecx, register32_type_edx, register32_type_esi, register32_type_edi, register32_type_ebp, register32_type_esp, register32_type_eflags, register32_type_eip, register32_types }; class asm_t; class vm_t; struct register8_t; struct register16_t; struct register32_t; struct immediate8_t { typedef unsigned_int8_t value_type; protected: value_type m_value; public: operator value_type() const { return m_value; } immediate8_t( value_type value ): m_value(value) { } immediate8_t( const immediate8_t& rhs ): m_value(rhs.m_value) { } immediate8_t& operator=( const immediate8_t& rhs ){ if( this != &rhs ){ m_value = rhs.m_value; } return *this; } private: // イミディエイト値は必ず値があるので引数が必要 immediate8_t(); }; struct immediate16_t { typedef unsigned_int16_t value_type; protected: value_type m_value; public: operator value_type() const { return m_value; } immediate16_t( value_type value ): m_value(value) { } immediate16_t( const immediate16_t& rhs ): m_value(rhs.m_value) { } immediate16_t& operator=( const immediate16_t& rhs ){ if( this != &rhs ){ m_value = rhs.m_value; } return *this; } private: // イミディエイト値は必ず値があるので引数が必要 immediate16_t(); }; struct immediate32_t { typedef signed_int32_t value_type; protected: value_type m_value; public: operator value_type() const { return m_value; } immediate32_t( value_type value ): m_value(value) { } immediate32_t( const immediate32_t& rhs ): m_value(rhs.m_value) { } immediate32_t& operator=( const immediate32_t& rhs ){ if( this != &rhs ){ m_value = rhs.m_value; } return *this; } private: // イミディエイト値は必ず値があるので引数が必要 immediate32_t(); }; struct address8_t { typedef unsigned_int8_t* value_type; protected: value_type m_value; public: operator value_type() const { return m_value; } address8_t( value_type value ): m_value(value) { } address8_t( const address8_t& rhs ): m_value(rhs.m_value) { } address8_t& operator=( const address8_t& rhs ){ if( this != &rhs ){ m_value = rhs.m_value; } return *this; } address8_t& operator=( register8_t& rhs ); private: // アドレスは必ず参照先があるので引数が必要 address8_t(); }; struct address16_t { typedef unsigned_int16_t* value_type; protected: value_type m_value; public: operator value_type() const { return m_value; } address16_t( value_type value ): m_value(value) { } address16_t( const address16_t& rhs ): m_value(rhs.m_value) { } address16_t& operator=( const address16_t& rhs ){ if( this != &rhs ){ m_value = rhs.m_value; } return *this; } address16_t& operator=( register16_t& rhs ); private: // アドレスは必ず参照先があるので引数が必要 address16_t(); }; struct address32_t { typedef signed_int32_t* value_type; protected: value_type m_value; public: operator value_type() const { return m_value; } address32_t( value_type value ): m_value(value) { } address32_t( const address32_t& rhs ): m_value(rhs.m_value) { } address32_t& operator=( const address32_t& rhs ){ if( this != &rhs ){ m_value = rhs.m_value; } return *this; } address32_t& operator=( register32_t& rhs ); private: // アドレスは必ず参照先があるので引数が必要 address32_t(); }; template<typename register_type> struct indirect_t { typedef register_type* value_type; protected: value_type m_value; public: register_type& operator*() const { return *m_value; } indirect_t( value_type value ): m_value(value) { } indirect_t( const indirect_t& rhs ): m_value(rhs.m_value) { } indirect_t& operator=( const register_type& rhs ){ *reinterpret_cast<typename register_type::value_type*>(static_cast<typename register_type::value_type>(*m_value)) = rhs; return *this; } private: // レジスタ間接参照は必ず参照先のレジスタがあるので引数が必要 indirect_t(); }; struct register8_t { typedef unsigned_int8_t value_type; protected: register8_type m_type; value_type& m_value; public: register8_t& operator++(){ ++m_value; return *this; } register8_t& operator--(){ --m_value; return *this; } register8_t& operator+=( value_type d ){ m_value += d; return *this; } register8_t& operator-=( value_type d ){ m_value -= d; return *this; } register8_t& operator=( value_type rhs ){ m_value = rhs; return *this; } register8_t& operator=( const immediate8_t& rhs ){ m_value = rhs; return *this; } register8_t& operator=( const address8_t& rhs ){ m_value = *rhs; return *this; } operator value_type() const { return m_value; } explicit register8_t( register8_type type, value_type& value ): m_type(type), m_value(value) { } register8_t& operator=( register8_t& rhs ){ if( this != &rhs ){ m_value = rhs.m_value; } return *this; } private: // 8ビットレジスタは必ず 16ビットレジスタの一部なので独自の実体は持たない register8_t(); // レジスタは必ず実体を持っているのでコピー禁止 register8_t( const register8_t& rhs ); }; struct register16_t { typedef unsigned_int16_t value_type; protected: register16_type m_type; value_type& m_value; public: register16_t& operator++(){ ++m_value; return *this; } register16_t& operator--(){ --m_value; return *this; } register16_t& operator+=( value_type d ){ m_value += d; return *this; } register16_t& operator-=( value_type d ){ m_value -= d; return *this; } register16_t& operator=( value_type rhs ){ m_value = rhs; return *this; } register16_t& operator=( const immediate16_t& rhs ){ m_value = rhs; return *this; } register16_t& operator=( const address16_t& rhs ){ m_value = *rhs; return *this; } operator value_type() const { return m_value; } explicit register16_t( register16_type type, value_type& value ): m_type(type), m_value(value) { } register16_t& operator=( register16_t& rhs ){ if( this != &rhs ){ m_value = rhs.m_value; } return *this; } private: // 16ビットレジスタは必ず 32ビットレジスタの一部なので独自の実体は持たない register16_t(); // レジスタは必ず実体を持っているのでコピー禁止 register16_t( const register16_t& rhs ); }; struct register32_t { typedef signed_int32_t value_type; protected: register32_type m_type; value_type m_value; public: register32_t& operator++(){ ++m_value; return *this; } register32_t& operator--(){ --m_value; return *this; } register32_t& operator+=( value_type d ){ m_value += d; return *this; } register32_t& operator-=( value_type d ){ m_value -= d; return *this; } register32_t& operator=( value_type rhs ){ m_value = rhs; return *this; } register32_t& operator=( const immediate32_t& rhs ){ m_value = rhs; return *this; } register32_t& operator=( const address32_t& rhs ){ m_value = *rhs; return *this; } register32_t& operator=( const indirect_t<register32_t>& rhs ){ m_value = *rhs; return *this; } operator value_type() const { return m_value; } indirect_t<register32_t> operator*(){ return indirect_t<register32_t>(this); } register32_t( register32_type type ): m_type(type), m_value() { } register32_t& operator=( register32_t& rhs ){ if( this != &rhs ){ m_value = rhs.m_value; } return *this; } private: // レジスタは必ずタイプを指定する register32_t(); // レジスタは必ず実体を持っているのでコピー禁止 register32_t( const register32_t& rhs ); }; template<int _size> struct register_t; template<> struct register_t<8> { typedef register8_t& value_type; protected: value_type m_r; public: operator value_type() const { return m_r; } register_t( value_type _r ): m_r(_r) { } private: register_t(); register_t& operator=( const register_t& ); }; template<> struct register_t<16> { typedef register16_t& value_type; protected: value_type m_r; public: operator value_type() const { return m_r; } register_t( value_type _r ): m_r(_r) { } private: register_t(); register_t& operator=( const register_t& ); }; template<> struct register_t<32> { typedef register32_t& value_type; protected: value_type m_r; public: operator value_type() const { return m_r; } indirect_t<register32_t> operator*() const { return m_r.operator*(); } register_t( value_type _r ): m_r(_r) { } private: register_t(); register_t& operator=( const register_t& ); }; inline address8_t& address8_t::operator=( register8_t& rhs ){ *m_value = rhs; return *this; } inline address16_t& address16_t::operator=( register16_t& rhs ){ *m_value = rhs; return *this; } inline address32_t& address32_t::operator=( register32_t& rhs ){ *m_value = rhs; return *this; } enum operand_type_t { operand_type_void, operand_type_register32, operand_type_register16, operand_type_register8, operand_type_address32, operand_type_address16, operand_type_address8, operand_type_immediate32, operand_type_immediate16, operand_type_immediate8, operand_type_register32_indirect, operand_types }; struct operand_t { operand_type_t type; union { register32_t* r32; register16_t* r16; register8_t* r8; signed_int32_t* p32; unsigned_int16_t* p16; unsigned_int8_t* p8; signed_int32_t i32; unsigned_int16_t i16; unsigned_int8_t i8; }; operand_t(): type(operand_type_void) { } operand_t( register8_t& _r ): type(operand_type_register8) { r8 = &_r; } operand_t( register16_t& _r ): type(operand_type_register16) { r16 = &_r; } operand_t( register32_t& _r ): type(operand_type_register32) { r32 = &_r; } operand_t( const address8_t& _p ): type(operand_type_address8) { p8 = _p; } operand_t( const address16_t& _p ): type(operand_type_address16) { p16 = _p; } operand_t( const address32_t& _p ): type(operand_type_address32) { p32 = _p; } operand_t( const immediate8_t& _i ): type(operand_type_immediate8) { i8 = _i; } operand_t( const immediate16_t& _i ): type(operand_type_immediate16) { i16 = _i; } operand_t( const immediate32_t& _i ): type(operand_type_immediate32) { i32 = _i; } operand_t( const indirect_t<register32_t>& _r ): type(operand_type_register32_indirect) { r32 = &*_r; } operand_t( const register_t<8>& _r ): type(operand_type_register8) { r8 = &static_cast<register8_t&>(_r); } operand_t( const register_t<16>& _r ): type(operand_type_register16) { r16 = &static_cast<register16_t&>(_r); } operand_t( const register_t<32>& _r ): type(operand_type_register32) { r32 = &static_cast<register32_t&>(_r); } operator register8_t&() const { return *r8; } operator register16_t&() const { return *r16; } operator register32_t&() const { return *r32; } operator address8_t() const { return p8; } operator address16_t() const { return p16; } operator address32_t() const { return p32; } operator immediate8_t() const { return i8; } operator immediate16_t() const { return i16; } operator immediate32_t() const { return i32; } operator indirect_t<register32_t>() const { return r32; } }; template<typename T> struct operand_traits_t { typedef void output_argument_type; typedef void input_argument_type; typedef void value_type; static const int type = operand_type_void; }; template<> struct operand_traits_t<indirect_t<register32_t> > { typedef indirect_t<register32_t> output_argument_type; typedef const indirect_t<register32_t>& input_argument_type; typedef register32_t::value_type value_type; static const int type = operand_type_register32_indirect; }; template<> struct operand_traits_t<register_t<8> > { typedef register8_t& output_argument_type; typedef register8_t& input_argument_type; typedef register8_t::value_type value_type; static const int type = operand_type_register32; }; template<> struct operand_traits_t<register_t<16> > { typedef register16_t& output_argument_type; typedef register16_t& input_argument_type; typedef register16_t::value_type value_type; static const int type = operand_type_register16; }; template<> struct operand_traits_t<register_t<32> > { typedef register32_t& output_argument_type; typedef register32_t& input_argument_type; typedef register32_t::value_type value_type; static const int type = operand_type_register8; }; template<> struct operand_traits_t<register32_t> { typedef register32_t& output_argument_type; typedef register32_t& input_argument_type; typedef register32_t::value_type value_type; static const int type = operand_type_register32; }; template<> struct operand_traits_t<register16_t> { typedef register16_t& output_argument_type; typedef register16_t& input_argument_type; typedef register16_t::value_type value_type; static const int type = operand_type_register16; }; template<> struct operand_traits_t<register8_t> { typedef register8_t& output_argument_type; typedef register8_t& input_argument_type; typedef register8_t::value_type value_type; static const int type = operand_type_register8; }; template<> struct operand_traits_t<register32_t&> { typedef register32_t& output_argument_type; typedef register32_t& input_argument_type; typedef register32_t::value_type value_type; static const int type = operand_type_register32; }; template<> struct operand_traits_t<register16_t&> { typedef register16_t& output_argument_type; typedef register16_t& input_argument_type; typedef register16_t::value_type value_type; static const int type = operand_type_register16; }; template<> struct operand_traits_t<register8_t&> { typedef register8_t& output_argument_type; typedef register8_t& input_argument_type; typedef register8_t::value_type value_type; static const int type = operand_type_register8; }; template<> struct operand_traits_t<address32_t> { typedef address32_t output_argument_type; typedef const address32_t& input_argument_type; typedef signed_int32_t* value_type; static const int type = operand_type_address32; }; template<> struct operand_traits_t<address16_t> { typedef address16_t output_argument_type; typedef const address16_t& input_argument_type; typedef unsigned_int16_t* value_type; static const int type = operand_type_address16; }; template<> struct operand_traits_t<address8_t> { typedef address8_t output_argument_type; typedef const address8_t& input_argument_type; typedef unsigned_int8_t* value_type; static const int type = operand_type_address8; }; template<> struct operand_traits_t<const address32_t&> { typedef address32_t output_argument_type; typedef const address32_t& input_argument_type; typedef signed_int32_t* value_type; static const int type = operand_type_address32; }; template<> struct operand_traits_t<const address16_t&> { typedef address16_t output_argument_type; typedef const address16_t& input_argument_type; typedef unsigned_int16_t* value_type; static const int type = operand_type_address16; }; template<> struct operand_traits_t<const address8_t&> { typedef address8_t output_argument_type; typedef const address8_t& input_argument_type; typedef unsigned_int8_t* value_type; static const int type = operand_type_address8; }; template<> struct operand_traits_t<signed_int32_t*> { typedef address32_t output_argument_type; typedef const address32_t& input_argument_type; typedef signed_int32_t* value_type; static const int type = operand_type_address32; }; template<> struct operand_traits_t<unsigned_int16_t*> { typedef address16_t output_argument_type; typedef const address16_t& input_argument_type; typedef unsigned_int16_t* value_type; static const int type = operand_type_address16; }; template<> struct operand_traits_t<unsigned_int8_t*> { typedef address8_t output_argument_type; typedef const address8_t& input_argument_type; typedef unsigned_int8_t* value_type; static const int type = operand_type_address8; }; template<> struct operand_traits_t<immediate32_t> { typedef void output_argument_type; typedef const immediate32_t& input_argument_type; typedef signed_int32_t value_type; static const int type = operand_type_immediate32; }; template<> struct operand_traits_t<immediate16_t> { typedef void output_argument_type; typedef const immediate16_t& input_argument_type; typedef unsigned_int16_t value_type; static const int type = operand_type_immediate16; }; template<> struct operand_traits_t<immediate8_t> { typedef void output_argument_type; typedef const immediate8_t& input_argument_type; typedef unsigned_int8_t value_type; static const int type = operand_type_immediate8; }; template<> struct operand_traits_t<const immediate32_t&> { typedef void output_argument_type; typedef const immediate32_t& input_argument_type; typedef signed_int32_t value_type; static const int type = operand_type_immediate32; }; template<> struct operand_traits_t<const immediate16_t&> { typedef void output_argument_type; typedef const immediate16_t& input_argument_type; typedef unsigned_int16_t value_type; static const int type = operand_type_immediate16; }; template<> struct operand_traits_t<const immediate8_t&> { typedef void output_argument_type; typedef const immediate8_t& input_argument_type; typedef unsigned_int8_t value_type; static const int type = operand_type_immediate8; }; template<> struct operand_traits_t<signed_int32_t> { typedef void output_argument_type; typedef const immediate32_t& input_argument_type; typedef signed_int32_t value_type; static const int type = operand_type_immediate32; }; template<> struct operand_traits_t<unsigned_int16_t> { typedef void output_argument_type; typedef const immediate16_t& input_argument_type; typedef unsigned_int16_t value_type; static const int type = operand_type_immediate16; }; template<> struct operand_traits_t<unsigned_int8_t> { typedef void output_argument_type; typedef const immediate8_t& input_argument_type; typedef unsigned_int8_t value_type; static const int type = operand_type_immediate8; }; template<bool _value> struct bool_type { static const bool value = _value; }; template<typename argument_type, int = operand_traits_t<argument_type>::type> struct is_register : public bool_type<false> {}; template<typename argument_type> struct is_register<argument_type,operand_type_register32> : public bool_type<true> {}; template<typename argument_type> struct is_register<argument_type,operand_type_register16> : public bool_type<true> {}; template<typename argument_type> struct is_register<argument_type,operand_type_register8> : public bool_type<true> {}; template<typename argument_type, int = operand_traits_t<argument_type>::type> struct is_address : public bool_type<false> {}; template<typename argument_type> struct is_address<argument_type,operand_type_address32> : public bool_type<true> {}; template<typename argument_type> struct is_address<argument_type,operand_type_address16> : public bool_type<true> {}; template<typename argument_type> struct is_address<argument_type,operand_type_address8> : public bool_type<true> {}; template<typename argument_type, int = operand_traits_t<argument_type>::type> struct is_immediate : public bool_type<false> {}; template<typename argument_type> struct is_immediate<argument_type,operand_type_immediate32> : public bool_type<true> {}; template<typename argument_type> struct is_immediate<argument_type,operand_type_immediate16> : public bool_type<true> {}; template<typename argument_type> struct is_immediate<argument_type,operand_type_immediate8> : public bool_type<true> {}; enum opcode_t { opcode_nop, opcode_mov, opcode_lea, opcode_inc, opcode_dec, opcode_jmp, opcode_jz, opcode_jnz, opcode_push, opcode_pop, opcode_call, opcode_ret, opcodes }; class mnemonic_t { protected: typedef void (*callback0_t)( vm_t&, opcode_t ); typedef void (*callback1_t)( vm_t&, opcode_t, const operand_t& ); typedef void (*callback2_t)( vm_t&, opcode_t, const operand_t&, const operand_t& ); typedef void (*callback3_t)( vm_t&, opcode_t, const operand_t&, const operand_t&, const operand_t& ); struct callback_t { callback0_t m_callback; public: void operator()( vm_t& vm, opcode_t opcode ){ m_callback( vm, opcode ); } void operator()( vm_t& vm, opcode_t opcode, const operand_t& operand1 ){ reinterpret_cast<callback1_t>(m_callback)( vm, opcode, operand1 ); } void operator()( vm_t& vm, opcode_t opcode, const operand_t& operand1, const operand_t& operand2 ){ reinterpret_cast<callback2_t>(m_callback)( vm, opcode, operand1, operand2 ); } void operator()( vm_t& vm, opcode_t opcode, const operand_t& operand1, const operand_t& operand2, const operand_t& operand3 ){ reinterpret_cast<callback3_t>(m_callback)( vm, opcode, operand1, operand2, operand3 ); } callback_t( callback0_t callback ): m_callback(callback) { } callback_t( callback1_t callback ): m_callback(reinterpret_cast<callback0_t>(callback)) { } callback_t( callback2_t callback ): m_callback(reinterpret_cast<callback0_t>(callback)) { } callback_t( callback3_t callback ): m_callback(reinterpret_cast<callback0_t>(callback)) { } }; callback_t m_callback; opcode_t m_opcode; std::vector<operand_t> m_operands; public: opcode_t opcode() const { return m_opcode; } const operand_t& operand( size_t n ) const { return m_operands[n]; } const operand_t& operator[]( size_t n ) const { return m_operands[n]; } size_t size() const { return m_operands.size(); } mnemonic_t( callback0_t callback, opcode_t opcode ): m_callback(callback), m_opcode(opcode) { } mnemonic_t( callback1_t callback, opcode_t opcode, const operand_t& operand1 ): m_callback(callback), m_opcode(opcode) { m_operands.push_back( operand1 ); } mnemonic_t( callback2_t callback, opcode_t opcode, const operand_t& operand1, const operand_t& operand2 ): m_callback(callback), m_opcode(opcode) { m_operands.push_back( operand1 ); m_operands.push_back( operand2 ); } mnemonic_t( callback3_t callback, opcode_t opcode, const operand_t& operand1, const operand_t& operand2, const operand_t& operand3 ): m_callback(callback), m_opcode(opcode) { m_operands.push_back( operand1 ); m_operands.push_back( operand2 ); m_operands.push_back( operand3 ); } void exec( vm_t& vm ){ if( m_operands.empty()){ m_callback( vm, m_opcode ); } else if( m_operands.size() == 1 ){ m_callback( vm, m_opcode, m_operands[0] ); } else if( m_operands.size() == 2 ){ m_callback( vm, m_opcode, m_operands[0], m_operands[1] ); } else if( m_operands.size() == 3 ){ m_callback( vm, m_opcode, m_operands[0], m_operands[1], m_operands[2] ); } } }; struct eax_t : public register32_t { struct ax_t : public register16_t { register8_t al_; register8_t ah_; ax_t( unsigned_int16_t& value ): register16_t(register16_type_ax,value), al_(register8_type_al,reinterpret_cast<union_int16_t&>(value).h[0]), ah_(register8_type_ah,reinterpret_cast<union_int16_t&>(value).h[1]) { } using register16_t::operator=; }; ax_t ax_; eax_t(): register32_t(register32_type_eax), ax_(reinterpret_cast<union_int32_t&>(m_value).x[0]) { } using register32_t::operator=; }; struct ebx_t : public register32_t { struct bx_t : public register16_t { register8_t bl_; register8_t bh_; bx_t( unsigned_int16_t& value ): register16_t(register16_type_bx,value), bl_(register8_type_bl,reinterpret_cast<union_int16_t&>(value).h[0]), bh_(register8_type_bh,reinterpret_cast<union_int16_t&>(value).h[1]) { } using register16_t::operator=; }; bx_t bx_; ebx_t(): register32_t(register32_type_ebx), bx_(reinterpret_cast<union_int32_t&>(m_value).x[0]) { } using register32_t::operator=; }; struct ecx_t : public register32_t { struct cx_t : public register16_t { register8_t cl_; register8_t ch_; cx_t( unsigned_int16_t& value ): register16_t(register16_type_cx,value), cl_(register8_type_cl,reinterpret_cast<union_int16_t&>(value).h[0]), ch_(register8_type_ch,reinterpret_cast<union_int16_t&>(value).h[1]) { } using register16_t::operator=; }; cx_t cx_; ecx_t(): register32_t(register32_type_ecx), cx_(reinterpret_cast<union_int32_t&>(m_value).x[0]) { } using register32_t::operator=; }; struct edx_t : public register32_t { struct dx_t : public register16_t { register8_t dl_; register8_t dh_; dx_t( unsigned_int16_t& value ): register16_t(register16_type_dx,value), dl_(register8_type_dl,reinterpret_cast<union_int16_t&>(value).h[0]), dh_(register8_type_dh,reinterpret_cast<union_int16_t&>(value).h[1]) { } using register16_t::operator=; }; dx_t dx_; edx_t(): register32_t(register32_type_edx), dx_(reinterpret_cast<union_int32_t&>(m_value).x[0]) { } using register32_t::operator=; }; struct esi_t : public register32_t { register16_t si_; esi_t(): register32_t(register32_type_esi), si_(register16_type_si,reinterpret_cast<union_int32_t&>(m_value).x[0]) { } using register32_t::operator=; }; struct edi_t : public register32_t { register16_t di_; edi_t(): register32_t(register32_type_edi), di_(register16_type_di,reinterpret_cast<union_int32_t&>(m_value).x[0]) { } using register32_t::operator=; }; struct ebp_t : public register32_t { register16_t bp_; ebp_t(): register32_t(register32_type_ebp), bp_(register16_type_bp,reinterpret_cast<union_int32_t&>(m_value).x[0]) { } using register32_t::operator=; }; struct esp_t : public register32_t { register16_t sp_; esp_t(): register32_t(register32_type_esp), sp_(register16_type_sp,reinterpret_cast<union_int32_t&>(m_value).x[0]) { } using register32_t::operator=; }; struct eip_t : public register32_t { eip_t(): register32_t(register32_type_eip) { } using register32_t::operator=; }; #define CFLAGS_CF 0x00000001 // キャリーフラグ #define CFLAGS_PF 0x00000004 // パリティフラグ #define CFLAGS_ZF 0x00000040 // ゼロフラグ #define CFLAGS_SF 0x00000080 // サインフラグ #define CFLAGS_OF 0x00000800 // オーバーフローフラグ #define EFLAGS_CF CFLAGS_CF #define EFLAGS_PF CFLAGS_PF #define EFLAGS_ZF CFLAGS_ZF #define EFLAGS_SF CFLAGS_SF #define EFLAGS_OF CFLAGS_OF #if !defined( _BIT_COUNT_ ) inline unsigned_int8_t bit_count_population8( unsigned_int8_t b ) { b = static_cast<unsigned_int8_t>(( b & 0x55 ) + (( b >> 1 ) & 0x55 )); // 01010101 b = static_cast<unsigned_int8_t>(( b & 0x33 ) + (( b >> 2 ) & 0x33 )); // 00110011 b = static_cast<unsigned_int8_t>(( b & 0x0f ) + (( b >> 4 ) & 0x0f )); // 00001111 return b; } #endif // _BIT_COUNT_ class eflags_t : public register32_t { struct cflags_t : public register16_t { cflags_t( unsigned_int16_t& value ):register16_t(register16_type_cflags,value){} bool cf() const { return !!( m_value & CFLAGS_CF ); } bool pf() const { return !!( m_value & CFLAGS_PF ); } bool zf() const { return !!( m_value & CFLAGS_ZF ); } bool sf() const { return !!( m_value & CFLAGS_SF ); } bool of() const { return !!( m_value & CFLAGS_OF ); } }; cflags_t m_cflags; public: eflags_t():register32_t(register32_type_eflags),m_cflags(reinterpret_cast<union_int32_t&>(m_value).x[0]){} bool cf() const { return m_cflags.cf(); } bool pf() const { return m_cflags.pf(); } bool zf() const { return m_cflags.zf(); } bool sf() const { return m_cflags.sf(); } bool of() const { return m_cflags.of(); } void cmp1( signed_int32_t value, signed_int32_t mask ){ signed_int32_t flags = 0; if( mask & CFLAGS_ZF ){ if( !value ){ flags |= CFLAGS_ZF; } } if( mask & CFLAGS_SF ){ if( value < 0 ){ flags |= CFLAGS_SF; } } if( mask & CFLAGS_PF ){ if( ~bit_count_population8( reinterpret_cast<union_int32_t&>(value).h[0] ) & 1 ){ flags |= CFLAGS_PF; } } m_value = ( m_value & ~mask ) | ( flags & mask ); } void cmp2( signed_int32_t lhs, signed_int32_t rhs, signed_int32_t mask ){ cmp1( lhs, mask & (CFLAGS_ZF|CFLAGS_SF|CFLAGS_PF)); mask &= ~(CFLAGS_ZF|CFLAGS_SF|CFLAGS_PF); signed_int32_t flags = 0; if( mask & CFLAGS_OF ){ // true : 0x7ffffffff <-> 0x800000000 if( static_cast<signed_int32_t>( static_cast<unsigned_int32_t>(lhs) ^ static_cast<unsigned_int32_t>(rhs)) < 0 ){ flags |= CFLAGS_OF; } } m_value = ( m_value & ~mask ) | ( flags & mask ); } void cmp3( signed_int32_t lhs, signed_int32_t rhs, signed_int32_t d, signed_int32_t mask ){ cmp2( lhs, rhs, mask & (CFLAGS_ZF|CFLAGS_SF|CFLAGS_PF|CFLAGS_OF)); mask &= ~(CFLAGS_ZF|CFLAGS_SF|CFLAGS_PF|CFLAGS_OF); signed_int32_t flags = 0; if( mask & CFLAGS_CF ){ // true : 0xffffffff <-> 0x00000000 if(( static_cast<unsigned_int32_t>(lhs) < static_cast<unsigned_int32_t>(rhs)) != ( d < 0 )){ flags |= CFLAGS_CF; } } m_value = ( m_value & ~mask ) | ( flags & mask ); } using register32_t::operator=; }; class vm_t { protected: eax_t m_eax; ebx_t m_ebx; ecx_t m_ecx; edx_t m_edx; esi_t m_esi; edi_t m_edi; ebp_t m_ebp; esp_t m_esp; eip_t m_eip; eflags_t m_eflags; char m_stack[1024]; public: register32_t& eax_(){ return m_eax; } register32_t& ebx_(){ return m_ebx; } register32_t& ecx_(){ return m_ecx; } register32_t& edx_(){ return m_edx; } register32_t& esi_(){ return m_esi; } register32_t& edi_(){ return m_edi; } register32_t& ebp_(){ return m_ebp; } register32_t& esp_(){ return m_esp; } register16_t& ax_(){ return m_eax.ax_; } register16_t& bx_(){ return m_ebx.bx_; } register16_t& cx_(){ return m_ecx.cx_; } register16_t& dx_(){ return m_edx.dx_; } register16_t& si_(){ return m_esi.si_; } register16_t& di_(){ return m_edi.di_; } register16_t& bp_(){ return m_ebp.bp_; } register8_t& al_(){ return m_eax.ax_.al_; } register8_t& ah_(){ return m_eax.ax_.ah_; } register8_t& bl_(){ return m_ebx.bx_.bl_; } register8_t& bh_(){ return m_ebx.bx_.bh_; } register8_t& cl_(){ return m_ecx.cx_.cl_; } register8_t& ch_(){ return m_ecx.cx_.ch_; } register8_t& dl_(){ return m_edx.dx_.dl_; } register8_t& dh_(){ return m_edx.dx_.dh_; } void cmp1( signed_int32_t value, signed_int32_t flags = EFLAGS_PF|EFLAGS_ZF|EFLAGS_SF ){ m_eflags.cmp1( value, flags ); } void cmp2( signed_int32_t lhs, signed_int32_t rhs, signed_int32_t flags = EFLAGS_PF|EFLAGS_ZF|EFLAGS_SF|EFLAGS_OF ){ m_eflags.cmp2( lhs, rhs, flags ); } void cmp3( signed_int32_t lhs, signed_int32_t rhs, signed_int32_t d, signed_int32_t flags = EFLAGS_PF|EFLAGS_ZF|EFLAGS_SF|EFLAGS_OF|EFLAGS_CF ){ m_eflags.cmp3( lhs, rhs, d, flags ); } void reset(){ m_eax = 0; m_ebx = 0; m_ecx = 0; m_edx = 0; m_esi = 0; m_edi = 0; m_ebp = 0; m_esp = reinterpret_cast<int>(&m_stack[sizeof(m_stack)]); m_eip = 0; m_eflags = 0; } void exec( asm_t& ); vm_t(): m_eax(), m_ebx(), m_ecx(), m_edx(), m_esi(), m_edi(), m_ebp(), m_esp(), m_eip(), m_eflags(), m_stack() { reset(); } void nop(){ ++m_eip; } template<typename first_argument_type, typename second_argument_type> void mov( first_argument_type lhs, second_argument_type rhs ){ lhs = rhs; ++m_eip; } template<typename first_argument_type, typename second_argument_type> void lea( first_argument_type lhs, second_argument_type rhs ){ union { typename operand_traits_t<second_argument_type>::value_type rhs; typename operand_traits_t<first_argument_type>::value_type lhs; } temp = { rhs }; lhs = temp.lhs; ++m_eip; } template<typename argument_type> void inc( argument_type operand ){ typename operand_traits_t<argument_type>::value_type prev = operand; ++operand; cmp2( operand, prev ); ++m_eip; } template<typename argument_type> void dec( argument_type operand ){ typename operand_traits_t<argument_type>::value_type prev = operand; --operand; cmp2( operand, prev ); ++m_eip; } template<typename argument_type> void jmp( argument_type ip ){ m_eip = ip; } template<typename argument_type> void jz( argument_type ip ){ if( m_eflags.zf()){ m_eip = ip; } else{ ++m_eip; } } template<typename argument_type> void jnz( argument_type ip ){ if( !m_eflags.zf()){ m_eip = ip; } else{ ++m_eip; } } template<typename argument_type> void push( argument_type r ){ m_esp -= sizeof( typename operand_traits_t<argument_type>::value_type ); *m_esp = r; ++m_eip; } template<typename argument_type> void pop( argument_type r ){ r = *reinterpret_cast<typename operand_traits_t<argument_type>::value_type*>(static_cast<signed_int32_t>(m_esp)); m_esp += sizeof( typename operand_traits_t<argument_type>::value_type ); ++m_eip; } template<typename argument_type> void call( argument_type target ){ push<register32_t&>( m_eip ); jmp<argument_type>( target ); } void ret(){ pop<register32_t&>( m_eip ); } }; // nop(); struct mnemonic_nop_t : public mnemonic_t { mnemonic_nop_t():mnemonic_t(nop,opcode_nop){} static void nop( vm_t& vm, opcode_t ){ vm.nop(); } }; // mov( イミディエイト以外, なんでも ); template<typename first_argument_type, typename second_argument_type> struct mnemonic_mov_t : public mnemonic_t { mnemonic_mov_t( typename operand_traits_t<first_argument_type>::output_argument_type lhs, typename operand_traits_t<second_argument_type>::input_argument_type rhs ):mnemonic_t(mov,opcode_mov,lhs,rhs){} static void mov( vm_t& vm, opcode_t, const operand_t& lhs, const operand_t& rhs ){ vm.mov<typename operand_traits_t<first_argument_type>::output_argument_type, typename operand_traits_t<second_argument_type>::input_argument_type>( lhs, rhs ); } }; // lea( レジスタ, アドレス ); template<typename first_argument_type, typename second_argument_type> struct mnemonic_lea_t : public mnemonic_t { mnemonic_lea_t( typename operand_traits_t<first_argument_type>::output_argument_type lhs, typename operand_traits_t<second_argument_type>::input_argument_type rhs ):mnemonic_t(lea,opcode_lea,lhs,rhs){} static void lea( vm_t& vm, opcode_t, const operand_t& lhs, const operand_t& rhs ){ vm.lea<typename operand_traits_t<first_argument_type>::output_argument_type, typename operand_traits_t<second_argument_type>::input_argument_type>( lhs, rhs ); } }; // inc( レジスタ ); template<typename argument_type, bool = is_register<argument_type>::value> struct mnemonic_inc_t; template<typename argument_type> struct mnemonic_inc_t<argument_type,true> : public mnemonic_t { mnemonic_inc_t( typename operand_traits_t<argument_type>::output_argument_type operand ):mnemonic_t(inc,opcode_inc,operand){} static void inc( vm_t& vm, opcode_t, const operand_t& operand ){ vm.inc<typename operand_traits_t<argument_type>::output_argument_type>( operand ); } }; // dec( レジスタ ); template<typename argument_type, bool = is_register<argument_type>::value> struct mnemonic_dec_t; template<typename argument_type> struct mnemonic_dec_t<argument_type,true> : public mnemonic_t { mnemonic_dec_t( typename operand_traits_t<argument_type>::output_argument_type operand ):mnemonic_t(dec,opcode_dec,operand){} static void dec( vm_t& vm, opcode_t, const operand_t& operand ){ vm.dec<typename operand_traits_t<argument_type>::output_argument_type>( operand ); } }; // jmp( なんでも ); template<typename argument_type> struct mnemonic_jmp_t : public mnemonic_t { mnemonic_jmp_t( typename operand_traits_t<argument_type>::input_argument_type target ):mnemonic_t(jmp,opcode_jmp,target){} static void jmp( vm_t& vm, opcode_t, const operand_t& target ){ vm.jmp<typename operand_traits_t<argument_type>::input_argument_type>( target ); } }; // jz( なんでも ); template<typename argument_type> struct mnemonic_jz_t : public mnemonic_t { mnemonic_jz_t( typename operand_traits_t<argument_type>::input_argument_type target ):mnemonic_t(jz,opcode_jz,target){} static void jz( vm_t& vm, opcode_t, const operand_t& target ){ vm.jz<typename operand_traits_t<argument_type>::input_argument_type>( target ); } }; // jnz( なんでも ); template<typename argument_type> struct mnemonic_jnz_t : public mnemonic_t { mnemonic_jnz_t( typename operand_traits_t<argument_type>::input_argument_type target ):mnemonic_t(jnz,opcode_jnz,target){} static void jnz( vm_t& vm, opcode_t, const operand_t& target ){ vm.jnz<typename operand_traits_t<argument_type>::input_argument_type>( target ); } }; // push( レジスタ ); template<typename argument_type> struct mnemonic_push_t : public mnemonic_t { mnemonic_push_t( typename operand_traits_t<argument_type>::input_argument_type target ):mnemonic_t(push,opcode_push,target){} static void push( vm_t& vm, opcode_t, const operand_t& value ){ vm.push<typename operand_traits_t<argument_type>::input_argument_type>( value ); } }; // pop( レジスタ ); template<typename argument_type> struct mnemonic_pop_t : public mnemonic_t { mnemonic_pop_t( typename operand_traits_t<argument_type>::input_argument_type target ):mnemonic_t(pop,opcode_pop,target){} static void pop( vm_t& vm, opcode_t, const operand_t& value ){ vm.pop<typename operand_traits_t<argument_type>::input_argument_type>( value ); } }; // call( レジスタかアドレス ); template<typename argument_type> struct mnemonic_call_t : public mnemonic_t { mnemonic_call_t( typename operand_traits_t<argument_type>::input_argument_type target ):mnemonic_t(call,opcode_call,target){} static void call( vm_t& vm, opcode_t, const operand_t& value ){ vm.call<typename operand_traits_t<argument_type>::input_argument_type>( value ); } }; // ret(); struct mnemonic_ret_t : public mnemonic_t { mnemonic_ret_t():mnemonic_t(ret,opcode_ret){} static void ret( vm_t& vm, opcode_t ){ vm.ret(); } }; class asm_t { std::vector<mnemonic_t> m_mnemonics; public: void nop(){ m_mnemonics.push_back( mnemonic_nop_t()); } template<typename first_argument_type, typename second_argument_type> void mov( first_argument_type lhs, second_argument_type rhs ){ m_mnemonics.push_back( mnemonic_mov_t<first_argument_type,second_argument_type>( lhs, rhs )); } template<typename first_argument_type, typename second_argument_type> void lea( first_argument_type lhs, second_argument_type rhs ){ m_mnemonics.push_back( mnemonic_lea_t<first_argument_type,second_argument_type>( lhs, rhs )); } template<typename argument_type> void inc( argument_type operand ){ m_mnemonics.push_back( mnemonic_inc_t<argument_type>( operand )); } template<typename argument_type> void dec( argument_type operand ){ m_mnemonics.push_back( mnemonic_dec_t<argument_type>( operand )); } template<typename argument_type> void jmp( argument_type operand ){ m_mnemonics.push_back( mnemonic_jmp_t<argument_type>( operand )); } template<typename argument_type> void jz( argument_type operand ){ m_mnemonics.push_back( mnemonic_jz_t<argument_type>( operand )); } template<typename argument_type> void jnz( argument_type operand ){ m_mnemonics.push_back( mnemonic_jnz_t<argument_type>( operand )); } template<typename argument_type> void push( argument_type operand ){ m_mnemonics.push_back( mnemonic_push_t<argument_type>( operand )); } template<typename argument_type> void pop( argument_type operand ){ m_mnemonics.push_back( mnemonic_pop_t<argument_type>( operand )); } template<typename argument_type> void call( argument_type operand ){ m_mnemonics.push_back( mnemonic_call_t<argument_type>( operand )); } void ret(){ m_mnemonics.push_back( mnemonic_ret_t()); } signed_int32_t label() const { return static_cast<signed_int32_t>(m_mnemonics.size()); } size_t size() const { return m_mnemonics.size(); } mnemonic_t& at( register32_t& ip ){ return m_mnemonics[ip]; } asm_t(): m_mnemonics() { } }; void vm_t::exec( asm_t& asm_ ){ while( static_cast<size_t>(static_cast<signed_int32_t>(m_eip)) < asm_.size()){ asm_.at( m_eip ).exec( *this ); } }
使用例その1
#if !defined( UNREFERENCED_PARAMETER ) #define UNREFERENCED_PARAMETER(a) (void)a #endif // UNREFERENCED_PARAMETER int main(){ vm_t vm; register_t<32> eax_ = vm.eax_(); register_t<32> ebx_ = vm.ebx_(); register_t<32> ecx_ = vm.ecx_(); register_t<32> edx_ = vm.edx_(); register_t<32> esi_ = vm.esi_(); register_t<32> edi_ = vm.edi_(); register_t<32> ebp_ = vm.ebp_(); register_t<32> esp_ = vm.esp_(); register_t<16> ax_ = vm.ax_(); register_t<16> bx_ = vm.bx_(); register_t<16> cx_ = vm.cx_(); register_t<16> dx_ = vm.dx_(); register_t<16> si_ = vm.si_(); register_t<16> di_ = vm.di_(); register_t<16> bp_ = vm.bp_(); register_t<8> al_ = vm.al_(); register_t<8> ah_ = vm.ah_(); register_t<8> bl_ = vm.bl_(); register_t<8> bh_ = vm.bh_(); register_t<8> cl_ = vm.cl_(); register_t<8> ch_ = vm.ch_(); register_t<8> dl_ = vm.dl_(); register_t<8> dh_ = vm.dh_(); UNREFERENCED_PARAMETER( eax_ ); UNREFERENCED_PARAMETER( ebx_ ); UNREFERENCED_PARAMETER( ecx_ ); UNREFERENCED_PARAMETER( edx_ ); UNREFERENCED_PARAMETER( esi_ ); UNREFERENCED_PARAMETER( edi_ ); UNREFERENCED_PARAMETER( ebp_ ); UNREFERENCED_PARAMETER( esp_ ); UNREFERENCED_PARAMETER( ax_ ); UNREFERENCED_PARAMETER( bx_ ); UNREFERENCED_PARAMETER( cx_ ); UNREFERENCED_PARAMETER( dx_ ); UNREFERENCED_PARAMETER( si_ ); UNREFERENCED_PARAMETER( di_ ); UNREFERENCED_PARAMETER( bp_ ); UNREFERENCED_PARAMETER( al_ ); UNREFERENCED_PARAMETER( ah_ ); UNREFERENCED_PARAMETER( bl_ ); UNREFERENCED_PARAMETER( bh_ ); UNREFERENCED_PARAMETER( cl_ ); UNREFERENCED_PARAMETER( ch_ ); UNREFERENCED_PARAMETER( dl_ ); UNREFERENCED_PARAMETER( dh_ ); asm_t asm_; signed_int32_t a = 0; asm_.mov( ebx_, 100 ); asm_.lea( ecx_, &a ); asm_.mov( *ecx_, ebx_ ); asm_.mov( al_, 3 ); signed_int32_t label0 = asm_.label(); asm_.dec( al_ ); asm_.jnz( label0 ); asm_.push( ebx_ ); asm_.pop( eax_ ); vm.exec( asm_ ); return 0; }
使用例その2
int main(){ vm_t vm; register_t<8> al_ = vm.al_(); asm_t asm_; asm_.mov( al_, 3 ); signed_int32_t label0 = asm_.label(); asm_.dec( al_ ); signed_int32_t label1 = 0; asm_.jz( &label1 ); asm_.jmp( label0 ); label1 = asm_.label(); vm.exec( asm_ ); return 0; }
使用例その3
int main(){ vm_t vm; register_t<32> eax_ = vm.eax_(); register_t<32> ebx_ = vm.ebx_(); asm_t asm_; signed_int32_t label2 = 0; signed_int32_t label3 = 0; asm_.mov( ebx_, 100 ); asm_.call( &label2 ); asm_.jmp( &label3 ); label2 = asm_.label(); asm_.push( ebx_ ); asm_.pop( eax_ ); asm_.ret(); label3 = asm_.label(); asm_.mov( ebx_, 10 ); vm.exec( asm_ ); return 0; }
どうでしょう
こうして実際に自分で書いてみるともうアセンブラなんて簡単じゃないですか?
試しに情報処理の試験で使う casl 2 と comet 2 を実装してみましょう