prozeduren
-
hallo im rahmen meines studiums muss ich lernen mit dem MIPS-Simulator SPIM
zu programmieren, die aufgabe besteht darin eine funktion zu schreiben die 2 zahlen iterativ multipliziert und dann ein rahmenprogramm das die argumente einliest, die funktion aufruft und anschließend das ergebnis ausgibt,ich habe leider keine ahnung von :
1. framepointern - was ist ein framepointer?
2. wie funktioniert das mit kellerrahmen erstellen rücksprungaddresse retten ?
3. sowieso funktionen aufrufen?kann mir einer ein GANZ einfaches beispiel schreiben?
bisher habe ich das ganze so gelöst ( es funktioniert entspricht aber nicht den konventionen):
.data aufforderung: .asciiz "Geben Sie bitte eine zahl ein: " ausgabe : .asciiz "Das Produkt der beiden Zahlen ist: " .text main: addi $t0, $zero, 1 addi $t1, $zero, 1 loop: li $v0, 4 # code für print_string la $a0, aufforderung # lade string syscall li $v0, 5 # code für read_int syscall sw $v0, ($sp) # speichere eingabe auf stackpointer addi $sp, $sp, -4 # stack um 1 wort verschieben slt $t2, $t1, $t0 # $t2 := 1 wenn $t1 > $t0 addi $t0, $t0, 1 beq $t2, $zero, loop # springe zu loop wenn $t2 == 0 jal prod move $t0, $v0 # $v0 nach $t0 li $v0, 4 # code für print_string la $a0, ausgabe # lade string syscall li $v0, 1 # print_int move $a0, $t0 # argument übergeben syscall exit: li $v0, 10 # code für ende des programmes syscall prod: addi $sp, $sp, 4 # stack um 1 wort verschieben lw $t0, ($sp) # lade eingegebne zahl2 in $t0 addi $sp, $sp, 4 # stack um 1 wort verschieben lw $t1, ($sp) # lade eingegebne zahl1 in $t1 addi $t2, $zero, 1 # zählervariable auf 1 setzen add $v0, $zero, $t0 # $v0 := $t0 loop2: add $v0, $v0, $t0 # addiere eingegebene zahl2 zu $v0 addi $t2, $t2, 1 bne $t2, $t1, loop2 # vergleiche $t2 mit $t1 springe jr $ra # springe zu caller
-
korgan schrieb:
1. framepointern - was ist ein framepointer?
Ganz allgemein ein Zeiger, der auf einen Prozedur-Frame zeigt.
Das ist eine Datenstruktur auf dem Stack, die je nach Aufrufkonvention in unterschiedlicher Reihenfolge lokale Variablen, die Ruecksprungadresse und Parameter der Funktion enthaelt.
idR. ist es naheliegend, wie bei cdecl oder stdcall zuerst die Parameter, als naechstes die Ruecksprungadresse und zuletzt lokale Variablen abzulegen.
Der Frame- oder Base-Pointer wird dann oft zwischen dem Ablegen der Ruecksprungadresse und dem Anlegen der lokalen Variablen auf sp gesetzt, so dass er auf die Ruecksprungadresse zeigt. Relativ dazu koennen dann lokale Variablen und Parameter adressiert werden.korgan schrieb:
2. wie funktioniert das mit kellerrahmen erstellen rücksprungaddresse retten ?
Die Ruecksprungadresse wird beim MIPS AFAIR in r25(? ich glaube bei dir heisst das $ra) abgelegt. Den packst du dann also auf den Stack. Wie du Parameter auf den Stack bringst, scheinst du ja auch schon zu wissen. Platz fuer lokale Variablen schaffst du bei einem descending stack, indem du die benoetigte Zahl Bytes von sp abziehst (bei MIPS muessen die Daten AFAIR auch dword aligned sein, also immer vielfache von 4). Dann hast du von sp bis sp + x (x die Zahl, die du abgezogen hast) Platz im RAM, um allerlei lokalen Kram abzulegen.
korgan schrieb:
3. sowieso funktionen aufrufen?
Siehe zu 1 und http://de.wikipedia.org/wiki/Aufrufkonvention
Oder wo hakt es? Ich meine, du rufst in deinem Code doch schon Funktionen auf.Ein Beispiel kann ich dir leider nicht geben, da ich aktuell weder in MIPS drin bin, noch die SPIM-Syntax kenne.
-
danke soweit, das hat schonmal sehr geholfen?
aber um sicher zu gehen kannst du dir meinen quellcode mal anschaun und mir in etwa sagen was noch zu ändern ist?
-
Die Parameter scheinst du direkt nach dem Einlesen auf den Stack zu packen. Dann fehlt IMHO eigentlich nur noch, dass du die Ruecksprungadresse in $ra am Anfang deiner "prod" auf den Stack sicherst, genauso wie alle in der Prozedur verwendeten/veraenderten Register(*) und beides am Ende vor dem Ruecksprung wiederherstellst. Lokale Variablen sind da ja offensichtlich nicht noetig.
edit:
*: Hatte ich vergessen zu erwaehnen. Vor den lokalen Variablen sicherst du idR. zuerst Register, die in der proc veraendert werden.