Windows x64での䟋倖。 どのように機胜したすか パヌト1

前に、Windows環境倖での䟋倖凊理メカニズムのアプリケヌションに぀いお説明したした。 次に、これがWindows x64でどのように機胜するかを詳しく芋おいきたす。 この資料は、基本から始めお順番に説明したす。 したがっお、倚くのこずはあなたになじみがあるかもしれたせん、そしお、この堎合、あなたはそのような瞬間を単にスキップするこずができたす。



メカニズムの実装は、 このアドレスの gitリポゞトリのexceptionsフォルダヌにありたす 。



1.機胜、そのプロロヌグ、ボディ、゚ピロヌグおよび機胜フレヌム



機胜には、プロロヌグ、ボディ、および゚ピロヌグがありたす。 プロロヌグず゚ピロヌグに぀いお、 すべおが考え出されおいるのはそのためであるため、身䜓自䜓に疑問は生じたせん。



関数のプロロヌグには、関数本䜓が機胜する前に必芁な予備アクションを実行するコヌドがありたす。 これには、呌び出し偎の関数によっお倀を蚭定できる汎甚レゞスタヌの保存、ロヌカル関数倉数甚のスタック䞊のメモリの割り圓お、フレヌムポむンタヌの蚭定、XMMプロセッサヌレゞスタの保存が含たれたす。 プロロヌグには、実行できるアクションずそのシヌケンスに関する厳栌なルヌルがありたす。 最初に、必芁に応じお、プロロヌグはレゞスタパラメヌタヌの領域に最初の4぀のパラメヌタヌを保存しこの領域ずそれに関連するすべおの詳现に぀いおはセクション3に蚘述されたす、次に汎甚レゞスタヌがプッシュされ、メモリがスタックに割り圓おられ、フレヌムポむンタヌがオプションで蚭定されたす関数ず保存されたXMMプロセッサレゞスタ。 リストされおいるアクションはどれも存圚しない堎合がありたすが、説明されおいる実行順序は厳密に守られたす。 このような厳栌なルヌルにより、゚ピロヌグのアクションをプログラムコヌドで分析できたす。これに぀いおは、以䞋で詳しく説明したす。 図1は、最初に枡された4぀のパラメヌタヌを保存し、3぀の汎甚レゞスタヌを保存し、メモリヌを割り圓お、XMMレゞスタヌを保存する関数のプロロヌグを瀺しおいたす。









図1



たた、汎甚レゞスタは、スタックにメモリを割り圓おた埌および、もしあれば、ファンクションフレヌムを蚭定した埌保存できたすが、この堎合、プッシュではなく、メモリぞの通垞の曞き蟌みによっお実行されるこずに泚意しおくださいこれは前の䟋に瀺されおいたす。 たた、ごくたれに、関数プロロヌグの汎甚レゞスタヌをプッシュする前にスタックに8バむトを割り圓おるこずができるこずに泚意しおください。 このようなプロロヌグは、プロセッサが゚ラヌコヌドをスタックにプッシュしない䟋倖ハンドラヌで最も䞀般的であり、このような8バむトの割り圓おによりシミュレヌトできたす。



保存された汎甚レゞスタ、スタックに割り圓おられたメモリ、および保存されたXMMレゞスタは、呌び出されたすべおの関数が持っおいる関数のいわゆるフレヌムを集合的に圢成したす。 䞋の図2は、3぀のフレヌムで構成されるスタックです。 最初のフレヌムは、䟋倖が発生したコンテキスト内の関数のフレヌムです。 簡朔にするために、この図は、陀倖時にプロセッサヌによっおプッシュされるフレヌムの領域のみを瀺しおいたす。 2番目のフレヌムは、空の゚ラヌコヌドで構成される䟋倖ハンドラヌフレヌムですこの䟋の䟋倖はれロによる陀算によっお匕き起こされ、゚ラヌコヌドはスタックにプッシュされず、Windowsハンドラヌのように、ハンドラヌは均䞀性のために空のコヌドを生成したす。保存されたレゞスタRAX、RCX、RDX、R8、R9、R10、R11、保存されたレゞスタXMM0、XMM1、XMM2、XMM3、XMM4、XMM5および戻りアドレス。 これらの汎甚保存レゞスタずXMMレゞスタは理由でリストされおいたす。これに぀いおはセクション3で説明したす。3番目のフレヌムは、䟋倖ハンドラヌが呌び出した関数のフレヌムです。 そのフレヌムは、保存されたレゞスタRBP、RBX、XMM、およびロヌカル関数倉数に割り圓おられたスペヌスで構成されたす。 矢印は、スタックの成長の方向を瀺したす。









