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

时间:2018-01-15 11:41:58

标签: assembly mips

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

.data

.text
    main:

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

        li $v0, 10
        syscall

在我的“原创”程序中,我读取字符的字符串字符,将每个字符保存到寄存器中直到出现“”(空格),以获得单个字。现在将字节加载到寄存器$ t1中,检查读取字符是否为“空格”(停止循环)也可以工作,但是当我想将上面写的那个字节存储到另一个寄存器(应该在结束包含整个单词)产生错误。怎么了?据我所知,上面的代码应该将“$ t2”中包含的字节存储到$ t3 + 0中?至少是什么定义和文献所说的..因为字符是1字节,这应该有用吗?但是我似乎误解了某些东西,并且会对任何提示或解释感到高兴

错误为Exception occured at ...,然后是sb $t2, 0($t3)

行的位置

然后Bad address in data Stack read 0x0000...

发生了另一个错误

当我这样做时它起作用:

.data

    word:   .space 10
.text
    main:

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

        sb $t2, 0($t1)

        li $v0, 10
        syscall

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

1 个答案:

答案 0 :(得分:1)

        sb $t2, 0($t3)
  

上面的代码应该存储" $ t2"中包含的字节。进入$ t3 + 0

这些术语的使用有点奇怪,我不确定你是否只是以令人困惑的方式使用它们,或者你甚至错误地理解它们,但我会尝试解释IMO的正确方法描述它的作用。

该代码行取值为t2寄存器,并将其存储在地址t3 + 0的计算机内存中。 "将它存储到$ t3 + 0" 描述中对我来说就像修改t3寄存器的内容一样,但它没有。

你可以将它想象成两个截然不同的芯片(硬件芯片,而不是食品),一个是MIPS CPU。这个具有32个通用(1)目的寄存器,每个寄存器为32位宽,即1024位信息,直接存储在CPU芯片中。当你使用措辞"存储到寄存器"时,我想把信息写入CPU上这个1024位数组内的一个插槽中,正在"寻址"通过注册名称,例如$14(别名为$t6)。

另一个芯片是存储芯片,它只有很少的晶体管专用于某些逻辑" (从地址和数据总线接收信号,并根据总线状态从正确的存储器位单元读取/存储值),99%的晶体管/单元只是存储一位值的存储单元(0或1,以不同的电流编码)。它们按字(32一起形成单个单元)分组,并可按字节寻址(字元素的4个8位子部分),即每个字节在存储器芯片中具有不同的地址。

要使用指令sb将值存储到存储器中,您必须提供字节值(在您的情况下为t2寄存器的低8位)和存储器地址(整数32位{{1 }}寄存器用作地址值),然后CPU将t3内容设置为"地址"总线的一部分,t3内容到"数据"总线的一部分,并向存储器芯片发出信号"存储"与那些人合作。但是你没有在你的示例t2中提供任何值,因此它将解决一些随机计算机内存(可能是零地址,在高级语言中通常用作t3,因此通过默认情况下,它经常被OS映射为无效的内存地址,这对您来说是不受限制的,NULL指令在写入计算机内存的非法部分时会崩溃。

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

.data

然后,您可以将.data word_buffer: .space 1000 # maximum possible word length is 1000 (including terminator value) # if you will overwrite 1001 bytes, you will overwrite following memory 设置为包含第一个保留的1000字节的地址:

t3

当使用像MARS / SPIM这样的模拟器时,您可以在编译后检查符号表以查看缓冲区所在的内存位置,即 la $t3, word_buffer # la = "load address" pseudo instruction # this will modify the "t3" content on the CPU chip, not memory 符号的值将为word_buffer或类似,&# 39; s用于通过0x00401000指令修改内存内容的内存地址(也意味着sb基本上是la的别名,但使用" la"对于任何审阅您的原始意图来源的人来说,它具有更高的可读性。)

* 1)我发现它们不是完全通用的,因为li $t3, 0x00401000又名$0将始终读为零(即使你将其他值写入其中),还有更多有一些特殊的隐式用法,比如$zero,但是大约有28-29个是一般的,在你想要的任何用法中都是相同的。

编辑:关于你的问题编辑

仍然不清楚你的意思,因为你现在意识到自己$sp是无效的内存地址。因此,您必须决定使用哪个内存部分:

  • 两个常见的选择是t3 + 0段和堆栈内存,你也可以拿起视频内存(MARS模拟器有插件用于位图显示,可以配置为使用一些共享的通用内存{{ 1}}地址,由MARS" OS")提供,或者您可以使用" OS"用于从"堆"动态保留一些内存的API操作系统正在管理的内存保留。

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

如果要在寄存器中仅使用字节(8位)进行操作,则必须应用正确的掩码(通常为t2,或者以所需的方式移动旧值以为新位腾出空间),并合并注册位t3(在某些情况下还andi和类似的值可能需要值合并,如果你知道,你在做什么),以你的方式建立32位内容的寄存器欲(例如,在单个寄存器中存储四个不同的8位子部分)。