Mips32中的Printf和Scanf以及其他问题

时间:2015-11-11 02:27:44

标签: c mips

我必须使用Mips32作为课程,我在使用I / O时遇到了一些麻烦。最大的问题是我不能使用系统调用,因为那些只能在模拟器上运行,而我的教授只想使用汇编程序,因此我们需要使用printf和scanf。我尝试编写一个程序来处理一些非常基本的I / O.这个想法是提示用户输入一个整数,扫描一个整数,输出用户输入的值。所以我的程序看起来像这样:

.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

此程序将输出inputMessage,但它不会输出我们扫描的整数。此外程序不会终止,它只会等我按ctrl-c。我知道有一个系统调用来结束程序,但我需要在这里做类似的事情吗?或者它应该只是它自己的结束?我如何终止我的字符串有问题吗?在跳转并链接到另一个标签之前,是否需要保留返回地址?

正如您所看到的,我有很多问题而不是很多经验,所以任何帮助都会非常感激。谢谢。

1 个答案:

答案 0 :(得分:1)

如果您在真正的基于MIPS的设备或模拟分支延迟插槽的仿真器上运行此操作,您可能需要填写这些插槽,以防您使用的汇编程序没有为您执行此操作。也就是说,在每个分支指令后插入nop(有更好的方法,但这是最简单的方法)。

  

我知道有一个系统调用来结束程序,但是我需要在这里做类似的事情吗?

假设您正在与libc进行关联,则可以调用exit函数。只要您保存jr $ra在输入main时所拥有的值并在{{1}之前恢复它,$ra例程结尾处的main也可能有效}}

  

我是如何终止字符串的?

jr表示零终止的ASCII,因此字符串中的.asciiz是多余的,但不应导致任何问题。

  

在跳转并链接到另一个标签之前,是否需要保留返回地址?

每当你有嵌套的函数调用时,你需要保留返回地址,因为每个'\0'都会修改jal