Datorsystemteknik DVGA03 Föreläsning 5 Stack och subrutiner Programmeringskonventionen Större delen av materialet framtaget av :Jan Eric Larsson, Mats Brorsson och Mirec Novak IT-inst LTH
Registren i MIPS - återblick REG NAMN $0 zero KOMMENTAR alltid noll $1 at används av assemblern $2-$3 v0-v1 returvärden från funktioner $4-$7 a0-a3 argument till subrutiner $8-$15 t0-t7 temporära register $16-$23 s0-s7 får ej förändras av subrutiner $24-$25 t8-t9 temporära register $26-$27 k0-k1 används av operativsystem/avbrott $28 gp $29 sp $30 s8/fp $31 ra global datapekare stackpekare ibland frame pointer return address: återhoppsadress
Lab 1.data var1: var2:.word 0.word 0 Minnet.set noreorder.text.globl start.ent start start: addi t0,zero,17 addi t1,zero,9 sw t0,var1 sw t1,var2.end start Statiska data var1 Program addi t0,zero,17 Höga adresser Låga adresser
Subrutinanrop - hur går det till? Huvudprogram Subrutin Subrutinen ska hoppa tillbaka till olika ställen beroende på varifrån den anropades. Återhoppsadressen måste alltså sparas! (Reg $31) MIPS-namn jal label jalr $rs jr $31 Kommentar Hoppa till label. Kom ihåg återhoppsadressen i register $31. Hoppa till adressen som finns i register $rs. Kom ihåg återhoppsadressen i register $31. Hoppa tillbaka från subrutin
Vid subrutinanrop: Programmet som anropar lägger parametrarna i register a0-a3 Hoppa till subrutinen med jal-instruktionen Subrutinen utför sin uppgift Subrutinen lägger eventuellt returvärde i register v0 (och ev. v1) Subrutinen hoppar tillbaka med jr ra
Subrutinanrop: sqr.data var:.word 0.set noreorder.text.globl start.ent start start: addi a0,zero,17 # a0=17 jal sqr # v0=17*17 nop sw v0,var.end start.globl sqr.ent sqr sqr: add t0,a0,zero mult t0,t0 mflo v0 nop nop jr ra nop.end sqr
Kan subrutiner se ut hur som helst? Vi kan ha mera komplexa situationer Subrutiner som anropar andra subrutiner kan ställa till problem. VARFÖR?? Vi tittar på ett exempel:
Subrutinen silly.globl silly.ent silly silly: addiu t0,zero,0 #Nollställ.. jal sillier #Sparar #återhoppsadress i ra! nop sw v0,16(t0) jr ra.end silly.globl sillier.ent sillier sillier: addi t1,t1,7 jr ra.end sillier OM EN RUTIN ANROPAR silly BLIR DET FEL - VARFÖR??? VAD BLIR ÅTERHOPPSADRESSEN NÄR VI HOPPAR TILLBAKA FRÅN silly?
Subrutinen silly - analys Subrutinen silly anropar en annan subrutin Genom jal-instruktionen i silly skrivs ra över Det är omöjligt att komma tillbaka till den rutin som anropade silly Register ra måste sparas undan någonstans. Men var?
Komplexa situationer som kan förekomma vid subrutinanrop Subrutiner som anropar andra subrutiner Subrutiner med fler än fyra parametrar Subrutinen kan använda register a0-a3, v0-v1, t0-t9 (enligt konventionen) men vad händer om fler register behövs? Subrutinen behöver kanske använda sig av lokala variabler eller datastrukturer
Minnesorganisation Höga adresser sp Stack Stack. Växer nedåt Ledigt minne Dyn. data Heap. Växer uppåt Statiska data Variabler etc..data Låga adresser Program Programkod.text
Stacken En subrutin lägger upp data på stacken. När subrutinen är klar tas data bort från stacken igen. För att krångla till det: Stacken i vår dator växer nedåt (varför?) Pil nederst i stacken (håller reda på stackens topp) är ett register: stackpekaren (sp).
Subrutiner och stacken Vilka element kan en subrutin vilja spara undan? - ra: registret med återhoppsadressen (om rutinen anropar något annat) - s0-s8: subrutinregistren ska sparas om de används - lokala variabler och datastrukturer - plats för argument till anropad subrutin (minst 4)
Aktiveringsblock Register som ska sparas läggs på stacken Utrymme för lokala variabler och plats för argument allokeras på stacken Totala allokerade mängden data ska vara jämnt delbart med 8 (konvention) Det allokerade utrymmet kallas AKTIVERINGSBLOCK
Aktiveringsblocket Sp Plats för argument Sp Ev. sparade argument ra andra reg. Lokala var argument
Exempel: Subrutiner i C int stacktest(int x, int y) { int a,b; int level1(int x) { int a; } a=level1(x); b=level1(y); return a+b; /* Subrutinen stacktest anropar */ level1 som i sin tur anropar level2 a=level2(x+4); return a+4; } int level2(int x) { return x+1; }
Exempel: Subrutiner i assembler BÖRJA MED level2: - Anropar inga subrutiner - Behöver inte spara register om bara t0-t9 används.globl level2.ent level2 level2: addi t0,a0,1 or v0,t0,zero jr ra.end level2 int level1(int x) { int a; a=level2(x+4); return a+4; } int level2(int x) { return x+1; } ENKELT...
Exempel: Subrutiner i assembler FORTSÄTT MED level1: PROLOG - allokera aktiveringsblocket! - level1 har en paremeter och vi kan eventuellt spara undan den. - level1 anropar en subrutin - level2. - Aktiveringsblocket består av fyra delar: (1) återhoppsadress (ra), (2) subrutinvariabler (s0, s1), (3) lokal variabel och (4) argument för subrutin som vi kallar på (level2, fyra argument). - Totalt 8*4=32 bytes. Jämnt delbart med 8 OK..globl level1.ent level1 level1: sw a0,0(sp) # Spara undan parametern subu sp,sp,32 # Plats på stacken sw ra,28(sp) # Återhoppsadressen sw s0,24(sp) # Register s0 sw s1,20(sp) # Register s1 # Lokal variabel på 16(sp) # Plats för argument a0-a3 på 0(sp)
Exempel: Subrutiner i assembler level1: SUBRUTINENS FUNKTION... addi a0,a0,4 # Räkna fram rätt argument jal level2 # Hoppa till subrutinen nop sw v0,16(sp) # Spara resultatet i lokal variabel lw s0,16(sp) # Hämta igen (lite dumt, men...) nop addi s1,s0,4 # Beräkna a+4 or v0,s1,zero # Flytta s1 till v0...
Exempel: Subrutiner i assembler level1: EPILOG (ÅTERSTÄLL REGISTER OCH ÅTERLÄMNA AKTIVERINGSBLOCK)... lw s1,20(sp) lw s0,24(sp) lw ra,28(sp) addiu sp,sp,32 lw a0,0(sp) jr ra.end level1 # Och så är det dags att återställa # Återställ s1 # Återställ s0 # Återställ ra # Återställ stacken # Återställ a0
Hur skriver man en subrutin? - Deklarera subrutinen - Allokera aktiveringsblocket - Spara register på stacken - Gör det som ska göras i rutinen - Återställ registren - Återlämna aktiveringsblock - Hoppa tillbaka