我必须使用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。我知道有一个系统调用来结束程序,但我需要在这里做类似的事情吗?或者它应该只是它自己的结束?我如何终止我的字符串有问题吗?在跳转并链接到另一个标签之前,是否需要保留返回地址?
正如您所看到的,我有很多问题而不是很多经验,所以任何帮助都会非常感激。谢谢。
答案 0 :(得分:1)
如果您在真正的基于MIPS的设备或模拟分支延迟插槽的仿真器上运行此操作,您可能需要填写这些插槽,以防您使用的汇编程序没有为您执行此操作。也就是说,在每个分支指令后插入nop
(有更好的方法,但这是最简单的方法)。
我知道有一个系统调用来结束程序,但是我需要在这里做类似的事情吗?
假设您正在与libc
进行关联,则可以调用exit
函数。只要您保存jr $ra
在输入main
时所拥有的值并在{{1}之前恢复它,$ra
例程结尾处的main
也可能有效}}
我是如何终止字符串的?
jr
表示零终止的ASCII,因此字符串中的.asciiz
是多余的,但不应导致任何问题。
在跳转并链接到另一个标签之前,是否需要保留返回地址?
每当你有嵌套的函数调用时,你需要保留返回地址,因为每个'\0'
都会修改jal
。