2016-10-14 3 views
0

Ich arbeite derzeit an einem kleinen Programm auf einem Ci20-Maschine, die den Benutzer für einen ganzzahligen Wert auffordern, dann drucken Sie den Wert auf dem Bildschirm.Aufforderung zur Benutzereingabe in Assembly ci20 seg Fehler

Mein aktueller Code

.data 

prompt: 
.asciiz "Please enter an integer: " 
message: 
.asciiz "\nValue entered: " 

.text 
.global main 

main: 
    addiu $sp, $sp, -4 # push stack 
    sw $ra, ($sp)  # save return address 

    addi $v0, $0, 4 
    la $a0, prompt 
    syscall   # printing prompt 

    addi $v0, $0, 5 
    syscall   # get user input 

    move $t0, $v0  # save input in $t0 
    move $a0, $v0 
    addi $v0, $0, 1 # Not sure if this is right to print message 
    la $a0, message # Not sure if this is right to print message 
    syscall 

    lw $ra, ($sp)  # restoring $sp 
    addiu $sp, $sp, +4 # release the stack space used for $sp 

Wenn ich versuche, das Programm, das ich einen Segmentation Fehler bekommen laufen und nicht sicher, warum. Jede Hilfe oder Anregung würde sehr geschätzt werden.

Antwort

3

edit: aus irgendeinem Grund habe ich diesen Code vollständig ignoriert auf ci20 Maschine getestet.

Also ist das Linux? Dann können Sie keine MARS-Syscalls verwenden, stattdessen müssen Sie Linux-Syscalls finden. Es ist dann wahrscheinlich Segfauling auf der ersten syscall Anweisung, da die Argumente für Linux ungültig sind.


Um "prompt" Sie als v0 = 4, a0 = prompt ... Set verwenden syscall mit Argumenten angezeigt werden "Meldung" angezeigt werden Sie setzen Argumente für syscall als v0 = 1, a0 = message.

Wenn dies in MARS, dann v0 = 1 "print integer", so sollte a0 ganze Zahl sein, nicht von "Nachricht" string adressieren. .. Sie möchten wahrscheinlich syscall zweimal aufrufen, mit v0 = 4 und v0 = 1 (Argument a0 ist "Nachricht" und Benutzer Integer für bestimmten Aufruf).

Wie auch immer, nichts davon sollte segfault. Der segfault tritt wahrscheinlich am Ende auf, wo Ihr Code mit addiu $sp, $sp, +4 endet, nicht zum ra zurückkehrt, oder Aufruf von syscall "exit" -Funktion (von der Speicherung von ra am Anfang Ihres Codes sieht es so aus, als ob Sie eher als Ausgang zurückkehren möchten , aber es liegt an dir). Daher wird die Ausführung über einige zufällige Anweisungen fortgesetzt (nicht initialisierter Speicherinhalt).

Auf jeden Fall 2, sollten Sie herausfinden, wie Last dieser Code in Debugger und Schritt über sie befehl, dann werden Sie in der Lage sein zu sagen, wo genau es Segfaults, und was war der Inhalt der Register vor Speicherzugriffsfehlern Anweisung . Wenn Ihr Code segfold ist und Sie nicht einmal wissen, wo, zeigt es mangelnde Anstrengungen auf Ihrer Seite.

(Disclaimer: Ich habe nie MIPS Montage, so dass ich meistens bin zu raten, wie es funktioniert und etwas übersehen haben kann)


bearbeiten über syscall, vielleicht wird dieser Hinweis helfen?

syscall ist keine magische Anweisung, die all diese raffinierten Sachen auf der CPU macht. Es springt nur zu einer Handler-Routine.

Dieser Handler-Code wird vom Betriebssystem eingerichtet. Die meisten MIPS-Assembly-Auflistungen auf SO sind auf MARS oder SPIM ausgerichtet, die einen völlig anderen Handler als Linux haben.

Also sollten Sie Linux ABI für MIPS studieren, und wie syscall dort verwendet wird. Und dann finden Sie Linux Systemaufrufe Tabelle, Sie werden wahrscheinlich Tonnen von x86-Dokumenten finden, so dass Sie das in v0/a0/... ABI konvertieren müssen.

Sie können immer noch MARS-Beispiele verfolgen, aber jede OS-Interaktion muss angepasst werden, und erwarten Sie nicht, für alles eine Alternative zu finden.Zum Beispiel ist die Ausgabe der Nummer in Linux nicht verfügbar. Sie müssen den Zahlenwert selbst in eine ASCII-Zeichenkette umwandeln (für einstellige Zahlen ist das Hinzufügen von '0' ausreichend, für Zahlen über 9 müssen Sie eine Ziffer für jede Potenz von 10 berechnen und in ein ASCII-Zeichen umwandeln und in einen Puffer speichern) und dann die Zeichenfolge mit sys_write/etc ausgeben. (Oder verlinke mit irgendeiner libc und rufe sprintf - ähnliche Funktion von C-Bibliothek).

+0

Ja, Linux Lese/Schreib-Systemaufrufe sollten Dateideskriptoren (z. B. 0 für Stdin, 1 für Stdout), Pufferadressen und Byte-Zählungen. –

+0

Vielen Dank für die Antwort @ Ped7g. Ich führe das Programm auf einem ci20-Rechner aus, der ein Linux-basierter Rechner ist, auf dem gdb läuft. Wenn ich es durch den gdb-Debugger laufe, teilt es keinen Fehler, daher meine Verwirrung darüber, warum es seg-Fehler gibt. – TurtleMan

+0

@TurtleMan Nun, dann sind die Argumente nicht toxisch genug, um segfault, aber Sie verwenden MARS Argumente für syscall statt Linux. Durch einen kurzen Blick auf das Web denke ich, dass dies etwas zur Konsole ausgeben kann: 'v0' =' 4' (sys_write), 'a0' =' 1' (Dateideskriptor stdout), 'a1' =' prompt' (Adresse von .ascii string), 'a2' =' 25' (Länge von .ascii string) 'syscall'. Versuchen Sie dies zuerst im Funktionscode, um zu sehen ... oh, und 'v0' =' 1' ist sys_exit (mit 'a0' Wert als Exit-Code). Wahrscheinlich teste ich das als erstes mit a0 = 123 und 'echo $?', Um zu sehen, ob der Exit-Code 123 war. – Ped7g