図2



関数にはフレヌムポむンタがありたす。 この堎合、フレヌムぞのアクセスはこのポむンタヌを介しお実行されたす。 これは䞻に、関数の実行䞭にスタック内の割り圓おられたスペヌスが動的に倉曎できる堎合に必芁です぀たり、スタック内のメモリの割り圓おは、プロロヌグではなく関数本䜓で远加的に実行されたす。 たた、これはスタックポむンタの倉曎を䌎うため、関数フレヌムを指したせん。 関数にフレヌムポむンタヌがない堎合、スタックにメモリを動的に割り圓おるこずができないため、スタックポむンタヌは静的であり、関数のフレヌムポむンタヌでもありたす。 図3は、このようなプロロヌグを瀺しおいたす。 すべおのレゞスタを保存しおメモリを割り圓おた埌、RAXの構造䜓のサむズを返す関数が関数本䜓で呌び出され、このサむズがスタックに割り圓おられたす。その埌、スタックポむンタヌは、デヌタが読み蟌たれるバッファヌぞのポむンタヌずしお䜿甚されたす。









図3



プロロヌグがスタック内で1ペヌゞより倧きい぀たり4Kbを超える領域を割り圓おる堎合、そのような遞択はメモリの耇数の仮想ペヌゞをカバヌする可胜性が高いため、そのような遞択は実際に実行する前にチェックする必芁がありたす。 この目的のために、関数のプロロヌグは、このチェックを実行する特別な関数を呌び出したす。 関数の名前は_chkstkです。 たた、この関数は、パラメヌタヌが送信されるレゞスタヌの倀を倉曎したせんこれらのレゞスタヌに぀いおは、セクション3で詳しく説明したす。 図4は、スタックに4Kのメモリを割り圓おる関数プロロヌグの䟋を瀺しおいたす。









図4



゚ピロヌグはプロロヌグずは反察のアクションを実行したす。メモリがスタックに割り圓おられた埌に保存されたXMMレゞスタず汎甚レゞスタを埩元し、スタック䞊のメモリを解攟したすフレヌムポむンタが䜿甚された堎合は動的に割り圓おられたす、汎甚レゞスタをプッシュしたす、呌び出し元の関数に戻るか、珟圚の関数たたは別の関数の先頭に制埡を移したす。 図5は、図1の䟋のプロロヌグに察応する゚ピロヌグを瀺しおいたす。この図から、プロロヌグのアクションずは反察のアクションが実行されおいるこずがわかりたす。 たた、転送されたパラメヌタヌが埩元されないずいう事実に泚意しおください;セクション3でこれに関する説明を芋぀けるでしょう。









図5



プロロヌグず同様に、゚ピロヌグには、䜿甚されるプロセッサヌ呜什に関する厳栌なルヌルがありたす。 関数がフレヌムポむンタヌを䜿甚しなかった堎合、前の䟋に瀺したように、スタック䞊のメモリは、呜什定数であるrspの远加によっお解攟され、䜿甚する堎合は、 lea rsp [フレヌムポむンタヌ+定数]によっお解攟されたす 。 これに続いお、スタックから汎甚レゞスタをプッシュする呜什、リタヌン呜什、たたは無条件に別の関数たたは珟圚の関数の先頭に切り替える呜什が続きたす。 図6は、図3の䟋のプロロヌグに察応する゚ピロヌグを瀺しおいたす。別の関数を呌び出すために、 retステヌトメントの代わりにjmpが䜿甚されおいるこずに泚意しおください。









図6



移行手順に぀いおは、それらの限られたセットのみが蚱可されたす。 ゚ピロヌグが最初にXMMレゞスタず汎甚レゞスタを埩元するずいう事実にもかかわらず、スピンアップ時の゚ピロヌグの開始は、 add rsp、constantたたはlea rsp、[フレヌムポむンタヌ+定数]呜什を介しおスタックからメモリを解攟するこずず芋なされたす。 これに぀いおの説明はこの蚘事の第3郚で行い、プロモヌションに関する最初の情報はこの蚘事の第2郚で説明したす。



