なんとなく思いついたのでやってみた.C 言語で書いたプログラムの(ブートストラップ後の)エントリポイントは main 関数なわけだけど,アセンブラレベルでは結局のところ call main して main というラベルにとんでいるだけ.ということは,main は別にC言語の関数ではなく変数でもよい(main というラベルが作られる).これを実証するコードは以下のとおり.
こいつは HelloWorld を表示するが,main は関数でなく変数である.
#include <stdio.h> int f() { printf("HelloWorld!\n"); return 0; } int main[] = {0xB8909090, (int)f, 0x9090E0FF}; /* int main = 0xB8909090; int main2 = (int)f; int main3 = 0x9090E0FF; */ /* struct main { int m1; int m2; int m3; } main = {0xB8909090, (int)f, 0x9090E0FF}; */
main の定義をコメントアウトしている形(構造体,複数個の連続した変数)にしても動く.原理としては main というラベルに飛ばされてくるので,そこに関数本体である f へのジャンプを行うマシン語を埋め込んで f へジャンプさせる.ジャンプのコードはi386で
90 NOP 90 NOP 90 NOP B8 XXXXXXXX MOVE EAX, f FF E0 JMP EAX 90 NOP 90 NOP
とかけるので,これらのマシン後が実行されるように main 変数に値を入れている.
ついでに C++ 版も.
#include <cstdio> struct main { int ins[5]; static int f() { puts("HelloWorld!"); return 0; } } main = {0xB8909090, (int)(main::f), 0xE0FF};
- Newer: ことはじめ