* khabao386(A)仕様 *** アプリケーション -基本: --セグメントレジスタの参照と代入は禁止(1)。 --far-callやfar-jmpも禁止(2)。 --DS==SSは仮定してよい。 --アプリ起動時は、 EAX = ECX = EDX = 0; EBX = EBP = NULL at DS/SS; ESP = ESI = EDI; を保証(NULLについては後述)。 --スタックプローブはしなくていい(3)。 --staticデータや一般の構造体をアクセスするときは、メモリアドレス値そのものを絶対に保存しないこと。データポインタをメモリに保存したい場合は、アドレスからEDIを減じた値を保存。コードポインタをメモリに保存したい場合は、アドレスからコード先頭アドレスを減じた値を保存(4)。 --スタックを利用する際はスタックタグを忘れないこと(5)。 --レジスタには、無補正データ(0xff)、データポインタ(0x00)、コードポインタ(0x01)、の3つの基本モードとと、反転データポインタ(0x40)、反転コードポインタ(0x41)、の2つの派生モードがある。 -スタックタグについて: --スタックタグは、スタックを利用するにあたって、 --スタックタグは、スタックを利用するにあたって、その用途を明記するためのものである。 -理由: --(1)セグメントレジスタがいくつになっているかは、実行環境依存であり、その情報を得て判断することは仮想化の理念に反する。実行環境に関する情報は、DLL等を通じて入手するべきである。セグメントレジスタの変更を許さない環境がありうるので、代入も禁止。 ---PUSH(DS); POP(DS); というこれだけのコードでさえも、PUSHした時点でタスクセーブが入って、異なる実行環境でタスクロードされて実行が開始されてPOPされた場合に、甚大なダメージとなり得る。つまり一瞬たりともセグメントレジスタをレジスタやメモリに入れてはいけないということである。 --(2)結局は(1)と同様の理由 --(3)win32では必須とされるスタックプローブだが、 khabao386 for win32 が実行に先立って確保したスタックを全てプローブしておくので、アプリはプローブ動作することなく、スタックを利用できる。 --(4)khabao386では、タスクセーブした後に別環境でタスクロードされる可能性を強く意識しており、その場合ロード時と同じアドレスにコードやデータ&スタックが保存される保証は全くない。したがって、コードはEDIを基点とし、その相対アドレスでアクセスすることが求められている。 ---例: EAX = [DS:EDI + 4096 + 1234]; --(4)コードは、コードの先頭アドレスを基点として、その相対アドレスで記述する。 --(4)それで、生の環境依存のポインタをメモリ内に保持すると、それはタスクロード時に補正できないため、使用が禁止されている。 --(4)しかし高速化のために、レジスタをデータポインタモードにすることができ、その場合は、 EBX = EDI + 4096 + 1234 のように設定可能で、したがって EAX = [DS:EBX]; のようなことができる。 -.objファイル編