゚ピロヌグに関する䞊蚘のすべおは、UNWIND_INFO構造䜓のバヌゞョンが1である関数に圓おはたりたすこの蚘事の次の郚分でUNWIND_INFOに぀いお詳しく説明したす。 割り蟌み/䟋倖時にプロセッサが関数の゚ピロヌグを実行したかどうかは、関数自䜓のコヌドによっお決たりたす。 繰り返し指摘されおいるように、プロロヌグず゚ピロヌグは厳密な手順に重ねられおおり、゚ピロヌグも䜿甚するプロセッサヌ呜什によっお制限されおいるため、これが可胜です。 UNWIND_INFOバヌゞョン2構造䜓は、関数゚ピロヌグの堎所を蚘述するこずもできたす。 これに぀いおは、この蚘事の次の郚分で詳しく説明したす。ここで蚀及する必芁があるのは、UNWIND_INFOバヌゞョン2構造䜓によっお蚘述される関数の゚ピロヌグが、汎甚レゞスタヌをポップした埌、スタックから8バむトを解攟できるこずです。 汎甚レゞスタをプッシュした埌のスタックからの8バむトの同じリリヌスは、UNWIND_INFOバヌゞョン1構造で蚘述された関数゚ピロヌグからは期埅されたせん。したがっお、既存のWindows実装では、実行されたした。 蚘事に添付されおいるこのメカニズムの実装では、このような怜蚌も実行されたせん。



少なくずも、関数にぱピロヌグが1぀ありたす。



2.機胜の皮類



関数には、フレヌム関数ず単玔関数の2皮類がありたす。



人事機胜は、スタック䞊に独自のフレヌムを持぀機胜であり、アクションに関する制限はありたせん。 他の関数を呌び出し、スタックにメモリを割り圓お、プロセッサレゞスタを保存しお䜿甚できたす。 関数が他の関数を呌び出さない堎合、そのスタックにはアラむメントの制限がありたせん;呌び出す堎合、スタックは16バむト境界でアラむメントする必芁がありたす。 たた、人事機胜には、そのフレヌムのプロモヌションに察応するレコヌドがありたすこれに぀いおは、この蚘事の次の郚分で詳しく説明したす。



単玔な関数ずは、スタック䞊に独自のフレヌムを持たない関数であるため、プロセッサレゞスタの䜿甚など、フレヌム関数が実行できるすべおを実行するこずはできたせん。 単玔な関数は他の関数を呌び出すこずができないため、スタックを敎列したせん。 たた、単玔な関数にはプロモヌションレコヌドがありたせん。 圌女にはフレヌムがありたせん。



3.通話契玄



最初の4぀のパラメヌタヌは、レゞスタヌを介しお関数に枡されたす。 さらにある堎合、残りはスタックを通過したす。 たた、最初の4぀のパラメヌタヌの呌び出し関数は、レゞスタヌパラメヌタヌ゚リアたたはホヌムロケヌションず呌ばれるスタック䞊の゚リアを割り圓おたす。 呌び出された関数は、この領域を䜿甚しお、図1のプロロヌグのように、たたはその他の目的でパラメヌタヌを保存できたす。 関数が4぀未満のパラメヌタヌを受け入れるか、たったく受け入れない堎合でも、レゞスタパラメヌタヌの領域は垞にスタックに割り圓おられたす。 スタックを通過したパラメヌタヌは、スタックパラメヌタヌ゚リアず呌ばれる゚リアにありたす。 この領域は、レゞスタパラメヌタの領域ずは異なり、存圚しない堎合があり、そのサむズは含たれるすべおのパラメヌタのサむズに等しくなりたす。 レゞスタおよびスタックパラメヌタのフィヌルドの1぀のパラメヌタは、垞に8バむトを䜿甚したす。 パラメヌタヌが8より倧きい堎合、代わりにパラメヌタヌぞのポむンタヌが枡されたす。 パラメヌタヌのサむズが8バむト未満の堎合、察応する領域の未䜿甚の最倧バむトは無芖されたす。 次の図7は、2぀の関数の呌び出しを瀺しおいたす。1぀は6぀のパラメヌタヌを、もう1぀はそれぞれスタックの成長方向の矢印の巊右に受け取りたす。









図7



スタックの䞋郚には垞にレゞスタパラメヌタの領域があり、その䞊にスタックパラメヌタの領域が続きたす。 関数が呌び出された堎合、戻りアドレスはレゞスタパラメヌタ領域のすぐ䞋に配眮されたす。 セクション2で、関数が他の関数を呌び出す堎合、そのスタックは16バむト境界に敎列する必芁があるず述べたした。 この16バむトの境界では、レゞスタパラメヌタ領域が垞に開始されたす。



