Assembly Mips,将字节存储到寄存器导致异常

Assembly Mips,将字节存储到寄存器导致异常,assembly,mips,Assembly,Mips,由于我没有找到任何帮助我解决问题的方法,我只想问问自己,例如,我有以下汇编(mips)代码: .data .text main: li $t2, 'S' sb $t2, 0($t3) li $v0, 10 syscall 在我的“原始”程序中,我逐字符读取一个字符串,将每个字符串保存到寄存器中,直到出现一个“”(空格),以获得单个单词。现在将逐字节加载到寄存器$t1中是可行的,检查读取的字符是否是“空格”(停止循环)

由于我没有找到任何帮助我解决问题的方法,我只想问问自己,例如,我有以下汇编(mips)代码:

.data

.text
    main:

        li $t2, 'S'
        sb $t2, 0($t3)

        li $v0, 10
        syscall
在我的“原始”程序中,我逐字符读取一个字符串,将每个字符串保存到寄存器中,直到出现一个“”(空格),以获得单个单词。现在将逐字节加载到寄存器$t1中是可行的,检查读取的字符是否是“空格”(停止循环)也是可行的,但是当我想将上面写入的字节存储到另一个寄存器(最后应该包含整个字)时,会产生错误。怎么了?据我所知,上面的代码应该将“$t2”中包含的字节存储到$t3+0中?这至少是定义和文献所说的。既然一个字符是1字节,这应该可以工作?但我似乎误解了一些东西,如果有任何提示或解释,我会非常高兴

错误是,
异常发生在…
处,然后是带有
sb$t2,0($t3)

然后,数据堆栈中的地址错误读取0x0000…

当我这样做时,它会起作用:

.data

    word:   .space 10
.text
    main:

        la $t1, word
        li $t2, 'S'

        sb $t2, 0($t1)

        li $v0, 10
        syscall
但是,如何在不在数据段中声明某些内容的情况下获得所需内容?似乎出现了错误,因为我想将某些内容存储到地址$t3+0中,而$t3甚至没有有效的地址

        sb $t2, 0($t3)
上面的代码应该将“$t2”中包含的字节存储到$t3+0中

这些术语的用法有点奇怪,我不确定你们是否只是在混乱地使用它们,或者你们甚至错误地理解了它们,但我将尝试解释一下什么是描述这些术语的正确方式

该代码行获取
t2
寄存器的值,并将其存储到计算机内存中的地址
t3+0
“将其存储到$t3+0”描述听起来像是在修改
t3
寄存器的内容,但实际上并没有

你可以把它想象成两个不同的芯片(硬件芯片,不是食物),一个是MIPS CPU。这一个有32个通用寄存器,每个寄存器宽32位,即1024位信息,直接存储在CPU芯片中。当你使用“存储到寄存器,我设想将信息写入CPU上这个1024位数组中的一个插槽中,通过寄存器名“寻址”,如
$14
(别名为
$t6

另一个芯片是内存芯片,它只有很少几个专用于某些“逻辑”的晶体管(从地址和数据总线线拾取信号,并根据总线状态从正确的内存位单元读取/存储值),99%的晶体管/单元只是存储一位值的存储单元(0或1,以不同的电流编码)。这些由字分组(32个字组成一个单元),并可通过字节(字元素的四个8位子部分)寻址,即每个字节在内存芯片中有不同的地址

要使用指令
sb
将值存储到内存中,您必须提供字节值(在您的情况下
t2
寄存器的低位8位)和内存地址(整个
t3
寄存器的32位用作地址值),然后CPU将
t3
内容设置为总线的“地址”部分,
t2
内容设置为“数据”总线的一部分,并向内存芯片发送信号,让其执行“存储”操作。但在示例中,您没有提供任何值的
t3
,因此它将处理一些随机的计算机内存(可能是零地址,在高级语言中经常用作
NULL
,因此默认情况下,操作系统通常将其映射为无效内存地址),这是您的禁区,
sb
指令在写入计算机内存的非法部分时会崩溃

要解决此问题,您必须指定要在内存中存储新生成的数据的位置,例如您可以在
.data
段中保留一些空间(以便有一些用于写入的内存):

然后,您可以将
t3
设置为包含保留的1000字节中的第一个字节的地址,如下所示:

    la $t3, word_buffer   # la = "load address" pseudo instruction
        # this will modify the "t3" content on the CPU chip, not memory
当使用类似于MARS/SPIM的模拟器时,您可以在编译后检查符号表,以查看缓冲区在内存中的位置,即
word\u buffer
符号将具有类似
0x00401000
或类似的值,这是用于通过
sb
指令修改内存内容的内存地址(也就是说,
la
基本上是
li$t3,0x00401000
的别名,但是使用“la”对任何查看源代码的人来说都更容易阅读)


*1) 我不认为它们是完全通用的,因为
$0
又称
$zero
将始终被读取为零(即使您将其他值写入其中),并且很少有其他值具有某种特殊的隐式用法,如
$sp
,但其中约有28-29个是通用的,在您希望的任何用法中都是相同的


编辑:关于你的问题编辑

仍然不清楚您的意思,因为您现在意识到
t3+0
是无效的内存地址。因此您必须决定使用哪部分内存:

  • 两种常见的选择是
    .data
    段和堆栈内存,您还可以选择视频内存(火星模拟器有用于位图显示的插件,可以配置为在
    $gp
    地址周围使用一些共享的通用内存,由火星“OS”提供),或者您可以使用“OS”API从操作系统正在管理的“堆”内存保留中动态保留一些内存

  • 或者您可以使用寄存器存储器本身(存储在CPU内的位,而不是内存中),然后您的问题的答案是简单的
    move$t3,$t2
    ,它将
    t2
    的值复制到
    t3
    (整个32位)

如果您想在寄存器中仅使用字节(8位)进行操作,则必须应用正确的掩码(通常通过
和i
),或者以所需的方式移动旧值以为
    la $t3, word_buffer   # la = "load address" pseudo instruction
        # this will modify the "t3" content on the CPU chip, not memory