REXAMDは、64 ビット x86 拡張機能を開発したときに、プレフィックス用の新しいオペコードやその他の新しい命令を追加する余地が必要でした。一部のオペコードの意味を新しい命令に変更しました。
命令のいくつかは、既存の命令の単なる短縮形であるか、そうでなければ必要ではありませんでした。PUSHA被害者の一人でした。なぜ禁止されたのかは明らかPUSHAではありませんが、新しい命令オペコードと重複しているようには見えません。おそらく、それらは将来の使用のために予約されているPUSHAオペコードPOPAです。これらは完全に冗長であり、これ以上高速ではなく、重要なほどコード内で頻繁に発生しないためです。
の順序は、PUSHA命令エンコードの順序でした: eax, ecx, edx, ebx, esp, ebp, . 重複してプッシュしたことに注意してください! プッシュされたデータを見つけるために知っておく必要があります!esiediespesp
コードを 64 ビットから変換している場合、PUSHAコードはとにかく良くないため、更新して新しいレジスタをプッシュする必要がありr8ますr15。また、はるかに大きな SSE 状態を保存して復元する必要がありxmm8ますxmm15。あなたがそれらを破壊しようとしていると仮定します。
割り込みハンドラ コードが C コードに転送される単なるスタブである場合、すべてのレジスタを保存する必要はありません。rbxC コンパイラは、rbp、rsi、rdi、およびr12thruを保持するコードを生成すると想定できますr15。rax、、、およびthrurcxを保存して復元するだけで済みます。(注: Linux またはその他の System V ABI プラットフォームでは、コンパイラは, , -を保持します。rdxr8r11rbxrbpr12r15rsirdi
セグメント レジスタはロング モードでは値を保持しません (中断されたスレッドが 32 ビット互換モードで実行されている場合は、セグメント レジスタを保存する必要があります。ughoavgfhw に感謝します)。実際には、ロング モードでのセグメンテーションの大部分を取り除きましたがFS、オペレーティング システムがスレッド ローカル データのベース アドレスとして使用するために予約されています。レジスタ値自体は重要ではなく、 と のベースはMSRFSとGSによって設定され0xC0000100ます0xC0000101。C コードによってアクセスされるスレッド ローカル データは、任意のスレッドの TLS を使用している可能性があることをFS覚えておいてください。C ランタイム ライブラリは一部の機能に TLS を使用するため、注意してください (例: 通常、strtok は TLS を使用します)。
FSまたはGS(ユーザー モードであっても) に値をロードすると、FSBASEまたはGSBASEMSR が上書きされます。一部のオペレーティング システムは「プロセッサ ローカル」ストレージとして使用するため (各 CPU の構造体へのポインターを保持する方法が必要です)、ユーザー モードでのGS読み込みによって破壊されない場所にそれを保持する必要があります。GSこの問題を解決するために、GSBASEレジスター用に 2 つの MSR が予約されています。1 つはアクティブで、もう 1 つは非表示です。カーネル モードでは、カーネルGSBASEは通常のGSBASEMSR に保持され、ユーザー モード ベースは別の (非表示) にあります。GSBASEMSR。カーネル モードからユーザー モード コンテキストにコンテキストを切り替えるとき、およびユーザー モード コンテキストを保存してカーネル モードに入るときに、コンテキスト切り替えコードは SWAPGS 命令を実行する必要があります。これにより、可視 MSR と非表示GSBASEMSR の値が交換されます。カーネルGSBASEはユーザー モードの他の MSR に安全に隠されているため、ユーザー モード コードはGSBASE、値を にロードしてカーネルを上書きすることはできませんGS。CPU がカーネル モードに再び入ると、コンテキスト保存コードが実行SWAPGSされ、カーネルのGSBASE.