为什么我的MIPS程序没有从内存中加载值?

时间:2017-11-03 00:24:36

标签: assembly mips

我正在开发一个可以反转字符串位置的程序。

但是我遇到了一些麻烦。

程序通过循环字符串一次来获得字符串的长度。

一旦发现另一个循环开始,通过将值保存在临时寄存器中来交换后面和前面的字符,然后存储到另一个值所在的字节中。

然后,字符串开头的地址递增,结束递减。这样做直到在循环中也递增的临时寄存器等于字符串长度的一半。

但由于某种原因,当我逐步完成程序时,它不会在第二次循环中将字符的值存储到寄存器中。

有人不知道为什么会发生这种情况以及如何解决这个问题?

谢谢。

.data
msg:    .asciiz "Hello World"
nline: .asciiz "\n"
.globl main


.text
#t0 address location
#t1 address location used to increment and find \0
#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

1 个答案:

答案 0 :(得分:0)

当您单步执行该程序时,您应该验证所有假设,特别是如果您发现某些问题,例如字母值未正确加载。

在你的情况下(我确实在MARS中运行),在标签swap:之前,寄存器包含:

t0  0x1001000b
t1  0x10010000
t2  0
t3  11
t4  5
t5  0x1001000b
t6  0x10010016

msg符号值为0x10010000。那个只在t1,但您使用t5, t6加载字符串值,t5指向msg的零终结符,t6是方式关闭。所以“某种原因”是你没有读取你想要的内存,而是读取内存。

根据代码中的评论判断,您在“strlen”中使用了t0而不是t1,并且您希望t0保留原始msg地址(但是t1保留了它,t0指向msg的零终结符。

此外,您的代码将因空字符串而失败,因为您执行了一些初始lb但不测试它,然后从字符串的第二个字节开始检查零。

总的来说,你可能经常尝试清理你的第一个想法,并稍微简化一下,在这个特殊的任务中你可以用指向字符串的指针做所有事情,不需要计算长度/ half_length作为整数: / p>

.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