C++言語を使用している際に、直接アセンブリで記述した機械語(=マシン語)を実行します。これまでWindowsバージョンを紹介しましたので、ここではUbuntuへ対応させたものを示します。
はじめに
本例はint型の変数を加算します。
C++コード
#include <iostream> #include <cstring> #include <sys/mman.h> using namespace std; int main() { unsigned char code[] = { 0x89, 0xf8, // mov eax, edi 0x01, 0xf0, // add eax, esi 0xc3 // ret }; try { // alloc. executable memory void* mem = mmap(nullptr, sizeof(code), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (mem == MAP_FAILED) throw "mmap" ; // copy machine code memcpy(mem, code, sizeof(code)); // cast as function pointer int (*func)(int, int) = (int (*)(int, int))mem; // 実行してみる int a =12, b =13; int r = func(a, b); // add cout << a << " + " << b << " =" << r << endl; // free memory munmap(mem, sizeof(code)); } catch (const char* str) { cerr << str << endl; return -1; } return 0; }
最初のcode配列は以下のアセンブリ命令を機械語に書き換えたものです。
mov eax, edi add eax, esi ret
WindowsバージョンでVirtualAllocを使っていた部分をmmapに書き換え実行可能メモリーを割り当てます。そして、そこへ受け取った機械語のコードをコピーします。
mmapの返却値はvoid*ですので、関数のシグネチャへ合わせたいためポインタへ代入します。これによってfuncを通常の関数と同じように呼び出すことができます。