MIPS - 超过4个字符串作为参数

时间:2013-12-02 02:59:17

标签: string mips

我正在尝试在MIPS中实现puts。我使用了$a0。它从该寄存器的地址开始打印字符串。但是,我现在正在尝试为任意数量的字符串实现puts,这意味着我不能再使用寄存器了。我很困惑如何有效地使用堆栈。从我的主程序,我堆叠任意数量的字符串。然后,我想要jalputs,这将打印所有字符串。我还在堆栈顶部传递要打印的字符串数。

以下是puts的代码:

# puts - prints ASCII to the screen
#    prints from $a0, $a1, $a2, $a3 (buffers)
#    stops when chracter is NULL
#   ASSUME THAT WHEN PUTS IS CALLED, AT LEAST ONE STRING IS PASSED
#
# CALLING CONVENTION
#
# I decided not to use any of the registers $a0-$a4. 
# Instead, the caller stacks all the strings it wants to print in the stack. 
# On top of it, it adds the number of strings it wants to print.
# puts will loop, printing each string, until it has printed all of them.
#
# Since the caller is using "s" registers, puts must save them to the stack. 
# Thus, these will be put on top of the stack.
# puts will have to access the strings below the stacked registers.
#
#   ============  STACK DIAGRAM ==============
#
#   \   Number of Strings   \ TOP
#   \       String 1        \ +200      
#   \       String 2        \ +400
#   \       String 3        \ +600
#   \       String 4        \ +800
#   \       String 5        \ +/000
#   \       String 6        \ +...
#   \         ...       \ 
#
# on entry:
#   $ra -- return address
#   0($sp) -- number of strings to print
#   x($sp) -- strings to print
#
# on exit:
#   $v0 -- number of character printed
#       
    .text
puts:
    addi $sp, $sp, -20  # make room for 6 registers
    sw $ra, 16($sp)     # save $ra on the stack
    sw $s0, 12($sp)     # save $s0 on the stack
    sw, $s1, 8($sp)     # save $s1 on the stack
    sw, $s2, 4($sp)     # save $s2 on the stack
    sw, $s3, 0($sp)     # save $s3 on the stack

    lw $s0, 224($sp)    # copy address of first string inside $s0
    lw $s1, 24($sp)     # copy number of strings to print inside $s1
    move $s2, $zero     # counter for the number of strings printed
    move $s3, $zero     # counter for the number of characters sent to putchar

putsString:
**  lbu $t3, ($s0)      # load ccurrent char into #t3
    beq $t3, $zero, exitString  # exit puts if the current character is the NULL character

    move $a0, $t3       # put the character to print inside $a0, accessible by putchar
    jal putchar     # print char using putchar
    addi $s3, $s3, 1    # character count += 1
    addi $s0, $s0, 4    # increment string address by 1 word (4 bytes)
    j putsString        # Loop to print next character
exitString:
    addi $s2, $s2, 1    # increment number of strings printed
    beq $s1, $s2, exitPuts  # if # of strings to print = # of strings printed, then exit puts; else, increment # of strings printed
    addi $s0, $s0, 200  # $s0 now points to next string to print
    j putsString
exitPuts:   
    move $v0, $s4       # return number of character printed
    lw $s3, 0($sp)      # restore stack
    lw $s2, 4($sp)      # -
    lw $s1, 8($sp)      # -
    lw $s0, 12($sp)     # -
    lw $ra, 16($sp)     # -
    addi $sp, $sp, 20   # pop from stack
    jr $ra          # return

带有**的线路现在是错误的线路。我得到Runtime exception at 0x00400124: address out of range 0x00000000

以下是我如何将字符串保存到堆栈中(我现在用gets读取2(2是硬编码的)字符串。

init:
    beq $s0,2,continue
    move $a0, $s2       # load buffer address into $a0          
    la $t1, limit       # - load limit into $a1             
    lb $a1, ($t1)       # - ...
    jal gets        # call gets - it will modify buffer     
    move $t0, $v0       # $t0 = string count returned by gets
moveBufferToStack:
    lbu $t1, ($s2)      # get first character inside buffer
    beqz $t1, endMoveBuffer
    sw $t1, ($sp)       # copy buffer(i) into array(i)

    addi $sp, $sp, 4    # array pointer points a position forward
    addi $s2, $s2, 4    # same for array pointer
    j moveBufferToStack
endMoveBuffer:
    addi $sp, $sp, 200  # step to next array cell 
    addi $s0, $s0, 1    # increment number of strings read
    j init          # loop until we have 9 elements
continue:           
    jal puts
    j done

1 个答案:

答案 0 :(得分:2)

只关注问题,我看到了:

lw $s0, 224($sp)    # copy address of first string inside $s0
...
putsString:
lbu $t3, ($s0)      # load ccurrent char into #t3

所以你已经加载$s0,内存的内容$sp开始经过224个字节。如果我理解正确,那就是字符串的前四个字节。意思是,如果字符串是“Madam,我是Adam”,那么$s0包含'a''d'''M'(如果我的字节顺序正确的话)。

因此,当您执行lbu $t3, ($s0)时,您未将当前字符加载到$t3。您正在加载 $s0指向的字节,它将成为内存中的随机点。如果您的字符串为空,$s0可能包含0x00000000 - 因此会产生您收到的错误。

我认为您想要做的是lw,而不是addi $s0, $sp, 224。{{1}}。然后,$ s0将指向$ sp + 224的地址。