Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Windows på ARM använder samma strukturerade mekanism för undantagshantering för asynkrona maskinvarugenererade undantag och synkrona programvarugenererade undantag. Språkspecifika undantagshanterare bygger på Windows strukturerad undantagshantering med hjälp av språkhjälpfunktioner. Det här dokumentet beskriver undantagshantering i Windows på ARM och språkhjälparna som både Microsoft ARM-monteringsverktyget och MSVC-kompilatorn genererar.
ARM-undantagshantering
Windows på ARM använder varva ned koder för att kontrollera att stacken varvar ned under strukturerad undantagshantering (SEH). Varva ned koder är en sekvens med byte som lagras i .xdata avsnittet i den körbara avbildningen. Dessa koder beskriver funktionens prolog- och epilogkod på ett abstrakt sätt. Hanteraren använder dem för att ångra funktionsprologens effekter när den varvar ned till anroparens stackram.
ARM EABI (inbäddad applikationsbinär gränssnitt) anger en modell för undantagsundanvindning som använder undanvinningskoder. Modellen räcker inte för att SEH ska kunna varva ned i Windows. Den måste hantera asynkrona fall där processorn är mitt i prologen eller epilogen för en funktion. Windows separerar också avspolningskontrollen i avspolning på funktionsnivå och språkspecifik omfångsavspolning, vilket är enhetligt i ARM EABI. Av dessa skäl anger Windows på ARM mer information för att ta bort data och procedurer.
Antaganden
Körbara avbildningar för Windows på ARM använder PE-formatet (Portable Executable). Mer information finns i PE-format. Information om undantagshantering lagras i .pdata och .xdata delarna av avbildningen.
Undantagshanteringsmekanismen gör vissa antaganden om kod som följer ABI för Windows på ARM:
När ett undantag inträffar i en funktions brödtext kan hanteraren ångra prologens åtgärder eller utföra epilogens åtgärder på ett framåtblickande sätt. Båda bör ge identiska resultat.
Prologer och epiloger tenderar att spegla varandra. Den här funktionen kan användas för att minska storleken på de metadata som behövs för att beskriva avspolning.
Funktioner tenderar att vara relativt små. Flera optimeringar förlitar sig på den här observationen för effektiv paketering av data.
Om ett villkor placeras på en epilog gäller det lika för varje instruktion i epilogen.
Om prologen sparar stackpekaren (SP) i ett annat register måste det registret förbli oförändrat i hela funktionen, så att det ursprungliga SP:et kan återställas när som helst.
Om SP inte sparas i ett annat register måste all manipulering av det ske strikt inom prologen och epilogen.
För att koppla ur en stackram krävs följande åtgärder:
Justera r13 (SP) i steg om 4 byte.
Öppna ett eller flera heltalsregister.
Öppna ett eller flera VFP-register (virtuell flyttal).
Kopiera ett godtyckligt registervärde till r13 (SP).
Läs in SP från stacken genom att använda en liten efterdekrement-åtgärd.
Parsa en av några väldefinierade ramtyper.
.pdata Arkiv
Posterna .pdata i en PE-formatbild är en ordnad matris med objekt med fast längd som beskriver varje stackmanipuleringsfunktion. Lövfunktioner (funktioner som inte anropar andra funktioner) kräver inte .pdata poster när de inte manipulerar stacken. (Det vill säga, de kräver inte någon lokal lagring och behöver inte spara eller återställa icke-flyktiga register.). Poster för dessa funktioner kan utelämnas från avsnittet .pdata för att spara utrymme. En upprullningsoperation från någon av dessa funktioner kan enkelt kopiera returadressen från Länkregistret (LR) till programräknaren (PC) för att flytta upp till anroparen.
Varje .pdata post för ARM är 8 byte lång. Det allmänna formatet för en post placerar den relativa virtuella startadressen för funktionen (RVA) i det första 32-bitarsordet, följt av ett andra ord som innehåller antingen en pekare till ett variabellängdsblock .xdata eller ett packat ord som beskriver en kanonisk funktion avvecklingssekvens, som visas i den här tabellen:
| Word-förskjutning | Bitar | Avsikt |
|---|---|---|
| 0 | 0-31 |
Function Start RVA är det 32-bitars RVA-värdet för där funktionen börjar. Om funktionen innehåller tumkod måste den låga biten av den här adressen anges. |
| 1 | 0-1 |
Flag är ett 2-bitarsfält som anger hur du tolkar de återstående 30 bitarna av det andra .pdata ordet. Om Flag är 0 bildar de återstående bitarna en RVA för undantagsinformation (med de låga två bitarna implicit 0). Om Flag är inte noll, bildar de återstående bitarna en Packad Avspolningsdatastruktur. |
| 1 | 2-31 |
Undantagsinformation RVA eller Packade avvecklingsdata. Undantagsinformation RVA är adressen till informationsstrukturen för undantag med variabel längd som lagras i avsnittet .xdata. Dessa data måste vara 4 byte justerade.Packad varva ned data är en komprimerad beskrivning av de åtgärder som krävs för att varva ned från en funktion, förutsatt att det finns ett kanoniskt formulär. I det här fallet krävs ingen .xdata-post. |
Packad Unwind-data
För funktioner vars prologer och epiloger följer det kanoniska formuläret som beskrivs nedan kan du använda packade data för att varva ned. Det eliminerar behovet av en .xdata post och minskar avsevärt det utrymme som krävs för att koppla bort data. De kanoniska prologerna och epilogerna är utformade för att uppfylla de vanliga kraven för en enkel funktion som inte kräver en undantagshanterare och utför sina konfigurations- och teardown-åtgärder i standardordning.
Den här tabellen visar formatet på en .pdata-post som har hopslagda nedrullningsdata.
| Word-förskjutning | Bitar | Avsikt |
|---|---|---|
| 0 | 0-31 |
Function Start RVA är det 32-bitars RVA-värdet för där funktionen börjar. Om funktionen innehåller tumkod måste den låga biten av den här adressen anges. |
| 1 | 0-1 |
Flag är ett 2-bitars fält som har följande betydelser:- 00 = packad varva ned data som inte används; återstående bitar pekar på .xdata posten.- 01 = packad varva ned data. - 10 = packade varva ned data där funktionen antas inte ha någon prolog. Det här är användbart för att beskriva funktionsfragment som är osammanhängande med början av funktionen. - 11 = reserverad. |
| 1 | 2-12 |
Function Length är ett 11-bitarsfält som ger längden på hela funktionen i byte dividerat med 2. Om funktionen är större än 4 000 byte måste en fullständig .xdata post användas i stället. |
| 1 | 13-14 |
Ret är ett 2-bitarsfält som anger hur funktionen returnerar:- 00 = returnera via pop {pc} (flaggbiten L måste vara inställd på 1 i det här fallet).- 01 = returnera med hjälp av en 16-bitars gren. - 10 = returnera med hjälp av en 32-bitars gren. - 11 = ingen epilog alls. Detta är användbart för att beskriva ett diskontinuerligt funktionselement som kanske bara innehåller en prolog, men vars epilog är någon annanstans. |
| 1 | 15 |
H är en 1-bitsflagga som anger om funktionen sparar heltalsparameterregistren (r0-r3) genom att spara dem i början av funktionen och avallokerar de 16 byte av stackminne innan funktionen returnerar. (0 = inte hem register, 1 = hem register.) |
| 1 | 16-18 |
Reg är ett 3-bitarsfält som anger indexet för det senast sparade icke-flyktiga registret. Om biten R är 0 sparas endast heltalsregister och antas ligga inom intervallet r4-rN, där N är lika med 4 + Reg. Om biten R är 1 sparas endast flyttalsregister och antas ligga i intervallet d8-dN, där N är lika med 8 + Reg. Den särskilda kombinationen av R = 1 och Reg = 7 anger att inga register sparas. |
| 1 | 19 |
R är en 1-bitars flagga som anger om sparade icke-flyktiga register är heltalsregister (0) eller flyttalsregister (1). Om R är inställt på 1 och fältet Reg är inställt på 7, sändes inga ickeflyktiga register. |
| 1 | 20 |
L är en 1-bitars flagga som anger om funktionen sparar/återställer LR, tillsammans med andra register som anges av fältet Reg . (0 = sparar/återställer inte, 1 = sparar/återställer.) |
| 1 | 21 |
C är en 1-bitars flagga som anger om funktionen innehåller extra instruktioner för att konfigurera en ramkedja för snabb stackgång (1) eller inte (0). Om den här biten anges läggs r11 implicit till i listan över icke-flyktiga heltalsregister som sparats. (Se begränsningarna nedan om C flaggan används.) |
| 1 | 22-31 |
Stack Adjust är ett 10-bitarsfält som anger antalet byte av stack som allokeras för den här funktionen, dividerat med 4. Endast värden mellan 0x000-0x3F3 kan dock kodas direkt. Funktioner som allokerar mer än 4044 byte i stacken måste använda en fullständig .xdata datapost. Om fältet Stack Adjust är 0x3F4 eller större har de låga 4 bitarna särskild betydelse:- Bitar 0-1 anger antalet ord för stackjustering (1-4) minus 1. - Bit 2 är inställd på 1 om prologen kombinerade denna justering i sin push-åtgärd. - Bit 3 är satt till 1 om epilogen kombinerade denna justering i sin pop-operation. |
På grund av eventuella redundanser i kodningarna ovan gäller följande begränsningar:
Om flaggan är inställd på
C1:Flaggan
Lmåste också vara inställd på 1, eftersom ramlänkning kräver både r11 och LR.r11 får inte ingå i den uppsättning register som beskrivs av
Reg. Om r4-r11 har pushats börRegalltså bara beskriva r4-r10, eftersomC-flaggan indikerar r11.
Om
Ret-fältet är inställt på 0 måsteL-flaggan vara inställd på 1.
Om du bryter mot dessa begränsningar orsakas en sekvens som inte stöds.
För diskussionen nedan härleds två pseudoflaggor från Stack Adjust:
PFeller "prologfällning" anger attStack Adjustär 0x3F4 eller större och bit 2 är satt.EFeller "epilog vikning" anger attStack Adjustär 0x3F4 eller större och bit 3 är inställd.
Prologer för kanoniska funktioner kan ha upp till 5 instruktioner (observera att 3a och 3b är ömsesidigt uteslutande):
| Instruktion | Opcode antas finnas om: | Storlek | Opcode | Varva ned koder |
|---|---|---|---|---|
| 1 |
H==1 |
16 | push {r0-r3} |
04 |
| 2 |
C==1 eller L==1 eller R==0 eller PF==1 |
16/32 | push {registers} |
80-BF/D0-DF/EC-ED |
| 3a |
C==1 och (R==1 och PF==0) |
16 | mov r11,sp |
FB |
| 3b |
C==1 och (R==0 eller PF==1) |
32 | add r11,sp,#xx |
FK |
| 4 |
R==1 och Reg != 7 |
32 | vpush {d8-dE} |
E0-E7 |
| 5 |
Stack Adjust != 0 och PF==0 |
16/32 | sub sp,sp,#xx |
00-7F/E8-EB |
Instruktion 1 finns alltid om biten H är inställd på 1.
För att konfigurera ramlänkningen finns antingen instruktion 3a eller 3b om biten C är inställd. Det är en 16-bitars mov om inga andra register än r11 och LR skickas. Annars är det en 32-bitars add.
Om en ofällbar justering anges är instruktion 5 den tydliga stackjusteringen.
Anvisningarna 2 och 4 anges baserat på om en push krävs. Den här tabellen sammanfattar vilka register som sparas baserat på fälten C, L, Roch PF . I samtliga fall N är lika Reg med + 4, E är lika Reg med + 8 och S är lika med (~Stack Adjust) & 3.
| C | L | R | PF | Heltalsregister placerade | VFP-register har push-överförts |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | r4 - r*N* |
inget |
| 0 | 0 | 0 | 1 | r*S* - r*N* |
inget |
| 0 | 0 | 1 | 0 | inget | d8 - d*E* |
| 0 | 0 | 1 | 1 | r*S* - r3 |
d8 - d*E* |
| 0 | 1 | 0 | 0 | r4 - r*N*, LR |
inget |
| 0 | 1 | 0 | 1 | r*S* - r*N*, LR |
inget |
| 0 | 1 | 1 | 0 | LR | d8 - d*E* |
| 0 | 1 | 1 | 1 | r*S* - r3, LR |
d8 - d*E* |
| 1 | 0 | 0 | 0 | (ogiltig kodning) | (ogiltig kodning) |
| 1 | 0 | 0 | 1 | (ogiltig kodning) | (ogiltig kodning) |
| 1 | 0 | 1 | 0 | (ogiltig kodning) | (ogiltig kodning) |
| 1 | 0 | 1 | 1 | (ogiltig kodning) | (ogiltig kodning) |
| 1 | 1 | 0 | 0 | r4 - r*N*, r11, LR |
inget |
| 1 | 1 | 0 | 1 | r*S* - r*N*, r11, LR |
inget |
| 1 | 1 | 1 | 0 | r11, LR | d8 - d*E* |
| 1 | 1 | 1 | 1 | r*S* - r3, r11, LR |
d8 - d*E* |
Epilogerna för kanoniska funktioner följer en liknande form, men i omvänd ordning och med några ytterligare alternativ. Epilogen kan vara upp till 5 instruktioner lång, och dess form är strikt dikterad av formen av prologen.
| Instruktion | Opcode antas finnas om: | Storlek | Opcode |
|---|---|---|---|
| 6 |
Stack Adjust!=0 och EF==0 |
16/32 | add sp,sp,#xx |
| 7 |
R==1 och Reg!=7 |
32 | vpop {d8-dE} |
| 8 |
C==1 eller (L==1 och (H==0 eller Ret !=0)) eller R==0 eller EF==1 |
16/32 | pop {registers} |
| 9a |
H==1 och (L==0 eller Ret!=0) |
16 | add sp,sp,#0x10 |
| 9b |
H==1 och L==1 och Ret==0 |
32 | ldr pc,[sp],#0x14 |
| 10a |
Ret==1 |
16 | bx reg |
| 10b |
Ret==2 |
32 | b address |
Instruktion 6 är den explicita stackjusteringen om en icke-vikande justering anges. Eftersom PF är oberoende av EFär det möjligt att ha instruktion 5 närvarande utan instruktion 6 eller vice versa.
Instruktioner 7 och 8 använder samma logik som prologen för att avgöra vilka register som återställs från stacken, men med dessa tre ändringar: först EF används i stället för PF; andra, om Ret = 0 och H = 0, ersätts LR med PC i registerlistan och epilogen slutar omedelbart; tredje, om Ret = 0 och H = 1, sedan utelämnas LR från registerlistan och poppas av instruktion 9b.
Om H anges finns antingen instruktion 9a eller 9b. Instruktion 9a används när Ret är nonzero, vilket också innebär förekomsten av antingen 10a eller 10b. Om L=1, togs LR bort som en del av instruktion 8. Instruktion 9b används när L är 1 och Ret är noll, för att indikera en tidig slutpunkt till epilogen och för att returnera och justera stacken samtidigt.
Om epilogen inte redan har avslutats, är antingen instruktion 10a eller 10b närvarande för att indikera en 16-bitars eller 32-bitars gren baserat på värdet av Ret.
.xdata Arkiv
När det kompakta avrullningsformatet inte är tillräckligt för att beskriva stackavrullningen av en funktion måste en .xdata-post med variabel längd skapas. Adressen för denna post lagras i det andra dataordet i .pdata-posten. Formatet för .xdata är en paketerad uppsättning ord med variabel längd som har fyra avsnitt:
En rubrik på 1 eller 2 ord som beskriver strukturens övergripande storlek
.xdataoch tillhandahåller nyckelfunktionsdata. Det andra ordet finns bara om fälten Antal epiloger och kodord båda är inställda på 0. Fälten är uppdelade i den här tabellen:Ord Bitar Avsikt 0 0-17 Function Lengthär ett 18-bitarsfält som anger funktionens totala längd i byte, dividerat med 2. Om en funktion är större än 512 KB, måste flera.pdata- och.xdata-poster användas för att beskriva funktionen. Mer information finns i avsnittet Stora funktioner i det här dokumentet.0 18-19 Vers är ett 2-bitarsfält som beskriver den återstående versionen .xdata. Endast version 0 är för närvarande definierad. värdena för 1–3 är reserverade.0 20 X är ett 1-bitars fält som anger förekomst (1) eller frånvaro (0) av undantagsdata. 0 21 Eär ett 1-bitarsfält som anger att information som beskriver en enda epilog är packad i rubriken (1) i stället för att kräva ytterligare omfångsord senare (0).0 22 F är ett 1-bitarsfält som anger att den här posten beskriver ett funktionsfragment (1) eller en fullständig funktion (0). Ett fragment innebär att det inte finns någon prolog och att all prologbearbetning bör ignoreras. 0 23-27 Epilogue Count är ett 5-bitars fält som har två betydelser, beroende på tillståndet för E-biten.
- OmEär 0 anger det här fältet det totala antalet epilogomfattningar som beskrivs i avsnitt 2. Om det finns fler än 31 omfång i funktionen måste det här fältet och fältet Kodord båda anges till 0 för att indikera att ett tilläggsord krävs.
– OmEär 1 anger det här fältet indexet för den första avaktiveringskoden som beskriver den enda epilogen.0 28-31 Kodord är ett 4-bitars fält som anger antalet 32-bitars ord som krävs för att innehålla alla avaktiveringskoder i avsnitt 4. Om fler än 15 ord krävs för mer än 63 avsnittsavkodningsbyte måste detta fält och fältet Antal epiloger båda sättas till 0 för att indikera att ett förlängningsord krävs. 1 0-15 Utökat antal epiloger är ett 16-bitars fält som ger mer utrymme för att koda ett ovanligt stort antal epiloger. Tilläggsordet som innehåller det här fältet finns bara om fälten Antal epiloger och kodord i det första rubrikordet båda är inställda på 0. 1 16-23 Utökade kodord är ett 8-bitars fält som ger mer utrymme för att representera ett mycket stort antal Unwind-koder. Tilläggsordet som innehåller det här fältet finns bara om fälten Antal epiloger och kodord i det första rubrikordet båda är inställda på 0. 1 24-31 Reserverad Efter undantagsdata (om biten
Ei rubriken var inställd på 0) finns en lista med information om epilogområden, som är packade en per ord och lagras i ordning efter stigande startförskjutning. Varje omfång innehåller följande fält:Bitar Avsikt 0-17 Epilog startförskjutning är ett 18-bitars fält som beskriver förskjutningen av epilogen, i byte dividerat med 2, i förhållande till början av funktionen. 18-19 Res är ett 2-bitars fält som är reserverat för framtida expansion. Värdet måste vara 0. 20-23 Condition är ett 4-bitars fält som ger villkoret under vilket epilogen körs. För ovillkorliga epiloger ska det vara inställt på 0xE, vilket indikerar "alltid". (En epilog måste vara helt villkorsstyrd eller helt ovillkorlig, och i Thumb-2-läge börjar epilogen med den första instruktionen efter IT-opcode.) 24-31 Epilogstartindex är ett 8-bitars fält som anger byteindexet för den första varva ned-koden som beskriver den här epilogen. Efter listan över epilogomfattningar kommer en byte-array som innehåller uppackningskoder, som beskrivs i detalj i avsnittet om Uppackningskoder i den här artikeln. Den här matrisen är vadderad i slutet till närmaste fullständiga ordgräns. Byte lagras i liten-endiansk ordning så att de kan hämtas direkt i liten-endian-läge.
Om X-fältet i rubriken är 1, följs avvecklingskodens byte av informationen om undantagshanteraren. Detta består av en RVA för undantagshanterare som innehåller adressen till undantagshanteraren, följt omedelbart av den (variabellängd) mängd data som krävs av undantagshanteraren.
Posten .xdata är utformad så att det går att hämta de första 8 byteen och beräkna postens fulla storlek, utan att inkludera längden på undantagsdata i variabelstorlek som följer. Det här kodfragmentet beräknar poststorleken:
ULONG ComputeXdataSize(PULONG Xdata)
{
ULONG Size;
ULONG EpilogueScopes;
ULONG UnwindWords;
if ((Xdata[0] >> 23) != 0) {
Size = 4;
EpilogueScopes = (Xdata[0] >> 23) & 0x1f;
UnwindWords = (Xdata[0] >> 28) & 0x0f;
} else {
Size = 8;
EpilogueScopes = Xdata[1] & 0xffff;
UnwindWords = (Xdata[1] >> 16) & 0xff;
}
if (!(Xdata[0] & (1 << 21))) {
Size += 4 * EpilogueScopes;
}
Size += 4 * UnwindWords;
if (Xdata[0] & (1 << 20)) {
Size += 4; // Exception handler RVA
}
return Size;
}
Även om prologen och varje epilog har ett index i varva ned-koderna delas tabellen mellan dem. Det är inte ovanligt att alla kan dela samma avspolningskoder. Vi rekommenderar att kompilatorskrivare optimerar för det här fallet, eftersom det största index som kan anges är 255 och som begränsar det totala antalet avspolningskoder som är möjliga för en viss funktion.
Varva ned koder
Matrisen med avvecklingskoder är en pool med kommandosekvenser som beskriver exakt hur man ångrar effekterna av prologen, i den ordning som operationerna måste ångras. Avkopplingskoderna är en miniinstruktionsuppsättning som kodas som en sträng med byte. När körningen har slutförts finns returadressen till den anropande funktionen i LR-registret och alla icke-flyktiga register återställs till sina värden när funktionen anropades.
Om undantag garanterades att bara inträffa i en funktionskropp, och aldrig inom en prolog eller epilog, skulle endast en varva ner-sekvens vara nödvändig. Avrullningsmodellen för Windows kräver dock en möjlighet att avrulla från en delvis utförd prolog eller epilog. För att tillgodose detta krav har unwind-koderna noggrant utformats för att säkerställa en entydig en-till-en-mappning till varje relevant opcode i prologen och epilogen. Detta har flera konsekvenser:
Det är möjligt att beräkna längden på prologen och epilogen genom att räkna antalet unwind-koder. Detta är möjligt även med Thumb-2-instruktioner med variabel längd eftersom det finns distinkta mappningar för 16-bitars och 32-bitars operationskoder.
Genom att räkna antalet instruktioner efter början av ett epilogomfång går det att hoppa över motsvarande antal unwind-koder och verkställa resten av sekvensen för att slutföra den delvis genomförda avvecklingsprocess som epilogen genomförde.
Genom att räkna antalet instruktioner före prologens slut går det att hoppa över motsvarande antal unwind-koder och exekvera resten av sekvensen för att endast ångra de delar av prologen som redan har körts.
I följande tabell visas mappningen från varva ned koder till opcodes. De vanligaste koderna är bara en byte, medan mindre vanliga koder kräver två, tre eller till och med fyra byte. Varje kod lagras från mest betydande byte till minst betydande byte. Kodstrukturen för avveckling skiljer sig från den kodning som beskrivs i ARM EABI, eftersom dessa avvecklingskoder är utformade för att ha en en-till-en-mappning till opkoderna i prologen och epilogen, för att möjliggöra avveckling av delvis utförda prologer och epiloger.
| Byte 1 | Byte 2 | Byte 3 | Byte 4 | Opsize | Förklaring |
|---|---|---|---|---|---|
| 00-7F | 16 | add sp,sp,#Xdär X är (kod & 0x7F) * 4 |
|||
| 80-BF | 00-FF | 32 | pop {r0-r12, lr}där LR tas bort från stacken om code & 0x2000 och r0-r12 tas bort från stacken om motsvarande bit anges i code & 0x1FFF |
||
| C0-CF | 16 | mov sp,rXdär X är kod &0x0F |
|||
| D0-D7 | 16 | pop {r4-rX,lr}där X är (Kod & 0x03) + 4 och LR tas bort om Kod & 0x04 |
|||
| D8-DF | 32 | pop {r4-rX,lr}där X är (kod & 0x03) + 8 och LR visas om kod & 0x04 |
|||
| E0-E7 | 32 | vpop {d8-dX}där X är (kod & 0x07) + 8 |
|||
| E8-EB | 00-FF | 32 | addw sp,sp,#Xdär X är (kod & 0x03FF) * 4 |
||
| EC-ED | 00-FF | 16 | pop {r0-r7,lr}där LR poppas om Kod & 0x0100 och r0-r7 poppas om motsvarande bit anges i Kod &0x00FF |
||
| EE | 00-0F | 16 | Microsoft-specifik | ||
| EE | 10-FF | 16 | Tillgängligt | ||
| EF | 00-0F | 32 | ldr lr,[sp],#Xdär X är (kod &0x000F) * 4 |
||
| EF | 10-FF | 32 | Tillgängligt | ||
| F0-F4 | - | Tillgängligt | |||
| F5 | 00-FF | 32 | vpop {dS-dE}där S är (kod & 0x00F0) >> 4 och E är kod &0x000F |
||
| F6 | 00-FF | 32 | vpop {dS-dE}where S is ((Code & 0x00F0) |
||
| F7 | 00-FF | 00-FF | 16 | add sp,sp,#Xdär X är (kod & 0x00FFFF) * 4 |
|
| F8 | 00-FF | 00-FF | 00-FF | 16 | add sp,sp,#Xdär X är (kod & 0x00FFFFFF) * 4 |
| F9 | 00-FF | 00-FF | 32 | add sp,sp,#Xdär X är (kod & 0x00FFFF) * 4 |
|
| FA | 00-FF | 00-FF | 00-FF | 32 | add sp,sp,#Xdär X är (kod & 0x00FFFFFF) * 4 |
| FB | 16 | nop (16-bitars) | |||
| FK | 32 | nop (32-bitars) | |||
| FD | 16 | slut + 16-bitars nop i slutdel | |||
| FE | 32 | end + 32-bit nop i den epilog | |||
| FF | - | ände |
Detta visar intervallet med hexadecimala värden för varje byte i en kodkod för varva ned, tillsammans med opcode-storleken Opsize och motsvarande ursprungliga instruktionstolkning. Tomma celler anger kortare avspolningskoder. I instruktioner som har stora värden som täcker flera byte lagras de viktigaste bitarna först. Fältet Opsize visar den implicita opcode-storlek som är associerad med varje Thumb-2-åtgärd. De uppenbara duplicerade posterna i tabellen med olika kodningar används för att skilja mellan olika opcode-storlekar.
Avkopplingskoderna är utformade så att den första byte av koden anger både den totala storleken i byte av koden och storleken på motsvarande opcode i instruktionsströmmen. Om du vill beräkna storleken på prologen eller epilogen går du igenom avrullningskoderna från början av sekvensen till slutet och använder en uppslagstabell eller liknande metod för att avgöra hur länge motsvarande opcode är.
Upprullningskoder 0xFD och 0xFE motsvarar den vanliga slutkoden 0xFF, men tar hänsyn till en extra nop opcode i epilogfallet, oavsett om det är 16-bitars eller 32-bitars. För prologer är koderna 0xFD, 0xFE och 0xFF exakt likvärdiga. Detta står för de vanliga epilogsluten bx lr eller b <tailcall-target>, som inte har någon motsvarande prologinstruktion. Detta ökar risken för att avspolningssekvenser kan delas mellan prologen och epilogerna.
I många fall bör det vara möjligt att använda samma uppsättning avspolningskoder för prologen och alla epiloger. Men för att hantera avspolning av delvis utförda prologer och epiloger kan du behöva ha flera avspolningskodsekvenser som varierar i ordning eller beteende. Det är därför varje epilog har ett eget index i återställningsmatrisen för att visa var programmet ska börja köras.
Avspolning av partiella prologer och epiloger
Det vanligaste avspolningsfallet är när undantaget inträffar i funktionens brödtext, bort från prologen och alla epiloger. I det här fallet kör avrullaren koderna i avrullningsmatrisen med början vid index 0 och fortsätter tills en slutopkod har upptäckts.
När ett undantag inträffar medan en prolog eller epilog körs är stackramen bara delvis konstruerad, och avvecklingsmekanismen måste fastställa exakt vad som har gjorts för att korrekt kunna ångra det.
Tänk till exempel på den här prolog- och epilogsekvensen:
0000: push {r0-r3} ; 0x04
0002: push {r4-r9, lr} ; 0xdd
0006: mov r7, sp ; 0xc7
...
0140: mov sp, r7 ; 0xc7
0142: pop {r4-r9, lr} ; 0xdd
0146: add sp, sp, #16 ; 0x04
0148: bx lr
Bredvid varje opcode finns lämplig avspolningskod för att beskriva den här åtgärden. Sekvensen med avspolningskoder för prologen är en speglingsbild av avspolningskoderna för epilogen, utan att räkna den slutliga instruktionen. Detta fall är vanligt och orsaken till att avrullningskoderna för prologen alltid antas lagras i omvänd ordning från prologens exekveringsordning. Detta ger oss en gemensam uppsättning avspolningskoder:
0xc7, 0xdd, 0x04, 0xfd
Den 0xFD koden är en särskild kod för slutet av sekvensen, vilket innebär att epilogen är en 16-bitars instruktion längre än prologen. Detta möjliggör en större delning av unwind-koder.
I det här exemplet, om ett undantag inträffar när funktionstexten mellan prologen och epilogen körs, börjar avvecklingen med epilogfallet vid förskjutning 0 i epilogkoden. Detta motsvarar förskjutning 0x140 i exemplet. Avrullaren kör hela avrullningssekvensen eftersom ingen rensning har gjorts tidigare. Om undantaget i stället inträffar en instruktion efter början av epilogkoden kan avvecklaren framgångsrikt avveckla genom att hoppa över den första avvecklingskoden. Givet en direkt korrelation mellan opcodes och avvecklingskoder, om avveckling från instruktion n i epilogen, bör avvecklaren hoppa över de första n avvecklingskoderna.
Liknande logik fungerar omvänt för prologen. Om du varvar ned från förskjutningen 0 i prologen behöver ingenting köras. Om avveckling från en instruktion pågår, bör avvecklingssekvensen starta en avvecklingskod från slutet eftersom prologens avvecklingskoder lagras i omvänd ordning. I allmänhet, om avveckling sker från instruktion n i prologen, bör avvecklingen börja vid n avvecklingskoder från slutet av listan med koder.
Prolog- och epilogkoder matchar inte alltid exakt. I så fall kan avspolningskodmatrisen behöva innehålla flera sekvenser med koder. Använd den här logiken för att fastställa förskjutningen som behövs för att börja bearbeta koder.
Om du varvar ned från funktionens brödtext börjar du köra varva ned koder vid index 0 och fortsätta tills ett slut opcode har nåtts.
Om du rullar tillbaka från en epilog, använd det epilogspecifika startindex som tillhandahålls av epilogens omfattning. Beräkna hur många byte datorn är från början av epilogen. Hoppa vidare genom varva ned koderna tills alla redan utförda instruktioner har redovisats. Kör varva ned-sekvensen från och med den tidpunkten.
Om du varvar ned från prologen börjar du från index 0 i avspolningskoderna. Beräkna längden på prologkoden från sekvensen och beräkna sedan hur många byte PC:n är från slutet av prologen. Fortsätt framåt genom avrullningskoderna tills alla oexekverade instruktioner har redovisats. Kör varva ned-sekvensen från och med den tidpunkten.
Avkopplingskoderna för prologen måste alltid vara de första i arrayen. de är också de koder som används för att avveckla i det allmänna fallet av avveckling inifrån huvudfunktionen. Alla epilogspecifika kodsekvenser bör följa omedelbart efter prologkodsekvensen.
Funktionsfragment
För kodoptimering kan det vara användbart att dela upp en funktion i sammanhängande delar. När detta är klart kräver varje funktionsfragment sin egen separata .pdata–och möjligen .xdata–post.
Förutsatt att funktionsprologen är i början av funktionen och inte kan delas, finns det fyra funktionsfragmentfall:
Endast prolog; alla epiloger i andra fragment.
Prolog och en eller flera epiloger; fler epiloger i andra fragment.
Inga prologer eller epiloger; prolog och en eller flera epiloger i andra fragment.
Endast epiloger; prolog och eventuellt fler epiloger i andra fragment.
I det första fallet måste endast prologen beskrivas. Detta kan göras i kompakt .pdata form genom att beskriva prologen normalt och ange värdet Ret 3 för att indikera ingen epilog. I den fullständiga .xdata formen kan du göra detta genom att ange prologens avrullningskoder vid index 0 som vanligt och ange ett epilogantal på 0.
Det andra fallet är precis som en normal funktion. Om det bara finns en epilog i fragmentet, och den är i slutet av fragmentet, kan en kompakt .pdata postering användas. Annars måste en fullständig .xdata datapost användas. Tänk på att de förskjutningar som anges för epilogstarten är relativa till början av fragmentet, inte den ursprungliga starten av funktionen.
Det tredje och fjärde fallet är varianter av de första respektive andra fallen, förutom att de inte innehåller någon prolog. I dessa situationer antas det att det finns kod före epilogen börjar och det anses vara en del av funktionskroppen, som normalt skulle avvecklas genom att upphäva prologens effekter. Dessa fall måste därför kodas med en pseudo-prolog, som beskriver hur du varvar ner inifrån kroppen, men som behandlas som 0-längd när du avgör om du ska utföra en partiell varva ner i början av fragmentet. Alternativt kan den här pseudoprologen beskrivas med samma återställningskoder som epilogen eftersom de förmodligen utför motsvarande operationer.
I det tredje och fjärde fallet anges förekomsten av en pseudoprolog antingen genom att fältet Flag i den kompakta .pdata posten anges till 2, eller genom att F-flaggan i .xdata rubriken anges till 1. I båda fallen ignoreras kontrollen av en partiell prolog avveckling, och alla icke-epilog avvecklingar anses vara fullständiga.
Stora funktioner
Fragment kan användas för att beskriva funktioner som är större än den gräns på 512 KB som har införts av bitfälten .xdata i rubriken. Om du vill beskriva en större funktion kan du dela upp den i fragment som är mindre än 512 KB. Varje fragment bör justeras så att det inte delar upp en epilog i flera delar.
Endast det första fragmentet av funktionen innehåller en prolog. Alla andra fragment markeras som utan prolog. Beroende på antalet epiloger kan varje fragment innehålla noll eller fler epiloger. Tänk på att varje epilogområde i ett fragment anger dess startförskjutning i förhållande till början av fragmentet och inte till början av funktionen.
Om ett fragment inte har någon prolog och ingen epilog, kräver det fortfarande sin egen .pdata- och möjligen .xdata- post för att beskriva hur man varvar ner inifrån funktionens brödtext.
krymppaketering
Ett mer komplext specialfall med funktionsfragment kallas krympslagning. Det är en teknik för att skjuta upp registersparningar från början av funktionen till senare i funktionen. Den optimerar för enkla fall som inte kräver registerbesparing. Det här fallet har två delar: det finns en yttre region som allokerar stackutrymmet men sparar en minimal uppsättning register och en inre region som sparar och återställer andra register.
ShrinkWrappedFunction
push {r4, lr} ; A: save minimal non-volatiles
sub sp, sp, #0x100 ; A: allocate all stack space up front
... ; A:
add r0, sp, #0xE4 ; A: prepare to do the inner save
stm r0, {r5-r11} ; A: save remaining non-volatiles
... ; B:
add r0, sp, #0xE4 ; B: prepare to do the inner restore
ldm r0, {r5-r11} ; B: restore remaining non-volatiles
... ; C:
pop {r4, pc} ; C:
Förpackade funktioner förväntas vanligtvis förallokera utrymme för de extra registersparningarna i den vanliga prologen och sedan spara registren med hjälp av str eller stm i stället för push. Den här åtgärden håller kvar all stackpekarmanipulering i funktionens ursprungliga prolog.
Den krympade exempelfunktionen måste vara uppdelad i tre regioner, som är markerade som A, Boch C i kommentarerna. Den första A regionen omfattar starten av funktionen till slutet av de ytterligare icke-flyktiga sparandena. En post av typen .pdata eller .xdata måste konstrueras för att beskriva att detta fragment har en prolog och inga epiloger.
Mellanregionen B får sin egen .pdata eller .xdata post som beskriver ett fragment som inte har någon prolog och ingen epilog. Avkopplingskoderna för den här regionen måste dock fortfarande finnas eftersom det anses vara en funktionskropp. Koderna måste beskriva en sammansatt prolog som representerar både de ursprungliga register som sparats i regionprologen A och de extra register som sparades innan de gick in i regionen B, som om de skapades av en åtgärdssekvens.
Det går inte att betrakta registret som sparas för region B som en "inre prolog" eftersom den sammansatta prolog som beskrivs för region B måste beskriva både regionens prolog A och de ytterligare register som sparats. Om fragmentet B hade en prolog skulle frikodningskoderna också innebära storleken på prologen, och det finns inget sätt att beskriva en sammansatt prolog på ett sätt som mappar en-till-en med operationskoderna som bara sparar de ytterligare registren.
Extra registersparningar måste betraktas som en del av regionen A, eftersom den sammansatta prologen inte beskriver stackens tillstånd korrekt förrän de är klara.
Den sista C-regionen får sin egen .pdata- eller .xdata-post, som beskriver ett fragment utan prolog men med en epilog.
En alternativ metod kan också fungera om stackmanipulering som gjorts innan man går in i regionen B kan reduceras till en instruktion.
ShrinkWrappedFunction
push {r4, lr} ; A: save minimal non-volatile registers
sub sp, sp, #0xE0 ; A: allocate minimal stack space up front
... ; A:
push {r4-r9} ; A: save remaining non-volatiles
... ; B:
pop {r4-r9} ; B: restore remaining non-volatiles
... ; C:
pop {r4, pc} ; C: restore non-volatile registers
Den viktigaste insikten är att på varje instruktionsgräns är stacken helt konsekvent med avspolningskoderna för regionen. Om en avveckling inträffar innan den inre push i det här exemplet anses del av regionen A. Endast prologen för regionen A avvecklas. Om avvecklingen sker efter den interna pushen, anses den vara en del av regionen B som inte har någon prolog. Den har dock avvecklingskoder som beskriver både den interna push-operationen och den ursprungliga prologen från regionen A. Liknande logik gäller för den inre popen.
Kodningsoptimeringar
De omfattande avkopplingskoderna och möjligheten att använda kompakta och expanderade former av data ger många möjligheter att optimera kodningen för att ytterligare minska utrymmet. Med aggressiv användning av dessa tekniker kan nettoomkostnaderna för att beskriva funktioner och fragment med hjälp av varva ned-koder minimeras.
Den viktigaste optimeringsidén: Blanda inte ihop prolog- och epiloggränser för att varva ned med logiska prolog- och epiloggränser ur ett kompilatorperspektiv. Gränserna för avveckling kan krympas och göras stramare för att förbättra effektiviteten. En prolog kan till exempel innehålla kod efter stackkonfigurationen för verifieringskontroller. Men när all stackmanipulering är klar behöver du inte koda ytterligare åtgärder, och allt utöver det kan tas bort från avrullningsprologen.
Samma regel gäller för funktionslängden. Om det finns data (till exempel en literalpool) som följer en epilog i en funktion bör de inte inkluderas som en del av funktionslängden. Genom att krympa funktionen till bara den kod som ingår i funktionen är chansen mycket större att epilogen är precis i slutet och att en kompakt .pdata rekord kan användas.
När stackpekaren har sparats i ett annat register i en prolog behöver du vanligtvis inte registrera ytterligare opcodes. För att varva ned funktionen är det första som görs att återställa SP från det sparade registret. Ytterligare åtgärder påverkar inte avvecklingen.
Epilog med en instruktion behöver inte kodas överhuvudtaget, varken som områden eller som avvecklingskoder. Om en varva ned sker innan instruktionen körs är det säkert att anta att den kommer inifrån funktionens brödtext. Det räcker att bara köra prologens avrullningskoder. När upprullningen sker efter att den enskilda instruktionen har körts, sker den per definition i en annan region.
Epiloger med flera instruktioner behöver inte koda den första instruktionen i epilogen, av samma anledning som föregående punkt: om avlindningen sker innan instruktionen körs, räcker det med en fullständig prolog-upprullning. Om avvecklingen sker efter den instruktionen måste endast de senare operationerna beaktas.
Varva ned återanvändning av kod bör vara aggressivt. Indexet för varje epilogomfång pekar på en godtycklig startpunkt i fältet med avspolningskoder. Den behöver inte peka mot början av en tidigare sekvens; det kan peka i mitten. Den bästa metoden är att generera avspolningskodsekvensen. Sök sedan efter en exakt bytematchning i den redan kodade poolen med sekvenser. Använd valfri perfekt matchning som utgångspunkt för återanvändning.
Efter att epiloger med en instruktion ignoreras, om det inte finns några återstående epiloger, överväg att använda en kompakt .pdata form; sannolikheten för detta ökar betydligt utan en epilog.
Exempel
I de här exemplen är bildbasen på 0x00400000.
Exempel 1: Bladfunktion, Inga lokala variabler
Prologue:
004535F8: B430 push {r4-r5}
Epilogue:
00453656: BC30 pop {r4-r5}
00453658: 4770 bx lr
.pdata (fast, 2 ord):
Word 0
-
Function Start RVA= 0x000535F8 (= 0x004535F8-0x00400000)
-
Word 1
Flag= 1, som anger kanoniska prolog- och epilogformatFunction Length= 0x31 (= 0x62/2)Ret= 1, som anger en 16-bitars grenreturH= 0, vilket indikerar att parametrarna inte var hembyggdaR= 0 ochReg= 1, vilket indikerar push/pop av r4-r5L= 0, vilket indikerar att ingen LR sparas/återställsC= 0, vilket indikerar ingen ramlänkningStack Adjust= 0, vilket indikerar ingen stackjustering
Exempel 2: Kapslad funktion med lokal allokering
Prologue:
004533AC: B5F0 push {r4-r7, lr}
004533AE: B083 sub sp, sp, #0xC
Epilogue:
00453412: B003 add sp, sp, #0xC
00453414: BDF0 pop {r4-r7, pc}
.pdata (fast, 2 ord):
Word 0
-
Function Start RVA= 0x000533AC (= 0x004533AC -0x00400000)
-
Word 1
Flag= 1, som anger kanoniska prolog- och epilogformatFunction Length= 0x35 (= 0x6A/2)Ret= 0, som anger en pop {pc} returH= 0, vilket indikerar att parametrarna inte var hembyggdaR= 0 ochReg= 3, vilket indikerar push/pop av r4-r7L= 1, vilket indikerar att LR sparades/återställdesC= 0, vilket indikerar ingen ramlänkningStack Adjust= 3 (= 0x0C/4)
Exempel 3: Kapslad variadisk funktion
Prologue:
00453988: B40F push {r0-r3}
0045398A: B570 push {r4-r6, lr}
Epilogue:
004539D4: E8BD 4070 pop {r4-r6}
004539D8: F85D FB14 ldr pc, [sp], #0x14
.pdata (fast, 2 ord):
Word 0
-
Function Start RVA= 0x00053988 (= 0x00453988-0x00400000)
-
Word 1
Flag= 1, som anger kanoniska prolog- och epilogformatFunction Length= 0x2A (= 0x54/2)Ret= 0, som anger en retur i stil med {pc} (i det här fallet enldr pc,[sp],#0x14retur)H= 1, som anger att parametrarna var nollställdaR= 0 ochReg= 2, vilket indikerar push/pop av r4-r6L= 1, vilket indikerar att LR sparades/återställdesC= 0, vilket indikerar ingen ramlänkningStack Adjust= 0, vilket indikerar ingen stackjustering
Exempel 4: Funktion med flera epiloger
Prologue:
004592F4: E92D 47F0 stmdb sp!, {r4-r10, lr}
004592F8: B086 sub sp, sp, #0x18
Epilogues:
00459316: B006 add sp, sp, #0x18
00459318: E8BD 87F0 ldm sp!, {r4-r10, pc}
...
0045943E: B006 add sp, sp, #0x18
00459440: E8BD 87F0 ldm sp!, {r4-r10, pc}
...
004595D4: B006 add sp, sp, #0x18
004595D6: E8BD 87F0 ldm sp!, {r4-r10, pc}
...
00459606: B006 add sp, sp, #0x18
00459608: E8BD 87F0 ldm sp!, {r4-r10, pc}
...
00459636: F028 FF0F bl KeBugCheckEx ; end of function
.pdata (fast, 2 ord):
Word 0
-
Function Start RVA= 0x000592F4 (= 0x004592F4-0x00400000)
-
Word 1
Flag= 0, vilket indikerar att.xdataposten är närvarande (nödvändig för flera epiloger).xdataadress – 0x00400000
.xdata (variabel, 6 ord):
Word 0
Function Length= 0x0001A3 (= 0x000346/2)Vers= 0, som anger den första versionen av.xdataX= 0, som anger att det inte finns några undantagsdataE= 0, vilket anger en lista över epilogavsnittF= 0, som anger en fullständig funktionsbeskrivning, inklusive prologEpilogue Count= 0x04, vilket anger de fyra totala epilogområdenaCode Words= 0x01, som anger ett 32-bitars ord med avspolningskoder
Ord 1–4, som beskriver 4 epilogomfattningar på 4 platser. Varje omfång har en gemensam uppsättning avspolningskoder som delas med prologen vid offset-0x00 och är ovillkorligt och anger villkor 0x0E (alltid).
Varva ned koder med början i Word 5: (delas mellan prolog/epilog)
Varva ned kod 0 = 0x06: sp += (6 << 2)
Avvecklingskod 1 = 0xDE: pop {r4-r10, lr}
Varva ned kod 2 = 0xFF: slut
Exempel 5: Funktion med dynamisk stack och inre epilog
Prologue:
00485A20: B40F push {r0-r3}
00485A22: E92D 41F0 stmdb sp!, {r4-r8, lr}
00485A26: 466E mov r6, sp
00485A28: 0934 lsrs r4, r6, #4
00485A2A: 0124 lsls r4, r4, #4
00485A2C: 46A5 mov sp, r4
00485A2E: F2AD 2D90 subw sp, sp, #0x290
Epilogue:
00485BAC: 46B5 mov sp, r6
00485BAE: E8BD 41F0 ldm sp!, {r4-r8, lr}
00485BB2: B004 add sp, sp, #0x10
00485BB4: 4770 bx lr
...
00485E2A: F7FF BE7D b #0x485B28 ; end of function
.pdata (fast, 2 ord):
Word 0
-
Function Start RVA= 0x00085A20 (= 0x00485A20-0x00400000)
-
Word 1
Flag= 0, vilket indikerar att.xdataposten finns (behövs för flera epiloger).xdataadress – 0x00400000
.xdata (variabel, 3 ord):
Word 0
Function Length= 0x0001A3 (= 0x000346/2)Vers= 0, som anger den första versionen av.xdataX= 0, som anger att det inte finns några undantagsdataE= 0, vilket anger en lista över epilogavsnittF= 0, som anger en fullständig funktionsbeskrivning, inklusive prologEpilogue Count= 0x001, vilket anger det 1 totala epilogomfångetCode Words= 0x01, som anger ett 32-bitars ord med avspolningskoder
Word 1: Epilogomfång vid offset 0xC6 (= 0x18C/2), start av avvecklingskodindex vid 0x00 och med villkoret 0x0E (alltid)
Varva ned koder med början i Word 2: (delas mellan prolog/epilog)
Varva ned kod 0 = 0xC6: sp = r6
Varva ned kod 1 = 0xDC: pop {r4-r8, lr}
Varva ned kod 2 = 0x04: sp += (4 << 2)
Varva ned kod 3 = 0xFD: end, räknas som 16-bitars instruktion för epilog
Exempel 6: Funktion med undantagshanterare
Prologue:
00488C1C: 0059 A7ED dc.w 0x0059A7ED
00488C20: 005A 8ED0 dc.w 0x005A8ED0
FunctionStart:
00488C24: B590 push {r4, r7, lr}
00488C26: B085 sub sp, sp, #0x14
00488C28: 466F mov r7, sp
Epilogue:
00488C6C: 46BD mov sp, r7
00488C6E: B005 add sp, sp, #0x14
00488C70: BD90 pop {r4, r7, pc}
.pdata (fast, 2 ord):
Word 0
-
Function Start RVA= 0x00088C24 (= 0x00488C24-0x00400000)
-
Word 1
Flag= 0, vilket indikerar att.xdataposten finns (behövs för flera epiloger).xdataadress – 0x00400000
.xdata (variabel, 5 ord):
Word 0
Function Length=0x000027 (= 0x00004E/2)Vers= 0, som anger den första versionen av.xdataX= 1, som anger undantagsdata som finnsE= 1, vilket indikerar en enda epilogF= 0, som anger en fullständig funktionsbeskrivning, inklusive prologEpilogue Count= 0x00, vilket indikerar att epilogens avrullningskoder börjar vid förskjutning 0x00Code Words= 0x02, som anger två 32-bitars ord med avspolningskoder
Varva ned koder med början i Word 1:
Avsnurra kod 0 = 0xC7: sp = r7
Varva ned kod 1 = 0x05: sp += (5 << 2)
Unwind-kod 2 = 0xED/0x90: pop {r4, r7, lr}
Avslutningskod 4 = 0xFF: slut
Word 3 anger en undantagshanterare = 0x0019A7ED (= 0x0059A7ED – 0x00400000)
Ord 4 och framåt är infogade undantagsdata
Exempel 7: Funclet
Function:
00488C72: B500 push {lr}
00488C74: B081 sub sp, sp, #4
00488C76: 3F20 subs r7, #0x20
00488C78: F117 0308 adds r3, r7, #8
00488C7C: 1D3A adds r2, r7, #4
00488C7E: 1C39 adds r1, r7, #0
00488C80: F7FF FFAC bl target
00488C84: B001 add sp, sp, #4
00488C86: BD00 pop {pc}
.pdata (fast, 2 ord):
Word 0
-
Function Start RVA= 0x00088C72 (= 0x00488C72-0x00400000)
-
Word 1
Flag= 1, som anger kanoniska prolog- och epilogformatFunction Length= 0x0B (= 0x16/2)Ret= 0, som anger en pop {pc} returH= 0, vilket indikerar att parametrarna inte var hembyggdaR= 0 ochReg= 7, vilket indikerar att inga register har sparats/återställtsL= 1, vilket indikerar att LR sparades/återställdesC= 0, vilket indikerar ingen ramlänkningStack Adjust= 1, vilket anger en justering av stacken med 1 × 4 byte
Se även
Översikt över ARM ABI-konventioner
vanliga problem med migrering av Visual C++ ARM