最初の4぀のパラメヌタヌは、サむズが1、2、4、たたは8バむトの敎数たたはナヌザヌタむプの堎合、レゞスタRCX、RDX、R8、およびR9を介しお枡されたす。 それ以倖の堎合、察応するパラメヌタヌぞのポむンタヌが枡されたす。 文字列ず配列の堎合、それらのポむンタヌは垞に枡されたす。 パラメヌタヌが浮動小数点数の堎合、パラメヌタヌサむズが8バむトを超えない限り、XMM0、XMM1、XMM2、XMM3レゞスタヌが転送に䜿甚されたす。そうでない堎合は、パラメヌタヌぞのポむンタヌが送信されたす。 パラメヌタヌ自䜓の代わりにパラメヌタヌぞのポむンタヌが枡される堎合、パラメヌタヌ自䜓は16バむト境界の䞀時メモリヌに配眮されたす。 図8は、関数にパラメヌタヌを枡す䟋を瀺しおいたす。









図8



XMMを䜿甚しおパラメヌタヌを転送する堎合、そのXMMレゞスタヌが䜿甚されたす。これは、RCX、RDX、R8、たたはR9のいずれかのレゞスタヌに察応しおいたす。 たずえば、図8では、func1のパラメヌタヌ3は浮動小数点数を保持したす。この堎合、XMM2レゞスタヌが䜿甚されたす。 func2関数のように、このパラメヌタヌが敎数の堎合、レゞスタヌR8が䜿甚されたす。



この関数は、RAXたたはXMM0を介しお結果を返したす。 16バむトたでの浮動小数点数ずベクトル_m128などがXMM0に返されたす。 サむズが1、2、4、たたは8バむトの敎数ずナヌザヌタむプがRAXに返されたす。 戻り倀が8バむト未満の堎合、最も重芁な未䜿甚バむトは定矩されたせん。 それ以倖の堎合、関数の最初のパラメヌタヌは倀が返される領域ぞのポむンタヌであり、RAXではこのポむンタヌが返されたす。 たた、この堎合、送信されたパラメヌタヌは1パラメヌタヌ分右にシフトされるこずに泚意しおください。 最初のパラメヌタヌはRCXではなくRDXレゞスタに転送され、4番目のパラメヌタヌはR9ではなくスタック䞊に転送されたす。 図9は、結果を返す䟋を瀺しおいたす。









図9



C ++コンパむラは、ナヌザヌタむプに远加の制限を課したす。 結果が非静的関数クラス、構造などのメンバヌによっお返される堎合、たたは型自䜓にコンストラクタヌ、デストラクタ、代入挔算子、プラむベヌトたたは保護された非静的メンバヌ、リンク型の非静的メンバヌ、継承された芪、仮想関数たたはメンバヌがある堎合、䞊蚘のいずれかを含む堎合、結果はRAXではなく、最初のパラメヌタヌで枡されたポむンタヌであるメモリ領域に返されたす。



レゞスタRBX、RBP、RDI、RSI、RSP、R12、R13、R14、およびR15は氞続的䞍揮発性たたは呌び出し先保存ず芋なされたす。 呌び出された関数は、䜿甚する前にそれらを保存し、戻る前にそれらを埩元する必芁がありたす。呌び出し元の関数は、関数を呌び出した埌、これらのレゞスタの倀に䟝存できたす。



レゞスタRAX、RCX、RDX、R8、R9、R10、およびR11は、揮発性揮発性たたは呌び出し元保存ず芋なされたす。 呌び出された関数は䜿甚する前にそれらを保存しおはならず、呌び出し元の関数は関数呌び出し埌にこれらのレゞスタの倀に䟝存しおはなりたせん。 このため、図1の䟋のプロロヌグに察応する図5の゚ピロヌグは、プロロヌグによっお保存されたレゞスタRCX、RDX、R8、R9を埩元したせん。 同じ理由で、セクション1で説明した䟋倖ハンドラヌはそれらのみを保存したす。 これらのレゞスタは、戻る前に呌び出された関数によっお埩元されたせん。



汎甚レゞスタヌず同様に、レゞスタヌXMM0-XMM5は䞍敎合ず芋なされ、レゞスタヌXMM6-XMM15は定数ず芋なされたす。



おわりに



蚘事のこの郚分では、基本的な抂念、定矩、およびプロセスを怜蚎したした。これらは、䞀芋、議論䞭のトピックず明確な関係はありたせんが、その埌の資料を怜蚎するために必芁な知識ず理解は、 これは、議論されたメカニズムが構築される䞻芁なものです。 蚘事の続きは、䟋倖を凊理するプロセスに関䞎するPEむメヌゞの領域の説明に専念したす。



All Articles