構造体 UNWIND_CODE
アンワインド コード配列は、不揮発性レジスタと RSP に影響するプロローグ内の一連のオペレーションを記録するために使用します。各コード項目の形式は次のとおりです。
UBYTE |
プロローグ内のオフセット |
UBYTE: 4 |
アンワインド オペレーション コード |
UBYTE: 4 |
オペレーション情報 |
配列は、プロローグ内のオフセットの降順でソートされます。
プロローグ内のオフセット
このオペレーションを実行する命令の末尾にあるプロローグの先頭からのオフセットに 1 を加算したものです (つまり、次の命令の開始位置のオフセットです)。アンワインド オペレーション コード
メモ : 特定のオペレーション コードには、ローカル スタック フレーム内の値への符号なしオフセットが必要です。このオフセットは、固定スタック割り当ての開始位置 (最下位アドレス) からのオフセットです。UNWIND_INFO のフレーム レジスタ フィールドが 0 の場合、このオフセットは、RSP からのオフセットです。UNWIND_INFO のフレーム レジスタ フィールドが 0 以外の場合、このオフセットは、FP レジスタを設定したときに RSP が配置された場所からのオフセットです。これは、FP レジスタから FP レジスタ オフセット (16 * UNWIND_INFO 内のスケールされたフレーム レジスタ オフセット) を減算した値と等しくなります。FP レジスタを使用する場合、オフセットを使用するアンワインド コードは、プロローグ内で FP レジスタを設定した後にしか使用できません。UWOP_SAVE_XMM128 と UWOP_SAVE_XMM128_FAR を除くすべてのオペコードの場合、問題のすべてのスタック値は、8 バイト境界上に格納されるため、オフセットは常に 8 の倍数になります (スタック自身が常に 16 バイトでアライメントされます)。短いオフセット (512 KB より小さいオフセット) を使用するオペレーション コードの場合、このコードのノードの最後の USHORT は、8 で割ったオフセットを保持します。長いオフセット (512 KB 以上、4 GB 未満) を使用するオペレーション コードの場合、このコードの最後の 2 つの USHORT ノードはそのオフセットをリトル エンディアン形式で保持します。
オペコード UWOP_SAVE_XMM128 と UWOP_SAVE_XMM128_FAR の場合、128 ビットの XMM オペレーションはすべて 16 バイトでアライメントされたメモリ上で発生するため、オフセットは常に 16 の倍数になります。したがって、UWOP_SAVE_XMM128 にはスケール ファクター 16 が使用され、1 MB 未満のオフセットが許可されます。
アンワインド オペレーション コードは、次のいずれかになります。
UWOP_PUSH_NONVOL (0) 1 ノード
不揮発性整数レジスタをプッシュして、RSP を 8 ずつデクリメントします。オペレーション情報は、レジスタ番号です。エピローグ上の制約により、UWOP_PUSH_NONVOL アンワインド コードは、最初にプロローグ内に記述し、これに対応して最後にアンワインド コード配列内に記述する必要があります。この相対的な順序は、UWOP_PUSH_MACHFRAME を除く他のすべてのアンワインド コードに適用されます。
UWOP_ALLOC_LARGE (1) 2 または 3 ノード
スタック上に大規模な領域を割り当てます。2 つのフォームがあります。オペレーション情報が 0 と等しい場合、8 で割ったアロケーション サイズが、次のスロットに記録され、最大 512 KB - 8 までの割り当てができます。オペレーション情報が 1 と等しい場合、スケールされない割り当てサイズが次の 2 つのスロットにリトル エンディアン形式で記録され、最大 4 GB - 8 までの割り当てができます。
UWOP_ALLOC_SMALL (2) 1 ノード
スタック上に小規模な領域を割り当てます。割り当てサイズは、オペレーション情報フィールド * 8 + 8 で、8 ~ 128 バイトの割り当てができます。
スタック割り当てのアンワインド コードは、常にできる限り最短のエンコーディングを使用します。
割り当てサイズ
アンワインド コード
8 ~ 128 バイト
UWOP_ALLOC_SMALL
136 ~ 512 KB - 8 バイト
UWOP_ALLOC_LARGE、オペレーション情報 = 0
512 KB ~ 4 GB - 8 バイト
UWOP_ALLOC_LARGE、オペレーション情報 = 1
UWOP_SET_FPREG (3) 1 ノード
レジスタを現在の RSP のオフセットに設定することで、フレーム ポインター レジスタを設定します。オフセットは、UNWIND_INFO * 16 のフレーム レジスタ オフセット (スケール済み) フィールドに等しくなり、0 ~ 240 までのオフセットができます。オフセットの使用により、固定スタックの割り当ての中央を指すフレーム ポインターを設定できるようになります。これによって、より多くのアクセスで短い命令形式が使用できるようになるので、コード密度が向上します。オペレーション情報フィールドは予約して、使用できないようにする必要があります。
UWOP_SAVE_NONVOL (4) 2 ノード
PUSH の代わりに MOV を使用して、スタック上に不揮発性の整数レジスタを保存します。これは、主にシュリンクラッピングで使用します。シュリンクラッピングでは、不揮発性レジスタは既に割り当てられた位置にあるスタックに保存されます。オペレーション情報は、レジスタ番号です。上のノードで説明したとおり、8 でスケールされたスタック オフセットは、次のアンワインド オペレーション コードのスロットに記録されます。
UWOP_SAVE_NONVOL_FAR (5) 3 ノード
PUSH の代わりに MOV を使用して、長いオフセットでスタック上に不揮発性の整数レジスタを保存します。これは、主にシュリンクラッピングで使用します。シュリンクラッピングでは、不揮発性レジスタは既に割り当てられた位置にあるスタックに保存されます。オペレーション情報は、レジスタ番号です。上のノードで説明したとおり、スケールされていないスタック オフセットは、次の 2 つのアンワインド オペレーション コードのスロットに記録されます。
UWOP_SAVE_XMM128 (8) 2 ノード
不揮発性 XMM レジスタの 128 ビットすべてをスタック上に保存します。オペレーション情報は、レジスタ番号です。16 でスケールされたスタック オフセットは、次のスロットに記録されます。
UWOP_SAVE_XMM128_FAR (9) 3 ノード
不揮発性 XMM レジスタの 128 ビットすべてを長いオフセットでスタック上に保存します。オペレーション情報は、レジスタ番号です。スケールされていないスタック オフセットは、次の 2 つのスロットに記録されます。
UWOP_PUSH_MACHFRAME (10) 1 ノード
マシン フレームをプッシュします。これは、ハードウェア割り込みまたは例外の効果を記録するために使用します。2 つのフォームがあります。オペレーション情報が 0 と等しい場合、以下がスタックにプッシュされています。
RSP+32
SS
RSP+24
古い RSP
RSP+16
EFLAGS
RSP+8
CS
RSP
RIP
オペレーション情報が 1 と等しい場合、以下がプッシュされています。
RSP+40
SS
RSP+32
古い RSP
RSP+24
EFLAGS
RSP+16
CS
RSP+8
RIP
RSP
エラー コード
このアンワインド コードは、常にダミー プロローグに置かれます。ダミー プロローグは、実際には実行されませんが、割り込みルーチンの実際のエントリ ポイントの前に置かれ、マシン フレームのプッシュをシミュレートするための場所を提供するためだけに存在します。UWOP_PUSH_MACHFRAME は、そのシミュレーションを記録します。シミュレーションでは、マシン上で概念的には次の処理が実行されたことが示されます。
スタックの上部から Temp への RIP リターン アドレスのポップ
SS のプッシュ
古い RSP のプッシュ
EFLAGS のプッシュ
CS のプッシュ
Temp のプッシュ
(オペレーション情報が 1 に等しい場合) エラー コードのプッシュ
シミュレーションされた UWOP_PUSH_MACHFRAME オペレーションは、RSP を 40 (オペレーション情報が 0 と等しい場合) または 48 (オペレーション情報が 1 と等しい場合) ごとにデクリメントします。
オペレーション情報
これらの 4 ビットの意味は、オペレーション コードによって異なります。汎用 (整数) レジスタをエンコードするには、次の対応を使用します。0
RAX
1
RCX
2
RDX
3
RBX
4
RSP
5
RBP
6
RSI
7
RDI
8 ~ 15
R8 to R15