2016-11-03 72 views
1

所以我試圖寫一個程序,只是做一些簡單的遞歸,我讀過其他文章和問題的主題,我可以找到但無濟於事。反正我試圖向後打印我的名字。所以我一次只讀一個字節,在我的字符串末尾尋找0,如果我找到它,我開始展開並打印我保存的字節。 提前感謝您的幫助。在MIPS彙編中簡單遞歸的麻煩

代碼:

.data 
    # print name backwards 
    Yn: .asciiz "frodobaggins" #yn stands for your name 
.text 
main: 
    li $v0, 4   #the v registers tell system what to do 4 == 
    print_string 
    la $a1, Yn   #load Yn's address into a0 
    addi $sp, $sp, -4 #increment stack pointer, always initially points to garbage 
    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 
    lw $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 
    bne $t6, $0, otherwise #if t6 == 0 goto otherwise 
    add $a3, $a3, 1  #a1 = a1 + 1 
    sw $a3, 0($sp)  #store the word, without the byte $t6 used, onto the stack 
    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, 4  #setup $v0 to tell pc to print to console 
    lw $a0, 0($t6)  #console always reads from $a0 
    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) 
    jr $ra    #go back to original call of jal 
+0

你不問任何問題,是嗎? – tofro

+1

'lw $ t6,0($ a3)#讀取字節''lw'不加載一個字節;它加載一個_word_(4個字節)。 – Michael

+0

我原本是把它當作磅,但是現在它運行了,但是實際上不會打印任何東西,所以我把它改成了lw,看看我是否至少可以讓控制檯打印出這樣的東西 – Supercatfishpro

回答

0

有幾個問題。

加載$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