为什么我的 MIPS 程序不从内存中加载值?
Why isn't my MIPS program loading values from memory?
我正在开发一个反转字符串位置的程序。
但我 运行 遇到了一些麻烦。
该程序通过循环一次字符串来获取字符串的长度。
一旦发现另一个循环开始,通过将值保存在临时寄存器中来交换前后字符,然后将另一个值存储到字节中。
然后字符串的开头地址递增,结尾递减。这样做直到在循环中也递增的临时寄存器等于字符串长度的一半。
但出于某种原因,当我单步执行程序时,它在第二个循环期间没有将字符值存储到寄存器中。
有人知道为什么会这样吗?我该如何解决这个问题?
谢谢。
.data
msg: .asciiz "Hello World"
nline: .asciiz "\n"
.globl main
.text
#t0 address location
#t1 address location used to increment and find [=10=]
#t2 value stored in addres location of t1
#t3 stores length of string
main:
la $t0,msg #load address location
add $t1,$t0,$zero #loads address location for use in loop
lb $t2,0($t1) #loads value found at address in t1
add $t3,$zero,$zero #set length to 0
len: #increments value that determines length and memory location of current character
addi $t3,$t3,1
add $t0,$t0,1
#add $a0,$zero,$t3
#li $v0,1
#syscall
lb $t2,0($t0)
bne $t2,$zero,len #loops back to len if null character is not found
srl $t4,$t3,1
add $t5,$t0,$zero
add $t6,$t3,$t0
add $t9,$zero,$zero
swap:
lb $t7,0($t5)
lb $t8,0($t6)
sb $t8,0($t6)
sb $t7,0($t5)
addi $t5,$t5,1
sub $t6,$t6,1
addi $t9,$t9,1
bne $t4,$t9,swap
li $v0,10
syscall
当您逐步执行该程序时,您应该验证您的所有假设,尤其是当您发现某些问题时,例如字母值未正确加载。
在你的例子中(我在 MARS 中做了 运行),就在标签 swap:
之前,寄存器包含:
t0 0x1001000b
t1 0x10010000
t2 0
t3 11
t4 5
t5 0x1001000b
t6 0x10010016
而 msg
符号值为 0x10010000
。那个只在t1
中,但是你使用t5, t6
来加载字符串的值,t5
指向msg
的零终止符,t6
是一种方式离开。所以"some reason"就是你读的不是你想要的内存,而是内存之外的。
根据代码中的注释判断,您在 "strlen" 中使用 t0
而不是 t1
,并且您希望 t0
保留原始 [=13] =] 地址(但 t1
保留它,t0
指向 msg
的零终止符)。
你的代码也会因为空字符串而失败,因为你做了一些初始 lb
但不测试它,然后你从字符串的第二个字节开始检查零。
总的来说,您可能经常尝试稍微整理一下您的第一个想法,并稍微简化一下,在这个特定的任务中,您可以只使用指向字符串的指针来完成所有事情,无需计算 length/half_length作为整数:
.data
msg: .asciiz "Hello World"
.text
.globl main
main:
la $t0,msg # t0 = string address
add $t1,$t0,$zero # t1 = string address for "strlen"
len: # find zero terminator of string
lb $t2,($t1) # t2 = letter from string
addi $t1,$t1,1 # advance string pointer
bne $t2,$zero,len # loop back to len if null character is not found
# t0 = string address, t1 = points 1 byte after the zero terminator
addi $t1,$t1,-2 # adjust t1 to point to last character
# validate that t0 < t1 (will not for empty or one letter strings)
bgeu $t0,$t1,too_short_to_reverse # sltu+beq
swap:
lb $t2,0($t0) # swap letters at t0/t1 positions
lb $t3,0($t1)
sb $t2,0($t1)
sb $t3,0($t0)
addi $t0,$t0,1 # adjust pointers
addi $t1,$t1,-1
blt $t0,$t1,swap # while t0 < t1 keep swapping letters
too_short_to_reverse:
# done, string is reversed
# debug output of string to see it reversed
li $v0,4
la $a0,msg
syscall
li $v0,10 # exit syscall
syscall
(使用了很少的伪指令,虽然你的原始源代码看起来像你在试图避免它们,但你仍然有一些不准确的指令,这些指令一定是由汇编程序以任何方式调整的,比如 add $t0,$t0,1 -> addi
)
我正在开发一个反转字符串位置的程序。
但我 运行 遇到了一些麻烦。
该程序通过循环一次字符串来获取字符串的长度。
一旦发现另一个循环开始,通过将值保存在临时寄存器中来交换前后字符,然后将另一个值存储到字节中。
然后字符串的开头地址递增,结尾递减。这样做直到在循环中也递增的临时寄存器等于字符串长度的一半。
但出于某种原因,当我单步执行程序时,它在第二个循环期间没有将字符值存储到寄存器中。
有人知道为什么会这样吗?我该如何解决这个问题?
谢谢。
.data
msg: .asciiz "Hello World"
nline: .asciiz "\n"
.globl main
.text
#t0 address location
#t1 address location used to increment and find [=10=]
#t2 value stored in addres location of t1
#t3 stores length of string
main:
la $t0,msg #load address location
add $t1,$t0,$zero #loads address location for use in loop
lb $t2,0($t1) #loads value found at address in t1
add $t3,$zero,$zero #set length to 0
len: #increments value that determines length and memory location of current character
addi $t3,$t3,1
add $t0,$t0,1
#add $a0,$zero,$t3
#li $v0,1
#syscall
lb $t2,0($t0)
bne $t2,$zero,len #loops back to len if null character is not found
srl $t4,$t3,1
add $t5,$t0,$zero
add $t6,$t3,$t0
add $t9,$zero,$zero
swap:
lb $t7,0($t5)
lb $t8,0($t6)
sb $t8,0($t6)
sb $t7,0($t5)
addi $t5,$t5,1
sub $t6,$t6,1
addi $t9,$t9,1
bne $t4,$t9,swap
li $v0,10
syscall
当您逐步执行该程序时,您应该验证您的所有假设,尤其是当您发现某些问题时,例如字母值未正确加载。
在你的例子中(我在 MARS 中做了 运行),就在标签 swap:
之前,寄存器包含:
t0 0x1001000b
t1 0x10010000
t2 0
t3 11
t4 5
t5 0x1001000b
t6 0x10010016
而 msg
符号值为 0x10010000
。那个只在t1
中,但是你使用t5, t6
来加载字符串的值,t5
指向msg
的零终止符,t6
是一种方式离开。所以"some reason"就是你读的不是你想要的内存,而是内存之外的。
根据代码中的注释判断,您在 "strlen" 中使用 t0
而不是 t1
,并且您希望 t0
保留原始 [=13] =] 地址(但 t1
保留它,t0
指向 msg
的零终止符)。
你的代码也会因为空字符串而失败,因为你做了一些初始 lb
但不测试它,然后你从字符串的第二个字节开始检查零。
总的来说,您可能经常尝试稍微整理一下您的第一个想法,并稍微简化一下,在这个特定的任务中,您可以只使用指向字符串的指针来完成所有事情,无需计算 length/half_length作为整数:
.data
msg: .asciiz "Hello World"
.text
.globl main
main:
la $t0,msg # t0 = string address
add $t1,$t0,$zero # t1 = string address for "strlen"
len: # find zero terminator of string
lb $t2,($t1) # t2 = letter from string
addi $t1,$t1,1 # advance string pointer
bne $t2,$zero,len # loop back to len if null character is not found
# t0 = string address, t1 = points 1 byte after the zero terminator
addi $t1,$t1,-2 # adjust t1 to point to last character
# validate that t0 < t1 (will not for empty or one letter strings)
bgeu $t0,$t1,too_short_to_reverse # sltu+beq
swap:
lb $t2,0($t0) # swap letters at t0/t1 positions
lb $t3,0($t1)
sb $t2,0($t1)
sb $t3,0($t0)
addi $t0,$t0,1 # adjust pointers
addi $t1,$t1,-1
blt $t0,$t1,swap # while t0 < t1 keep swapping letters
too_short_to_reverse:
# done, string is reversed
# debug output of string to see it reversed
li $v0,4
la $a0,msg
syscall
li $v0,10 # exit syscall
syscall
(使用了很少的伪指令,虽然你的原始源代码看起来像你在试图避免它们,但你仍然有一些不准确的指令,这些指令一定是由汇编程序以任何方式调整的,比如 add $t0,$t0,1 -> addi
)