Prompting for user input in assembly ci20 seg faul

2019-03-04 17:29发布

问题:

I am currently working on a small program on a ci20 machine that prompt the user for a integer value then print the value to the screen.

My current 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

When I try to run the program I get a seg fault and not sure why. Any help or suggestion would be greatly appreciated.

回答1:

edit: for some reason I completely ignored this code was tested on ci20 machine.

So is this linux? Then you can't use MARS syscalls, you have to find linux syscalls instead. It is then probably segfaulting on the very first syscall instruction, as the arguments are invalid for Linux.


To display "prompt" you use syscall with arguments set as v0 = 4, a0 = prompt ... to display "message" you set arguments for syscall as v0 = 1, a0 = message.

If this is in MARS, then v0=1 is "print integer", so a0 should be integer, not address of "message" string. .. you probably want to call syscall twice, with v0=4 and v0=1 (argument a0 being "message" and users integer for particular call).

Anyway, none of this should segfault. The segfault happens probably at the end, where your code ends with addiu $sp, $sp, +4, not returning to the ra, or calling syscall "exit" function (from the saving of ra at the start of your code it looks like you want rather to return than exit, but it's up to you). So the execution continues over some random instructions (uninitialized memory content).

Anyway 2, you should figure out how to load this code in debugger and step over it instruction by instruction, then you will be capable to say where exactly it segfaults, and what was the content of registers before segfaulting instruction. If your code segfaults and you don't even know where, it shows lack of effort on your side.

(disclaimer: I never did MIPS assembly, so I'm mostly guessing how it works and may have overlooked something)


edit about syscall, maybe this hint will help too?

syscall isn't some magic instruction doing all that nifty stuff on the CPU. It just jumps to some handler routine.

That handler code is set up by the OS. Most of the MIPS assembly listings on SO are targetted at MARS or SPIM, which have completely different handler than Linux.

So you should study linux ABI for MIPS, and how syscall is used there. And then find linux system calls table, you will probably find ton of x86 docs, so you have to convert that into v0/a0/... ABI.

You can still follow MARS examples, but any OS interaction has to be adjusted, and don't expect to find alternative for everything. For example outputting the number is not available in linux. You have to convert the number value into ASCII string by yourself (for single digit numbers adding '0' is enough, for numbers above 9 you have to calculate digit for each power of 10 and convert it into ASCII character and store it into some buffer), and output then the string with sys_write/etc. (or link with some libc and call sprintf-like function from C library).