puts
MIPSに実装しようとしています。で動作させました$a0
。そのレジスタのアドレスから始まる文字列を出力しました。ただし、現在puts
、任意の量の文字列を実装しようとしています。つまり、レジスタを使用できなくなりました。スタックを効率的に使用する方法について混乱しています。私の主な手順から、任意の量の文字列をスタックします。私はその後、したいjal
のputs
すべての文字列が印刷されますされ、。また、スタックの一番上に、印刷する文字列の数を渡します。
これが私のコードです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
ます。
文字列をスタックに保存する方法は次のとおりです(今のところ、2つ(2つはハードコードされています)の文字列をで読み取りますgets
)。
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
問題のある行に焦点を合わせると、次のようになります。
lw $s0, 224($sp) # copy address of first string inside $s0
...
putsString:
lbu $t3, ($s0) # load ccurrent char into #t3
これで、224バイトを過ぎたメモリ$s0
の内容がロードされました$sp
。私が正しく理解していれば、それは文字列の最初の4バイトです。つまり、文字列が「マダム、私はアダムです」の場合、$s0
「a」「d」「a」「M」が含まれます(エンディアンが正しい場合)。
したがって、を実行するlbu $t3, ($s0)
と、現在の文字がにロードされません$t3
。が指す バイトをロードしています。$s0
これは、メモリ内のランダムなスポットになります。文字列が空白の場合、$s0
0x00000000が含まれている可能性があるため、発生するエラーが生成されます。
の代わりにlw
、あなたがやりたいことはaddi $s0, $sp, 224
です。次に、$ s0は$ sp +224のアドレスを指します。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加