x86エミュレータを書きながら学んだ奇妙なこと
- x86およびamd64エミュレータを書きながら学んだ、さまざまなトリビアや奇妙な点について説明している
- Time Travel Debugging(TTD)ではCPUエミュレータを使って、プロセスの実行を命令レベルで記録する
- 最初のバージョンのTTDはiDNAと呼ばれ、アセンブリコードで書かれていたため高速だったが、保守が難しかった
- 2番目のバージョンはC++で書かれ、保守性が向上した
役に立たないx86エンコーディングのトリビア
- x86のエンコーディング方式では、同じ命令を複数の方法でエンコードできる
int 3命令はCD 03またはCCとしてエンコードできる
EAXレジスタは「アキュムレータレジスタ」と呼ばれ、エンコーディング上も実際に違いがある
REXプレフィックスは64ビットコードで、より広い範囲のレジスタにアクセスできるようにする
- 命令は最大15バイトまで長くでき、これを超えると例外が発生する
- アドレスオーバーライドプレフィックスは、64ビットモードで32ビットアドレスを参照できるようにする
奇妙なフラグの特性
INC命令はADD命令と異なり、キャリーフラグを更新しない
CMPXCHG8B/CMPXCHG16B命令はゼロフラグだけを変更する
- シフトおよびローテート命令は、シフト量が1より大きい場合、オーバーフローフラグを未定義のままにする
シフト命令のさらなる驚き
shr ax, 10hはaxレジスタを16ビット分シフトして0にする
shr eax, 20hはeaxレジスタを32ビット分シフトするが、値は変化しない
- シフト量は1FHでマスクされる
セグメントオーバーライド
- セグメントは32ビットおよび64ビットコードでも依然として使われており、主にスレッドローカルストレージに使われる
- Windowsでは
FSまたはGSレジスタを使ってTEB(Thread Execution Block)を参照する
- 32ビットプロセスでは
FSを使い、64ビットプロセスではGSを使う
- 64ビットモードではセグメントレジスタの値は重要ではない
セグメントオーバーライド: さらに多くのトリビア
- 32ビットモードでは、セグメントレジスタの実際の値がセグメントディスクリプタを参照する
- 64ビットモードでは、ベースはMSRによって制御される
- WinDbgでは64ビットプロセスのセグメント値を直接読むことはできない
結論
- この記事はx86トリビアのランダムな一覧を提供している
- エミュレータを書くことは、CPUがどのように動作するかを深く理解する助けになる
- Agner Fogのウェブサイトで優れたリソースを確認できる
GN⁺のまとめ
- x86およびamd64エミュレータを書きながら学んだ、さまざまなトリビアや奇妙な点を説明している
- エミュレータを書くことは、CPUの動作方式を深く理解する助けになる
int 3命令のさまざまなエンコード方法、REXプレフィックス、セグメントオーバーライドなど、さまざまなトリビアを扱っている
- Agner Fogのウェブサイトでさらに多くのリソースを確認できる
1件のコメント
Hacker Newsのコメント