0

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.

Alexey Frunze
  • 61,140
  • 12
  • 83
  • 180
TurtleMan
  • 175
  • 2
  • 15

1 Answers1

3

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).

Ped7g
  • 16,236
  • 3
  • 26
  • 63
  • Yep, Linux read/write system calls should take file descriptors (e.g. 0 for stdin, 1 for stdout), buffer addresses and byte counts. – Alexey Frunze Oct 14 '16 at 10:58
  • Thank you for the response @Ped7g. I am running the program on a ci20 machine that is a Linux based machine that does have gdb running on it. When I run it through the gdb debugger it does not seg fault hence my confusion of why it is seg faulting. – TurtleMan Oct 14 '16 at 20:13
  • @TurtleMan well, then the arguments are not toxic enough to segfault, but you are using MARS arguments for syscall instead of linux. By a quick look on the web I think this may output something to console: `v0`=`4` (sys_write), `a0`=`1` (file descriptor stdout), `a1`=`prompt` (address of .ascii string), `a2`=`25` (length of .ascii string) `syscall`. Try this first in short code to see... oh, and `v0`=`1` is sys_exit (with `a0` value as exit code). Probably test that one as very first, with a0=123, and `echo $?` to see if exit code was 123. – Ped7g Oct 14 '16 at 21:07
  • syscalls with bad arguments don't segfault directly. They return -EINVAL or -EFAULT. On x86, the wrong `int` instruction will segfault (like `int 80` instead of `int 0x80`), but SYSCALL won't. More likely, the code never properly calls `sys_exit` and falls off the end of the code into bogus instructions. – Peter Cordes Oct 15 '16 at 17:26