有幾個問題。
加載$t6
應該是一個字節操作。到otherwise
的條件分支有不正確的意義。打印的系統調用應該是11而不是4 []。在otherwise
處的堆棧幀恢復有問題。
我創建了三個版本。顯示錯誤的註釋版本。清理和工作版本。而且,我從頭開始創建一個版本。
這裏的註釋版本[請原諒無償風格清理]:
.data
Yn: .asciiz "frodobaggins" # yn stands for your name
# print name backwards
.text
main:
li $v0,4 # syscall for print string
la $a1,Yn # load Yn's address into a0
addi $sp,$sp,-4 # increment stack pointer
sw $a1,0($sp) # store address of a1 (Yn) into stack pointer
jal recurse # recursive func call
addi $sp,$sp,4 # increment sp back to beggining
addi $v0,$0,10 # v0 = exit
syscall # exit
recurse:
lw $a3,0($sp) # load my name into reg $a3
# NOTE/BUG: this should be lb
# NOTE/BUG: by loading $t6 _before_ we've saved it, we are destroying the
# value that _caller_ set
###lw $t6,0($a3) # read byte
lb $t6,0($a3) # read byte
addi $sp,$sp,-12 # increment stack ptr
sw $ra,8($sp) # store address of $ra onto stack
sw $t6,4($sp) # store the byte loaded into $t6 onto stack
# NOTE/BUG: this should be beq and _not_ bne
###bne $t6,$0,otherwise # if t6 == 0 goto otherwise
beq $t6,$0,otherwise # if t6 == 0 goto otherwise
add $a3,$a3,1 # a1 = a1 + 1
sw $a3,0($sp) # push the word, without the byte $t6 used
jal recurse
lw $t6,4($sp) # load the byte that was stored into $t6
lw $ra,8($sp) # get $ra ready for returning
# NOTE/BUG: this is the puts syscall -- what we want is putc (i.e. 11)
###addi $v0,$0,4 # setup $v0 to tell pc to print to console
addi $v0,$0,11 # setup $v0 to tell pc to print to console
# NOTE/BUG: we want to load the byte into $a0
# NOTE/BUG: at this point $t6 has the byte value and _not_ a pointer
###lw $a0,0($t6) # console always reads from $a0
move $a0,$t6
syscall
addi $sp,$sp,12 # put stack pointer back
jr $ra # string is finished, return.
otherwise:
# because this is just returning, i need to get the ra that was just
# stored on the stack
lw $ra,8($sp)
# NOTE/BUG: by _not_ restoring the $t6 value of _caller_ things are broken
jr $ra # go back to original call of jal
這裏的工作版本。注意早期的堆棧幀設置和完整的堆棧幀在otherwise
彈出。這比較常見。也就是說,只有一個地方可以建立堆棧框架。而且,有且只有一個地方,彈出框和返回:
.data
Yn: .asciiz "frodobaggins" # yn stands for your name
# print name backwards
.text
main:
li $v0,4 # syscall for print string
la $a1,Yn # load Yn's address into a0
addi $sp,$sp,-4 # increment stack pointer
sw $a1,0($sp) # store address of a1 (Yn) into stack
jal recurse # recursive func call
addi $sp,$sp,4 # increment sp back to beggining
addi $v0,$0,10 # v0 = exit
syscall # exit
recurse:
lw $a3,0($sp) # load my name into reg $a3
lb $t6,0($a3) # read byte
addi $sp,$sp,-12 # establish stack frame
sw $ra,8($sp) # store address of $ra onto stack
sw $t6,4($sp) # store the byte loaded into $t6 onto stack
beq $t6,$0,otherwise # if t6 == 0 goto otherwise
add $a3,$a3,1 # a1 = a1 + 1
sw $a3,0($sp) # push the word, without the byte $t6 used
jal recurse
lw $t6,4($sp) # load the byte that was stored into $t6
lw $ra,8($sp) # get $ra ready for returning
addi $v0,$0,11 # setup $v0 to tell pc to print to console
move $a0,$t6
syscall
otherwise:
lw $ra,8($sp) # restore return address from stack
lw $t6,4($sp) # store the byte loaded into $t6 onto stack
addi $sp,$sp,12 # put stack pointer back
jr $ra # string is finished, return.
這裏是我的重構的版本。它更符合ABI標準。有一些可能的輕微變化:
.data
name: .asciiz "frodobaggins"
nl: .asciiz "\n"
.text
.globl main
main:
li $v0,4 # print string syscall
la $a0,name # string address
syscall
li $v0,4 # print string syscall
la $a0,nl # string address
syscall
la $a0,name # string address
jal recurse1
li $v0,4 # print string syscall
la $a0,nl # string address
syscall
li $v0,10
syscall
# recurse1 -- reverse print string
#
# arguments:
# a0 -- current string pointer
recurse1:
sub $sp,$sp,8 # create stack frame
sw $ra,4($sp) # save return address
sw $a0,0($sp) # save current string pointer
lb $t0,0($a0) # get current byte
beqz $t0,recurse1_exit # is it EOS? if yes, fly
addu $a0,$a0,1 # advance to next char
jal recurse1 # print other chars
subu $a0,$a0,1 # go back to our character
lb $a0,0($a0) # get current byte
li $v0,11 # putc syscall number
syscall
recurse1_exit:
lw $ra,4($sp) # restore return address
lw $a0,0($sp) # restore current string pointer
add $sp,$sp,8 # pop stack frame
jr $ra # return
# recurse2 -- reverse print string
#
# arguments:
# a0 -- current string pointer
recurse2:
sub $sp,$sp,8 # create stack frame
sw $ra,4($sp) # save return address
sw $a0,0($sp) # save current string pointer
lb $t0,0($a0) # get current byte
beqz $t0,recurse2_exit # is it EOS? if yes, fly
addu $a0,$a0,1 # advance to next char
jal recurse2 # print other chars
lw $a0,0($sp) # restore our pointer
lb $a0,0($a0) # get current byte
li $v0,11 # putc syscall number
syscall
recurse2_exit:
lw $ra,4($sp) # restore return address
lw $a0,0($sp) # restore current string pointer
add $sp,$sp,8 # pop stack frame
jr $ra # return
# recurse3 -- reverse print string
#
# arguments:
# a0 -- current string pointer
recurse3:
sub $sp,$sp,8 # create stack frame
sw $ra,4($sp) # save return address
lb $t0,0($a0) # get current byte
sw $t0,0($sp) # save current char value
beqz $t0,recurse3_exit # is it EOS? if yes, fly
addu $a0,$a0,1 # advance to next char
jal recurse3 # print other chars
lw $a0,0($sp) # get current byte
li $v0,11 # putc syscall number
syscall
recurse3_exit:
lw $ra,4($sp) # restore return address
add $sp,$sp,8 # pop stack frame
jr $ra # return
你不問任何問題,是嗎? – tofro
'lw $ t6,0($ a3)#讀取字節''lw'不加載一個字節;它加載一個_word_(4個字節)。 – Michael
我原本是把它當作磅,但是現在它運行了,但是實際上不會打印任何東西,所以我把它改成了lw,看看我是否至少可以讓控制檯打印出這樣的東西 – Supercatfishpro