Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Een overzicht van gestructureerde uitzonderingsafhandeling en C++ uitzonderingsafhandelingsconventies en gedrag op de x64. Zie Uitzonderingsafhandeling in Microsoft C++ voor algemene informatie over het afhandelen van uitzonderingen.
Unwind-gegevens voor uitzonderingsafhandeling en debuggerondersteuning
Als niet-vluchtige registers moeten worden hersteld tijdens het afhandelen van een uitzondering, worden niet-leaffuncties geannoteerd met statische gegevens. Deze gegevens, gewoonlijk "informatie voor het afwikkelen van functies" genoemd, beschrijven hoe u de functie bij een willekeurige instructie correct kunt afwikkelen. Deze gegevens worden opgeslagen als pdata of proceduregegevens, die op hun beurt verwijzen naar xdata, de uitzonderingsverwerkingsgegevens.
De informatie over de functie-unwind bestaat uit verschillende gegevensstructuren, die hieronder worden beschreven.
Voor informatie over ondersteuning voor Intel APX (Advanced Performance Extensions), zie de Unwind V3 Preview-specificatie.
struct RUNTIME_FUNCTION
Voor de verwerking van uitzonderingen op basis van tabellen is een tabelvermelding vereist voor alle functies die stackruimte toewijzen of een andere functie aanroepen (bijvoorbeeld niet-leaf-functies). Vermeldingen in de functietabel hebben de volgende notatie:
| Grootte | Waarde |
|---|---|
| ULONG | Beginadres van functie |
| ULONG | Eindadres van functie |
| ULONG | Infoadres tot rust laten komen |
De RUNTIME_FUNCTION structuur moet DWORD uitgelijnd zijn in het geheugen. Alle adressen zijn relatief ten opzichte van de afbeelding, dat wil gezegd: ze zijn 32-bits verschuivingen van het beginadres van de afbeelding die de vermelding van de functietabel bevat. Deze vermeldingen worden gesorteerd en in de .pdata sectie van een PE32+ afbeelding geplaatst. Voor dynamisch gegenereerde functies [JIT-compilers] moet de runtime die deze functies ondersteunt ofwel RtlInstallFunctionTableCallback of RtlAddFunctionTable gebruiken om deze informatie aan het besturingssysteem te verstrekken. Als u dit niet doet, resulteert dit in onbetrouwbare verwerking en foutopsporing van processen.
struct UNWIND_INFO
De informatiestructuur voor unwind-gegevens registreert welke gevolgen een functie heeft voor de stackpointer en waar de niet-vluchtige registers op de stack worden opgeslagen:
| Grootte | Waarde |
|---|---|
| UBYTE: 3 | Versie |
| UBYTE: 5 | Vlaggen |
| UBYTE | Grootte van prolog |
| UBYTE | Aantal afwikkelcodes |
| UBYTE: 4 | Frameregister |
| UBYTE: 4 | Verschuiving frameregister (geschaald) |
| USHORT * n | Matrix codes tot rust laten komen |
| veranderlijk | Kan in de vorm zijn van (1) of (2) hieronder |
(1) Uitzonderingshandler
| Grootte | Waarde |
|---|---|
| ULONG | Adres van uitzonderingshandler |
| veranderlijk | Taalspecifieke handlergegevens (optioneel) |
(2) Gecombineerde Unwind-informatie
| Grootte | Waarde |
|---|---|
| ULONG | Beginadres van functie |
| ULONG | Eindadres van functie |
| ULONG | Infoadres tot rust laten komen |
De UNWIND_INFO structuur moet DWORD in het geheugen worden uitgelijnd. Hier ziet u wat elk veld betekent:
Versie
Versienummer voor de afwikkelgegevens, momenteel 1.
vlaggen
Er zijn momenteel drie vlaggen gedefinieerd:
Vlag Beschrijving UNW_FLAG_EHANDLERDe functie heeft een uitzonderingshandler die door het besturingssysteem wordt aangeroepen om de status van de uitzondering te onderzoeken en deze mogelijk af te handelen. Taalfuncties zoals de C-component __tryregistreren een dergelijke handler.UNW_FLAG_UHANDLERDe functie heeft een beëindigingshandler die door het besturingssysteem wordt aangeroepen bij het afwikkelen van de stack. Deze handler kan resources vrijgeven die door de functie zijn toegewezen in uitzonderingsveilige code. Taalvoorzieningen zoals lokale C++-objectdestructors en C- __finally-clausules registreren zo'n beëindigingsafhandelaar.UNW_FLAG_CHAININFODeze unwind-informatiestructuur is niet de primaire voor de procedure. In plaats daarvan is het vastgeketende info-item de inhoud van een vorige RUNTIME_FUNCTIONvermelding. Zie Chained unwind-infostructuren voor meer informatie. Als deze vlag is ingesteld, moeten deUNW_FLAG_EHANDLERenUNW_FLAG_UHANDLERvlaggen worden gewist. Bovendien moeten de velden frameregister en vaste stack-allocatievelden dezelfde waarden hebben als in de primaire unwind-informatie.Grootte van proloog
De lengte van de functieprolog in bytes.
Aantal afwikkelcodes
Het aantal sleuven in de matrix met afwikkelcodes. Sommige afwikkelcodes, zoals
UWOP_SAVE_NONVOL, vereisen meer dan één sleuf in de matrix.Frameregister
Als de waarde niet nul is, gebruikt de functie een framaanwijzer (FP), en dit veld is het nummer van het niet-vluchtige register dat als framaanwijzer wordt gebruikt, waarbij dezelfde codering wordt gebruikt als voor het veld met bewerkingsinformatie van
UNWIND_CODE-knooppunten.Frameregisterverschuiving (geschaald)
Dit veld is een geschaalde verschuiving tussen de
RSPregisterwaarde en de geselecteerde FP-registerwaarde (Frame Pointer). Het geselecteerde FP-register is ingesteld opRSP+ 16 * dit getal, wat betekent dat u offsets van 0 tot 240 kunt gebruiken. Deze offset plaatst het FP-register midden in de lokale stackruimte voor dynamische stackframes, waardoor de code compacter wordt dankzij kortere instructies. (Dat wil gezegd, meer instructies kunnen het 8-bits ondertekende offsetformulier gebruiken.)Codes array ontwinden
Een reeks items waarin het effect van de proloog op de niet-vluchtige registers en
RSPwordt uitgelegd. Zie de paragraaf over code voor unwind-bewerkingen voor de betekenis van de afzonderlijke items. Om de juiste gegevensuitlijning te behouden, bevat deze matrix altijd een even aantal vermeldingen en kan de uiteindelijke vermelding ongebruikt zijn. In dat geval is de reeks één element langer dan aangegeven door het aantal afwikkelcodes.Adres van uitzonderingshandler
Een afbeeldingsafhankelijke aanwijzer naar de taalspecifieke uitzondering of beëindigingshandler van de functie, als de vlag
UNW_FLAG_CHAININFOleeg is en een van de vlaggenUNW_FLAG_EHANDLERofUNW_FLAG_UHANDLERis ingesteld.Taalspecifieke handlergegevens
De taalspecifieke gegevens van de uitzonderingshandler van de functie. De indeling van deze gegevens is niet opgegeven en wordt volledig bepaald door de specifieke uitzonderingshandler die wordt gebruikt.
Gekoppelde Ontdraaien Informatie
Als de vlag
UNW_FLAG_CHAININFOis ingesteld, eindigt deUNWIND_INFOstructuur met drieUWORDs. DezeUWORD's vormen deRUNTIME_FUNCTION-informatie voor de werking van de gekoppelde unwind.
struct UNWIND_CODE
Gebruik de array met unwind-codes om de volgorde vast te leggen van bewerkingen in de proloog die van invloed zijn op de niet-vluchtige registers en RSP. Elk code-item heeft deze indeling:
| Grootte | Waarde |
|---|---|
| UBYTE | Verschuiving in Prolog |
| UBYTE: 4 | Terugdraaiingscode |
| UBYTE: 4 | Bewerkingsgegevens |
De array wordt gesorteerd in aflopende volgorde van verschuiving in de proloog.
Verschuiving in Prolog
Verschuiving (vanaf het begin van de proloog) van het einde van de instructie die deze bewerking uitvoert, plus 1 (dat wil zeggen de verschuiving van het begin van de volgende instructie).
Terugdraaiingscode
Voor bepaalde bewerkingscodes is een niet-ondertekende verschuiving vereist naar een waarde in het lokale stackframe. Deze offset is vanaf het begin, oftewel het laagste adres van de vaste stapelallocatie. Als het veld Frame Register in de UNWIND_INFO nul is, wordt deze offset berekend vanaf RSP. Als het Frame Register-veld niet nul is, wordt deze offset berekend vanaf de locatie waar RSP zich bevond toen het FP-register werd ingesteld. Het is gelijk aan het FP-register minus de offset van het FP-register (16 * de offset van het geschaalde frameregister in de UNWIND_INFO). Als er een FP-register wordt gebruikt, mag elke afwikkelcode die een offset heeft alleen worden gebruikt nadat het FP-register in de proloog is vastgesteld.
Voor alle opcodes behalve UWOP_SAVE_XMM128 en UWOP_SAVE_XMM128_FAR, is de offset altijd een veelvoud van 8, omdat alle relevante stackwaarden worden opgeslagen op grenzen van 8 bytes (de stack zelf is altijd 16-bytes uitgelijnd). Voor bewerkingscodes die een korte offset gebruiken (minder dan 512K), bevat de laatste USHORT binnen de knooppunten voor deze code de offset gedeeld door 8. Voor operatiecodes die een lange offset gebruiken (512K <= offset < 4 GB), bevatten de laatste twee USHORT knooppunten van deze code de offset (in little-endian-formaat).
Voor de opcodes UWOP_SAVE_XMM128 en UWOP_SAVE_XMM128_FARis de offset altijd een veelvoud van 16, omdat alle 128-bits XMM bewerkingen moeten plaatsvinden op 16 byte uitgelijnd geheugen. Daarom wordt een schaalfactor van 16 gebruikt voor UWOP_SAVE_XMM128, waardoor offsets van minder dan 1 miljoen worden toegestaan.
De afwikkelbewerkingscode is een van de volgende waarden:
UWOP_PUSH_NONVOL(0) 1 knooppuntPlaats een niet-vluchtig integerregister op de stack, waarbij
RSPmet 8 wordt verlaagd. De bewerkingsgegevens zijn het nummer van het register. Vanwege de beperkingen voor epilogs moeten unwind-codes eerst in de proloog verschijnen en overeenkomstig als laatste in de unwind-code array staan. Deze relatieve volgorde is van toepassing op alle andere afwikkelcodes, met uitzondering vanUWOP_PUSH_MACHFRAME.UWOP_ALLOC_LARGE(1) 2 of 3 knooppuntenWijs een grote ruimte toe aan de stack. Er zijn twee vormen. Als de bewerkingsgegevens gelijk zijn aan 0, wordt de grootte van de toewijzing gedeeld door 8 vastgelegd in de volgende slot, waardoor een toewijzing tot 512K minus 8 mogelijk is. Als de bewerkingsgegevens gelijk zijn aan 1, wordt de niet-geschaalde grootte van de toewijzing vastgelegd in de volgende twee sleuven in little-endian-indeling, waardoor toewijzingen tot 4 GB - 8 zijn toegestaan.
UWOP_ALLOC_SMALL(2) 1 knooppuntWijs een kleine ruimte toe aan de stapel. De grootte van de toewijzing is het veld met bewerkingsgegevens * 8 + 8, waardoor toewijzingen van 8 tot 128 bytes zijn toegestaan.
De onthefcode voor een stacktoewijzing moet altijd gebruikmaken van de kortst mogelijke codering.
Toewijzingsgrootte Code uitvouwen 8 tot 128 bytes UWOP_ALLOC_SMALL136 tot 512K-8 bytes UWOP_ALLOC_LARGE, bewerkingsgegevens = 0512K tot 4G-8 bytes UWOP_ALLOC_LARGE, bewerkingsgegevens = 1UWOP_SET_FPREG(3) 1 knooppuntStel het frame pointer-register in door aan het register een offset ten opzichte van de huidige
RSPtoe te kennen. De offset is gelijk aan het veld Frame Register offset (geschaald) in deUNWIND_INFO, vermenigvuldigd met 16, waardoor offsets van 0 tot 240 mogelijk zijn. Het gebruik van een offset maakt het mogelijk om een frame pointer tot stand te brengen die naar het midden van de vaste stacktoewijzing wijst, wat bijdraagt aan de codedichtheid doordat meer toegang mogelijk is door gebruik te maken van korte instructievormen. Het veld bewerkingsgegevens is gereserveerd en mag niet worden gebruikt.UWOP_SAVE_NONVOL(4) 2 knooppuntenSla een niet-vluchtig geheel getal register op de stack op met behulp van een MOV in plaats van een PUSH. Deze code wordt voornamelijk gebruikt voor shrink-wrapping, waarbij een niet-vluchtig register wordt opgeslagen in de stack op een positie die eerder is toegewezen. De bewerkingsgegevens zijn het nummer van het register. De met factor 8 geschaalde stackoffset wordt vastgelegd in de volgende unwind-bewerkingscodesleuf, zoals hierboven beschreven.
UWOP_SAVE_NONVOL_FAR(5) 3 knooppuntenSla een niet-vluchtig register voor gehele getallen met een lange offset op de stack op, met behulp van een MOV in plaats van een PUSH. Deze code wordt voornamelijk gebruikt voor shrink-wrapping, waarbij een niet-vluchtig register wordt opgeslagen in de stack op een positie die eerder is toegewezen. De bewerkingsgegevens zijn het nummer van het register. De niet-geschaalde stack-offset wordt vastgelegd in de volgende twee ontwikkelingscodesites, zoals beschreven in de bovenstaande opmerking.
UWOP_SAVE_XMM128(8) 2 knooppuntenSla alle 128 bits van een niet-vluchtig
XMM-register op de stack op. De bewerkingsgegevens zijn het nummer van het register. De met 16 geschaalde stack-offset wordt vastgelegd in de volgende slot.UWOP_SAVE_XMM128_FAR(9) 3 knooppuntenSla alle 128 bits van een niet-vluchtig
XMM-register met een lange offset op de stack op. De bewerkingsgegevens zijn het nummer van het register. De niet-geschaalde stack offset wordt vastgelegd in de volgende twee slots.UWOP_PUSH_MACHFRAME(10) 1 knooppuntEen machineframe duwen. Deze unwind-code legt het effect van een hardwareonderbreking of uitzondering vast. Het heeft twee vormen. Een waarde van 0, geeft aan dat hardware een frame zoals dit op de stack heeft gepusht:
Locatie Waarde RSP+32SSRSP+24Oude RSPRSP+16EFLAGSRSP+8CSRSPRIPEen waarde van 1 geeft aan dat de hardware een frame zoals het volgende op de stack heeft geplaatst:
Locatie Waarde RSP+40SSRSP+32Oude RSPRSP+24EFLAGSRSP+16CSRSP+8RIPRSPFoutcode Deze afwikkelcode wordt altijd weergegeven in een dummy prolog, dat nooit daadwerkelijk wordt uitgevoerd, maar in plaats daarvan verschijnt vóór het echte ingangspunt van een interruptroutine en bestaat alleen om een plaats te bieden om het pushen van een machineframe te simuleren.
UWOP_PUSH_MACHFRAMEregistreert die simulatie, wat aangeeft dat de machine deze bewerking conceptueel heeft uitgevoerd:Haal het retouradres
RIPvan de top van de stack in TempDruk op
SSOud pushen
RSPPush
EFLAGSPush
CSPush Temp
Push-foutcode (als op info gelijk is aan 1)
De gesimuleerde
UWOP_PUSH_MACHFRAMEbewerking wordtRSPverminderd met 40 (als op-info gelijk is aan 0) of 48 (als op info gelijk is aan 1).
Bewerkingsgegevens
De betekenis van de bits van de bewerkingsgegevens is afhankelijk van de bewerkingscode. Voor het coderen van een algemeen register (geheel getal) wordt de volgende toewijzing gebruikt:
| Bit | Registreren |
|---|---|
| 0 | RAX |
| 1 | RCX |
| 2 | RDX |
| 3 | RBX |
| 4 | RSP |
| 5 | RBP |
| 6 | RSI |
| 7 | RDI |
| 8 tot 15 |
R8 tot en met R15 |
Geketende informatiestructuren
Als de UNW_FLAG_CHAININFO-vlag is ingesteld, dan is een unwind-informatiestructuur een secundaire structuur en bevat het adresveld voor de gedeelde uitzonderingshandler/gekoppelde informatie de primaire unwind-informatie. Met deze voorbeeldcode wordt de primaire unwind-informatie opgehaald, ervan uitgaande dat unwindInfo de structuur is waarvoor de vlag UNW_FLAG_CHAININFO is ingesteld.
PRUNTIME_FUNCTION primaryUwindInfo = (PRUNTIME_FUNCTION)&(unwindInfo->UnwindCode[( unwindInfo->CountOfCodes + 1 ) & ~1]);
Gekoppelde informatie is handig in twee situaties. Ten eerste kan deze worden gebruikt voor niet-aaneengesloten codesegmenten. Door gekoppelde informatie te gebruiken, kunt u de omvang van de vereiste unwind-informatie verkleinen, omdat u de array met unwind-codes uit de primaire unwind-informatie niet hoeft te dupliceren.
U kunt ook gekoppelde informatie gebruiken om vluchtige registeropslag te groeperen. De compiler kan het opslaan van enkele vluchtige registers vertragen totdat deze zich buiten het prolog-item van de functie bevindt. U kunt ze registreren door primaire unwind-informatie te gebruiken voor het gedeelte van de functie vóór de gegroepeerde code, en vervolgens gekoppelde informatie in te stellen met een prolooggrootte die niet nul is, waarbij de unwind-codes in de gekoppelde informatie het opslaan van de niet-vluchtige registers weergeven. In dat geval zijn de unwind-codes allemaal instanties van UWOP_SAVE_NONVOL. Een groepering die niet-compatibele registers opslaat met behulp van een PUSH register of het RSP register wijzigt met behulp van een extra vaste stacktoewijzing, wordt niet ondersteund.
Een UNWIND_INFO-item waarvoor UNW_FLAG_CHAININFO is ingesteld, kan een RUNTIME_FUNCTION-vermelding bevatten waarvan voor het UNWIND_INFO-item ook UNW_FLAG_CHAININFO is ingesteld, soms multiple shrink-wrapping genoemd. Uiteindelijk komen de gekoppelde unwind-infoaanwijzers uit bij een item UNWIND_INFO waarbij UNW_FLAG_CHAININFO is gewist. Dit item is het primaire UNWIND_INFO item, dat verwijst naar het werkelijke ingangspunt van de procedure.
Procedure tot rust laten komen
De unwind-code array wordt in aflopende volgorde gesorteerd. Wanneer er een uitzondering optreedt, slaat het besturingssysteem de volledige context op in een contextrecord. De logica voor het verzenden van uitzonderingen wordt vervolgens aangeroepen, waarmee herhaaldelijk deze stappen worden uitgevoerd om een uitzonderingshandler te vinden:
Gebruik de huidige
RIPopgeslagen in de contextrecord om te zoeken naar eenRUNTIME_FUNCTIONtabelvermelding die de huidige functie (of het functiegedeelte, voor gekoppeldeUNWIND_INFOvermeldingen) beschrijft.Als de zoekopdracht geen functietabelvermelding vindt, wordt ervan uitgegaan dat de code deel uitmaakt van een leaf-functie en
RSPde retourpointer rechtstreeks adresseert. De retourpointer op [RSP] wordt opgeslagen in de bijgewerkte context, de gesimuleerdeRSPwaarde wordt verhoogd met 8 en stap 1 wordt herhaald.Als de zoekopdracht een functietabelvermelding vindt,
RIPkan deze binnen drie regio's liggen: a) in een epilog, b) in de prolog of c) in code die mogelijk wordt gedekt door een uitzonderingshandler.Case a) Als het
RIPzich binnen een epilog bevindt, verlaat het besturingselement de functie. Er kan geen uitzonderingshandler zijn gekoppeld aan deze uitzondering voor deze functie. De effecten van de epiloog moeten de context van de aanroepende functie blijven bepalen. Om te bepalen of deRIPcode zich binnen een epilog bevindt, wordt de codestroom vanafRIPnu onderzocht. Als deze codestroom overeenkomt met het volggedeelte van een legitieme epilog, bevindt deze zich in een epilog. Het resterende gedeelte van het epilog wordt gesimuleerd, waarbij de contextrecord wordt bijgewerkt wanneer elke instructie wordt verwerkt. Na deze verwerking wordt stap 1 herhaald.- Geval b) Als de
RIPzich in de proloog bevindt, is de besturing nog niet in de functie gekomen. Er kan geen uitzonderingshandler zijn gekoppeld aan deze uitzondering voor deze functie. De effecten van het prolog moeten ongedaan worden gemaakt om de context van de aanroeperfunctie te berekenen. DeRIPbevindt zich binnen de proloog als de afstand van het begin van de functie tot deRIPkleiner is dan of gelijk is aan de grootte van de proloog die is gecodeerd in de unwind-informatie. De unwinder scant vooruit door de array met unwind-codes tot aan de eerste invoer met een offset die kleiner dan of gelijk aan de offset van deRIPten opzichte van het begin van de functie is, en maakt vervolgens het effect van alle resterende elementen in de unwind-codearray ongedaan. Stap 1 wordt vervolgens herhaald.
- Geval b) Als de
Geval c) Als de
RIPzich niet in een proloog of epiloog bevindt en de functie een uitzonderingsafhandelaar heeft (waarbijUNW_FLAG_EHANDLERis ingesteld), wordt de taalspecifieke afhandelaar aangeroepen. De handler scant de gegevens en roept filterfuncties aan, indien van toepassing. De taalspecifieke handler kan retourneren dat de uitzondering is verwerkt of dat de zoekopdracht moet worden voortgezet. Het kan ook direct een ontmanteling initiëren.
Als de taalspecifieke handler een afgehandelde status retourneert, wordt de uitvoering voortgezet met behulp van de oorspronkelijke contextrecord.
Als er geen taalspecifieke handler is of de handler de status 'zoeken voortzetten' retourneert, moet het contextrecord worden teruggedraaid naar de toestand van de aanroeper. De unwinder maakt het effect van elk element in de unwind-code-array ongedaan. Stap 1 wordt vervolgens herhaald.
Wanneer keten-unwindinfo aan de orde is, worden deze basisstappen nog steeds gevolgd. Het enige verschil is dat, terwijl de unwind-codearray wordt doorlopen om de effecten van een proloog ongedaan te maken, zodra het proces het einde van de array bereikt, het een koppeling maakt met de bovenliggende unwind-informatie en de volledige unwind-codearray doorloopt die daar te vinden is. Dit koppelen gaat door totdat unwind-informatie zonder de vlag UNW_CHAINED_INFO wordt bereikt, en vervolgens voltooit het het doorlopen van de unwind-codearray.
De kleinste set van afwikkelgegevens is 8 bytes. Deze set vertegenwoordigt een functie die slechts 128 bytes aan stack of minder heeft toegewezen en mogelijk één niet-compatibel register heeft opgeslagen. Het is ook de grootte van een gekoppelde structuur voor ontwalingsinformatie voor een nul-lengte proloog zonder ontwijkcodes.
Taalspecifieke handler
De UNWIND_INFO-structuur geeft het relatieve adres van de taalspecifieke handler wanneer de vlaggen UNW_FLAG_EHANDLER of UNW_FLAG_UHANDLER zijn ingesteld. Zoals beschreven in de vorige sectie roepen het zoeken naar een uitzonderingsafhandelaar en het afwikkelen van de aanroepstack de taalspecifieke afhandelaar aan. De handler gebruikt dit prototype:
typedef EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE) (
IN PEXCEPTION_RECORD ExceptionRecord,
IN ULONG64 EstablisherFrame,
IN OUT PCONTEXT ContextRecord,
IN OUT PDISPATCHER_CONTEXT DispatcherContext
);
ExceptionRecord levert een aanwijzer naar een uitzonderingsrecord, die de standaard Win64-definitie heeft.
EstablisherFrame is het adres van de basis van de vaste stacktoewijzing voor deze functie.
ContextRecord verwijst naar de uitzonderingscontext op het moment dat de uitzondering werd opgeworpen (in het geval van de uitzonderingshandler) of naar de huidige 'afwikkel'-context (in het geval van de beëindigingshandler).
DispatcherContext verwijst naar de context van de dispatcher voor deze functie. Het heeft deze definitie:
typedef struct _DISPATCHER_CONTEXT {
ULONG64 ControlPc;
ULONG64 ImageBase;
PRUNTIME_FUNCTION FunctionEntry;
ULONG64 EstablisherFrame;
ULONG64 TargetIp;
PCONTEXT ContextRecord;
PEXCEPTION_ROUTINE LanguageHandler;
PVOID HandlerData;
} DISPATCHER_CONTEXT, *PDISPATCHER_CONTEXT;
ControlPc is de waarde van RIP binnen deze functie. Deze waarde is een uitzonderingsadres of het adres waarop het besturingselement de instellingsfunctie heeft verlaten. Het RIP wordt gebruikt om te bepalen of het besturingselement zich binnen een beveiligde constructie binnen deze functie bevindt, bijvoorbeeld een __try blok voor__try/__except of .__try/__finally
ImageBase is de imagebasis (laadadres) van de module die deze functie bevat. De 32-bits-offsets die worden gebruikt in het functie-item en de unwind-informatie moeten worden opgeteld bij de ImageBase om het uiteindelijke adres te bepalen.
FunctionEntry verstrekt een aanwijzer naar de RUNTIME_FUNCTION functie-entry die de functie en de unwind-informatie bevat, met adressen voor deze functie ten opzichte van de image base.
EstablisherFrame is het adres van de basis van de vaste stacktoewijzing voor deze functie.
TargetIp biedt een optioneel instructieadres dat het adres voor voortzetting van het unwinden opgeeft. Dit adres wordt genegeerd als EstablisherFrame niet is opgegeven.
ContextRecord verwijst naar de uitzonderingscontext, voor gebruik door de systeemuitzondering dispatch/afwikkelcode.
LanguageHandler verwijst naar de taalspecifieke taalhandlerroutine die wordt aangeroepen.
HandlerData verwijst naar de taalspecifieke handlergegevens voor deze functie.
Afwikkelhulpjes voor MASM
Als u de juiste assemblyroutines wilt schrijven, gebruikt u een set pseudobewerkingen naast de werkelijke assembly-instructies. Deze pseudo-bewerkingen genereren de juiste .pdata en .xdata. Gebruik ook een set macro's die het gebruik van deze pseudobewerkingen vereenvoudigen voor hun meest voorkomende gebruik.
Onbewerkte pseudobewerkingen
| Pseudobewerking | Beschrijving |
|---|---|
| PROC FRAME [:ehandler] | Zorgt ervoor dat MASM een functietabelvermelding in .pdata en unwind-informatie in .xdata genereert voor het unwindgedrag van de gestructureerde uitzonderingsafhandeling van een functie. Als ehandler aanwezig is, wordt deze proc ingevoerd in de .xdata als de taalspecifieke handler.Wanneer u het kenmerk FRAME gebruikt, volgt u het met een . ENDPROLOG-richtlijn. Als de functie een leaf-functie is (zoals gedefinieerd in functietypen), is het FRAME-kenmerk overbodig, net als de rest van deze pseudobewerkingen. |
| . PUSHREG-register | Genereert een UWOP_PUSH_NONVOL afwikkelcodevermelding voor het opgegeven registernummer met behulp van de huidige offset in de proloog.Gebruik het alleen met niet-vluchtige registers van gehele getallen. Voor pushes van vluchtige registers gebruikt u een . ALLOCSTACK 8, in plaats daarvan. |
| . SETFRAME-register, offset | Hiermee vult u het veld frameregister en offset in de afwikkelinformatie in met het opgegeven register en offset. De offset moet een veelvoud van 16 en kleiner dan of gelijk aan 240 zijn. Deze richtlijn genereert ook een UWOP_SET_FPREG afwikkelcodevermelding voor het opgegeven register met behulp van de huidige proloog-offset. |
| . ALLOCSTACK-grootte | Genereert een UWOP_ALLOC_SMALL of een UWOP_ALLOC_LARGE met de opgegeven grootte voor de huidige offset in de proloog.De grootteoperand moet een veelvoud van 8 zijn. |
Genereert een UWOP_SAVE_NONVOL- of UWOP_SAVE_NONVOL_FAR-unwindcode-item voor het opgegeven register en de offsetwaarde, op basis van de huidige proloogoffset. MASM kiest voor de meest efficiënte codering.offset moet positief zijn en een veelvoud van 8. offset is relatief ten opzichte van de basis van het frame van de procedure, die zich meestal in RSP bevindt, of, als u een framepointer gebruikt, ten opzichte van de ongeschaalde framepointer. |
|
| .SAVEXMM128 register, offset | Genereert een UWOP_SAVE_XMM128- of UWOP_SAVE_XMM128_FAR-unwindcode-item voor het opgegeven XMM-register en de offset, op basis van de huidige proloog-offset. MASM kiest voor de meest efficiënte codering.offset moet positief zijn en een veelvoud van 16. offset is relatief aan de basis van het frame van de procedure, die zich doorgaans in RSP bevindt, of, als u een framepointer gebruikt, aan de ongeschaalde framepointer. |
| .PUSHFRAME [code] | Genereert een UWOP_PUSH_MACHFRAME afwikkelcodevermelding. Als u de optionele code opgeeft, krijgt het code-item de modificator 1. Anders is de wijzigingsfunctie 0. |
| . ENDPROLOG | Geeft het einde van de proloogverklaringen aan. Moet voorkomen in de eerste 255 bytes van de functie. |
Hier volgt een voorbeeldfunctieprolog met het juiste gebruik van de meeste opcodes:
sample PROC FRAME
db 048h; emit a REX prefix, to enable hot-patching
push rbp
.pushreg rbp
sub rsp, 040h
.allocstack 040h
lea rbp, [rsp+020h]
.setframe rbp, 020h
movdqa [rbp], xmm7
.savexmm128 xmm7, 020h ;the offset is from the base of the frame
;not the scaled offset of the frame
mov [rbp+018h], rsi
.savereg rsi, 038h
mov [rsp+010h], rdi
.savereg rdi, 010h ; you can still use RSP as the base of the frame
; or any other register you choose
.endprolog
; you can modify the stack pointer outside of the prologue (similar to alloca)
; because we have a frame pointer.
; if we didn't have a frame pointer, this would be illegal
; if we didn't make this modification,
; there would be no need for a frame pointer
sub rsp, 060h
; we can unwind from the next AV because of the frame pointer
mov rax, 0
mov rax, [rax] ; AV!
; restore the registers that weren't saved with a push
; this isn't part of the official epilog, as described in section 2.5
movdqa xmm7, [rbp]
mov rsi, [rbp+018h]
mov rdi, [rbp-010h]
; Here's the official epilog
lea rsp, [rbp+020h] ; deallocate both fixed and dynamic portions of the frame
pop rbp
ret
sample ENDP
Zie Epilog-code in x64 prolog en epilog voor meer informatie over het epilog-voorbeeld.
MASM-macro's
Gebruik de reeks macro's die zijn gedefinieerd in ksamd64.inc om het gebruik van ruwe pseudo-bewerkingen te vereenvoudigen. Deze macro's helpen u bij het maken van typische procedureproloog en epiloog.
| Macroniveau | Beschrijving |
|---|---|
| alloc_stack(n) | Wijst een stackframe van n bytes toe (met behulp van sub rsp, n) en verzendt de juiste afwikkelinformatie (.allocstack n) |
| save_reg reg, loc | Slaat een niet-vluchtig register reg op de stack op bij RSP offset loc en genereert de juiste unwind-informatie (.savereg reg, loc) |
| push_reg reg | Plaatst een niet-vluchtig register reg op de stack, en genereert de juiste unwind-informatie (.pushreg reg) |
| rex_push_reg reg | Slaat een niet-vluchtig register op de stack op met een push van 2 bytes, en genereert de juiste unwind-informatie (.pushreg reg). Gebruik deze macro als de push de eerste instructie in de functie is om ervoor te zorgen dat de functie hot patchable is. |
| save_xmm128 reg, loc | Slaat een niet-vluchtig XMM register reg op de stack op bij een RSP offset loc, en genereert de juiste unwind-informatie (.savexmm128 reg, loc) |
| set_frame reg, offset | Stelt het frameregister reg in op de RSP + offset (met behulp van een mov of een lea) en genereert de juiste unwind-informatie (.set_frame reg, offset) |
| push_eflags | Duwt de eflags met behulp van een pushfq instructie en verzendt de juiste afwikkelinformatie (.alloc_stack 8) |
Hier volgt een voorbeeldfunctieproloog met het juiste gebruik van de macro's:
sampleFrame struct
Fill dq ?; fill to 8 mod 16
SavedRdi dq ?; Saved Register RDI
SavedRsi dq ?; Saved Register RSI
sampleFrame ends
sample2 PROC FRAME
alloc_stack(sizeof sampleFrame)
save_reg rdi, sampleFrame.SavedRdi
save_reg rsi, sampleFrame.SavedRsi
.end_prolog
; function body
mov rsi, sampleFrame.SavedRsi[rsp]
mov rdi, sampleFrame.SavedRdi[rsp]
; Here's the official epilog
add rsp, (sizeof sampleFrame)
ret
sample2 ENDP
Gegevensdefinities in C tot rust laten komen
Hier volgt een C-beschrijving van de afwikkelgegevens:
typedef enum _UNWIND_OP_CODES {
UWOP_PUSH_NONVOL = 0, /* info == register number */
UWOP_ALLOC_LARGE, /* no info, alloc size in next 2 slots */
UWOP_ALLOC_SMALL, /* info == size of allocation / 8 - 1 */
UWOP_SET_FPREG, /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */
UWOP_SAVE_NONVOL, /* info == register number, offset in next slot */
UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */
UWOP_SAVE_XMM128 = 8, /* info == XMM reg number, offset in next slot */
UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */
UWOP_PUSH_MACHFRAME /* info == 0: no error-code, 1: error-code */
} UNWIND_CODE_OPS;
typedef unsigned char UBYTE;
typedef union _UNWIND_CODE {
struct {
UBYTE CodeOffset;
UBYTE UnwindOp : 4;
UBYTE OpInfo : 4;
};
USHORT FrameOffset;
} UNWIND_CODE, *PUNWIND_CODE;
#define UNW_FLAG_EHANDLER 0x01
#define UNW_FLAG_UHANDLER 0x02
#define UNW_FLAG_CHAININFO 0x04
typedef struct _UNWIND_INFO {
UBYTE Version : 3;
UBYTE Flags : 5;
UBYTE SizeOfProlog;
UBYTE CountOfCodes;
UBYTE FrameRegister : 4;
UBYTE FrameOffset : 4;
UNWIND_CODE UnwindCode[1];
/* UNWIND_CODE MoreUnwindCode[((CountOfCodes + 1) & ~1) - 1];
* union {
* OPTIONAL ULONG ExceptionHandler;
* OPTIONAL ULONG FunctionEntry;
* };
* OPTIONAL ULONG ExceptionData[]; */
} UNWIND_INFO, *PUNWIND_INFO;
typedef struct _RUNTIME_FUNCTION {
ULONG BeginAddress;
ULONG EndAddress;
ULONG UnwindData;
} RUNTIME_FUNCTION, *PRUNTIME_FUNCTION;
#define GetUnwindCodeEntry(info, index) \
((info)->UnwindCode[index])
#define GetLanguageSpecificDataPtr(info) \
((PVOID)&GetUnwindCodeEntry((info),((info)->CountOfCodes + 1) & ~1))
#define GetExceptionHandler(base, info) \
((PEXCEPTION_HANDLER)((base) + *(PULONG)GetLanguageSpecificDataPtr(info)))
#define GetChainedFunctionEntry(base, info) \
((PRUNTIME_FUNCTION)((base) + *(PULONG)GetLanguageSpecificDataPtr(info)))
#define GetExceptionDataPtr(info) \
((PVOID)((PULONG)GetLanguageSpecificData(info) + 1))