Mips,将字节存储到寄存器中会导致异常 [英] Mips, store byte into register causes exception

查看:144
本文介绍了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甚至没有有效的地址

解决方案

        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). /p>

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

要使用指令sb将值存储到内存中,您必须提供字节值(在您的情况下为t2寄存器的低8位)和内存地址(t3寄存器的整个32位用作地址) CPU将t3内容设置为总线的地址"部分,将t2内容设置为总线的数据"部分,并向存储芯片发出信号以对其进行存储"操作.但是在示例中您没有提供t3任何值,因此它将寻址一些随机的计算机内存(可能为零地址,在高级语言中通常用作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

然后,您可以将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_buffer符号将具有与0x00401000或类似的值,这就是将要存储的内存地址.用于通过sb指令修改内存内容(这也意味着la基本上是li $t3, 0x00401000的别名,但是使用"la"可以使任何对您的原始意图进行审查的人都具有可读性).


* 1)我发现它们并不是完全通用的,因为$0 aka $zero总是读为零(即使在其中写入其他值时也是如此),还有一些具有特殊的隐式用法,例如$sp,但其中大约28-29是通用的,并且在您希望使用的任何情况下都是相同的.


关于您的问题的编辑

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

  • 两个常见的选择是.data段和堆栈内存,还可以选择视频内存(MARS模拟器具有用于位图显示的插件,可以配置为在$gp地址周围使用一些共享的通用内存,由MARS"OS"提供),也可以使用"OS" API从OS正在管理的堆"内存中动态保留一些内存.

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

如果只想对寄存器中的字节(8位)进行操作,则必须应用正确的掩码(通常按andi或以所需的方式移位旧值以为新位腾出空间),然后合并寄存器位使用or(在某些情况下,也可能使用add类似的方法进行值合并,如果您知道,您在做什么),以您希望的方式建立寄存器的32位内容(例如,具有四个不同的8位子部分存储在单个寄存器中.

Since I didnt find anything that helped me fixing my problem Im just going to ask myself, I have the following assembly(mips) code for example:

.data

.text
    main:

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

        li $v0, 10
        syscall

In my "original" program Im reading a String character for character, saving each one into a register until a " " (Space) appears, to get single words. Now loading byte for byte into a register $t1 works, checking if the read character is a "Space" (to stop loop) works too, but when I then want to store that byte as written above into another register (which should at the end contain the whole word) produces that error. Whats wrong? As far as I understood, the code above should store the byte contained in "$t2" into $t3 + 0" ? Thats at least what definitions and literature say.. and since a character is 1 byte, this should work? But I seem to misunderstand something and would be really happy about any hints or explanations

The error is Exception occured at ... and then the position of the line with sb $t2, 0($t3)

Then another error with Bad address in data Stack read 0x0000...

It works when I do this:

.data

    word:   .space 10
.text
    main:

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

        sb $t2, 0($t1)

        li $v0, 10
        syscall

But how do I get what I want without declaring something in the data segment? Error seems to appear because I want to store something into the adress $t3 + 0 while $t3 doesnt even have a valid adress

解决方案

        sb $t2, 0($t3)

the code above should store the byte contained in "$t2" into $t3 + 0

That's a bit weird usage of those terms, I'm not sure whether you are just using them in confusing way, or you even understand them wrongly, but I will try to explain what is IMO correct way to describe what this does.

That code line takes value of t2 register, and stores it into computer memory at address t3 + 0. "storing it into $t3 + 0" description sounds to me like modifying the content of t3 register, which it does NOT.

You can imagine it in head as two distinct chips (HW chips, not food), one being MIPS CPU. This one has 32 general(1) purpose registers, each being 32 bits wide, that's 1024 bits of information, stored directly in the CPU chip. When you use wording "storing into register", I imagine writing the information into one of the slots inside this 1024 bit array on CPU, being "addressed" by register name, like $14 (having alias name $t6).

The other chip is the memory chip, which has only few transistors dedicated to some "logic" (picking up signals from address and data-bus-wires, and reading/storing value from correct memory bit cells according to the bus state), and 99% of it's transistors/cells are just memory cells storing one bit value (0 or 1, encoded in different electricity current). These are grouped by words (32 together forming single unit), and addressable by bytes (four 8 bit subpart of word element), i.e. each byte has distinct address in the memory chip.

To store value into memory with instruction sb you have to provide the byte value (the low 8 bits of t2 register in your case), and memory address (whole 32 bits of t3 register used as address value), then the CPU will set t3 content to "address" part of bus, t2 content to "data" part of bus, and signal the memory chip to do "store" operation with those. But you don't provide in your example t3 with any value, so it will address some random computer memory (probably zero address, which is often used as NULL in higher languages, and thus by default it is often mapped as invalid memory address by the OS), which is off limits to you, and the sb instruction does crash on writing into illegal part of computer memory.

To remedy you have to specify where in memory you want to store the newly generated data, like you can reserve some space in .data segment (to have some memory for writing):

.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

Then you can set up t3 to contain address of the first of the reserved 1000 bytes as:

    la $t3, word_buffer   # la = "load address" pseudo instruction
        # this will modify the "t3" content on the CPU chip, not memory

When using simulator like MARS/SPIM, you can check after compilation the symbol table to see where in memory the buffer is located, i.e. word_buffer symbol will have value like 0x00401000 or similar, that's the memory address which will used to modify memory content by sb instruction (also it means that la is basically alias of li $t3, 0x00401000, but using "la" has more readability for anyone reviewing your source about your original intent).


*1) I don't find them completely general-purpose, as $0 aka $zero will always read as zero (even when you write other value into it), and few more have a bit special implicit usage, like $sp, but about ~28-29 of them are general and equal in any usage you wish.


EDIT: about your question edit

Still not clear what you mean, as you now realize yourself the t3 + 0 is invalid memory address. So you must either to decide which part of memory you will use:

  • two common choices are .data segment, and stack memory, you can also pick up the video memory (MARS simulator has plugin for bitmap display, can be configured to use some shared general memory around $gp address, which is provided by the MARS "OS"), or you can use "OS" API to reserve some memory dynamically from the "heap" memory reserve the OS is managing.

  • or you may use the register storage itself (bits stored inside CPU, not in memory), then the answer to your question is simple move $t3, $t2, which will copy value of t2 into t3 (whole 32 bits).

If you want to operate with bytes only (8 bits) in registers, you have to apply correct masks (by andi usually, or shifting old values in desired way to make space for new bits), and merge register bits with or (in some cases also add and similar may be desirable for value merging, if you know, what you are doing), to build up the 32 bit content of register in a way you desire (like for example having four different 8 bit sub-parts stored in single register).

这篇关于Mips,将字节存储到寄存器中会导致异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