x64-uitzonderingsafhandeling

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_EHANDLER De 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 __try registreren een dergelijke handler.
    UNW_FLAG_UHANDLER De 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_CHAININFO Deze unwind-informatiestructuur is niet de primaire voor de procedure. In plaats daarvan is het vastgeketende info-item de inhoud van een vorige RUNTIME_FUNCTION vermelding. Zie Chained unwind-infostructuren voor meer informatie. Als deze vlag is ingesteld, moeten de UNW_FLAG_EHANDLER en UNW_FLAG_UHANDLER vlaggen 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 RSP registerwaarde en de geselecteerde FP-registerwaarde (Frame Pointer). Het geselecteerde FP-register is ingesteld op RSP + 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 RSP wordt 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_CHAININFO leeg is en een van de vlaggen UNW_FLAG_EHANDLER of UNW_FLAG_UHANDLER is 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_CHAININFO is ingesteld, eindigt de UNWIND_INFO structuur met drie UWORDs. Deze UWORD's vormen de RUNTIME_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 knooppunt

    Plaats een niet-vluchtig integerregister op de stack, waarbij RSP met 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 van UWOP_PUSH_MACHFRAME.

  • UWOP_ALLOC_LARGE (1) 2 of 3 knooppunten

    Wijs 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 knooppunt

    Wijs 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_SMALL
    136 tot 512K-8 bytes UWOP_ALLOC_LARGE, bewerkingsgegevens = 0
    512K tot 4G-8 bytes UWOP_ALLOC_LARGE, bewerkingsgegevens = 1
  • UWOP_SET_FPREG (3) 1 knooppunt

    Stel het frame pointer-register in door aan het register een offset ten opzichte van de huidige RSP toe te kennen. De offset is gelijk aan het veld Frame Register offset (geschaald) in de UNWIND_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 knooppunten

    Sla 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 knooppunten

    Sla 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 knooppunten

    Sla 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 knooppunten

    Sla 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 knooppunt

    Een 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+32 SS
    RSP+24 Oude RSP
    RSP+16 EFLAGS
    RSP+8 CS
    RSP RIP

    Een waarde van 1 geeft aan dat de hardware een frame zoals het volgende op de stack heeft geplaatst:

    Locatie Waarde
    RSP+40 SS
    RSP+32 Oude RSP
    RSP+24 EFLAGS
    RSP+16 CS
    RSP+8 RIP
    RSP Foutcode

    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_MACHFRAME registreert die simulatie, wat aangeeft dat de machine deze bewerking conceptueel heeft uitgevoerd:

    1. Haal het retouradres RIP van de top van de stack in Temp

    2. Druk op SS

    3. Oud pushen RSP

    4. Push EFLAGS

    5. Push CS

    6. Push Temp

    7. Push-foutcode (als op info gelijk is aan 1)

    De gesimuleerde UWOP_PUSH_MACHFRAME bewerking wordt RSP verminderd 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:

  1. Gebruik de huidige RIP opgeslagen in de contextrecord om te zoeken naar een RUNTIME_FUNCTION tabelvermelding die de huidige functie (of het functiegedeelte, voor gekoppelde UNWIND_INFO vermeldingen) beschrijft.

  2. Als de zoekopdracht geen functietabelvermelding vindt, wordt ervan uitgegaan dat de code deel uitmaakt van een leaf-functie en RSP de retourpointer rechtstreeks adresseert. De retourpointer op [RSP] wordt opgeslagen in de bijgewerkte context, de gesimuleerde RSP waarde wordt verhoogd met 8 en stap 1 wordt herhaald.

  3. Als de zoekopdracht een functietabelvermelding vindt, RIP kan 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 RIP zich 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 de RIP code zich binnen een epilog bevindt, wordt de codestroom vanaf RIP nu 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 RIP zich 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. De RIP bevindt zich binnen de proloog als de afstand van het begin van de functie tot de RIP kleiner 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 de RIP ten 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 c) Als de RIP zich niet in een proloog of epiloog bevindt en de functie een uitzonderingsafhandelaar heeft (waarbij UNW_FLAG_EHANDLER is 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.

  4. Als de taalspecifieke handler een afgehandelde status retourneert, wordt de uitvoering voortgezet met behulp van de oorspronkelijke contextrecord.

  5. 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.
register, offset 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))

Zie ook

x64-softwareconventies