简体   繁体   中英

Printf and Scanf in Mips32 and other questions

I have to use Mips32 for a class and I'm having some trouble with I/O. The big problem is that I can't use syscalls because those will only work on an emulator and my professor wants to just use an assembler, therefore we're required to use printf and scanf. I tried writing a program to handle some very basic I/O. The idea is to prompt the user to input an integer, scan an integer, and the output the value that the user put in. So my program looks like this:

.abicalls
.option pic0

.data

.align  2

inputMessage:
    .asciiz "Please input a positive integer: \0"
intFormat:
    .asciiz "%d\0"

input:
    .word   0

.text
.align  2
.globl  main
.set    nomips16
.ent    main
.type   main, @function # tells the symbol table that `main` is a function

c_print:
#Prints a format based on $a1
#$a1 = 0: prints input message
#$a1 = 1: prints integer in $a0

    # The following two instructions are necessary becuase printf takes argument $a0 as the address of a format string
    # and it takes $a1, $a2, etc... as the variables to be inserted based on that format string. So I need to move $a1
    # to $a2 and $a0 to $a1 to make room for the for the string format in $a0
    addi    $a2, $a1, 0     # Move $a1 to $a2
    addi    $a1, $a0, 0     # Move $a0 to $a1
    li  $t0, 1          # Load 1 into $t0. This is used to compare $a2 (now the option) to see what we will print

    beq $a2, $t0, print_o1  # If $a2 == 1 jump to print_o1, else it just goes to print_o0

    print_o0:
        la  $a0, inputMessage   # Load the address of the inputMessage string into $a0
        j   print_oEnd      # Jump to print_oEnd

    print_o1:
        la  $a0, intFormat      # Load the address of the intFormat string into $a0
        j   print_oEnd      # Jump to print_oEnd

    print_oEnd:

        # The following instruction is used to store the memory address so it is preserved when we return from printf
        addi    $s1, $ra, 0     # Put the return address into $s1
        jal     printf          # Jump and Link to printf
        addi    $ra, $s1, 0     # Put the return address back into $ra

    jr  $ra             # Jump back to the next instruction after we called c_print

c_scan:

    la  $a0, intFormat      # Load the address of the intFormat string into $a0
    la  $a1, input      # Load the address of the word called "input" into $a1

    addi    $s1, $ra, 0     # Preserve the return address in $s1
    jal     scanf           # Jump and Link to scanf
    addi    $ra, $s1, 0     # Put the return address back into #ra

    lw  $v0, input      # Load the word called "input" (now it's the user input integer) into $v0

    jr  $ra         # Jump back to the next instruction after we called c_scan

main:

#==========================

    li  $a0, 0      # Load 0 into $a0 (serves no purpose since I'm loading 0 into $a1)
    li  $a1, 0      # Load 0 into $a1 (option 0 makes c_print just print a message, not the int in $a1)
    jal c_print     # Jump and Link to function c_print

    jal c_scan      # Jump and Link to function c_scan (takes no arguments)

    addi    $a0, $v0, 0 # c_scan stores the input into $v0, so put $v0 into $a0
    li  $a1, 1      # Load 1 into $a1 (option 1 makes c_print print the integer in $a0)
    jal c_print     # Jump and link to function c_print

#==========================

.end    main
.size   main, .-main

At the moment this program will output the inputMessage, but it will not output the integer that we scanned in. Also the program will not terminate, it will just wait for me to press ctrl-c. I know that there is a syscall to end the program, but do I need to do something like that here? Or should it just end on it's own? Is there a problem with how I terminate my strings? And do I need to preserve the return address before I jump and link to another label?

As you can see I have a lot of questions and not a lot of experience, so any help would be greatly appreciated. Thank you.

If you're running this on a real MIPS-based device, or an emulator that emulates branch delay slots, you may need to fill those slots in case the assembler you use doesn't do it for you. That is, insert a nop after each branch instruction (there are better ways, but that's the easiest way).

I know that there is a syscall to end the program, but do I need to do something like that here?

Assuming that you're linking against libc you could call the exit function. A jr $ra at the end of you main routine might also work, as long as you save the value that $ra had when entering main and restore it before the jr .

Is there a problem with how I terminate my strings?

.asciiz means zero-terminated ASCII, so the '\\0' in your strings are redundant, but shouldn't cause any problems.

And do I need to preserve the return address before I jump and link to another label?

Whenever you have nested function calls you need to preserve the return address, since each jal will modify $ra .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM