在MIPS中,在使用跳转指令时,我们使用标签。
again: nop
$j again
因此,当我们到达跳转指令时,我们使用标签again
来显示去哪里以及使用的实际地址的值。我想知道再次标签的存储位置。意思是,nop
表示存储在0x00400000,跳转指令位于0x00400004。那么,again
保存在哪里,MIPS如何知道again
指向0x00400000?它存储在存储器映射的动态数据区域中吗? This is the memory map I've been provided for MIPS
我还在下面列出了导致这种混淆的问题,供参考。
为以下分支(be,bne)和jump(j)指令提供十六进制的目标代码。
... # some other instructions
again: add ... # there is an instruction here and meaning is insignificant
add ... # likewise for the other similar cases
beq $t0, $t1, next
bne $t0, $t1, again
add ...
add ...
add ...
next: j again
假设标签再次位于内存位置0x10 01 00 20.如果您认为没有足够的信息来生成代码解释。
答案 0 :(得分:1)
标签本身不存储在任何地方。它只是汇编器/链接器的符号地址。跳转j again
指令操作码确实存储了实际结果地址,如数字。
链接器将所有目标文件粘合在一起,合并目标文件中的所有符号并填充正确的相对地址+为OS加载程序创建重定位表,生成可执行文件。
加载可执行文件时的操作系统还会加载重定位表,根据加载二进制文件的实际地址修改/填充使用绝对地址的指令,然后抛出重定位表,并执行代码
因此标签只是程序员的“源代码”,是特定固定内存地址的别名,可以节省程序员计算实际指令操作码大小,计算磁头或内存变量地址中的跳转偏移量。
您可能需要检查汇编程序中的“列表文件”(通常是/l
开关),同时编译一些汇编源代码,以查看生成的实际machine code个字节(标签中没有)。
在0x00400000
编译时,您的“任务”代码如下所示(我将add
设置为执行t1 = t1 + t1以获得任何内容):
Address Code Basic Source
0x00400000 0x01294820 add $9,$9,$9 4 add $t1,$t1,$t1
0x00400004 0x01294820 add $9,$9,$9 5 add $t1,$t1,$t1
0x00400008 0x11090004 beq $8,$9,0x00000004 6 beq $t0, $t1, next
0x0040000c 0x1509fffc bne $8,$9,0xfffffffc 7 bne $t0, $t1, again
0x00400010 0x01294820 add $9,$9,$9 8 add $t1,$t1,$t1
0x00400014 0x01294820 add $9,$9,$9 9 add $t1,$t1,$t1
0x00400018 0x01294820 add $9,$9,$9 10 add $t1,$t1,$t1
0x0040001c 0x08100000 j 0x00400000 11 next: j again
正如您所看到的,每条实际指令都产生32位值,有时称为“操作码”(操作码),该值在“代码”列中可见。 “Address”列表示,此值存储在内存中,当加载可执行文件并准备执行时。 “Basic”列显示从操作码反汇编的指令,最后一个位置有“Source”列。
现在看看条件跳转如何将相对跳转值编码为16位(beq $8, $9
操作码为0x1109
,其他16位0x0004
为16位符号扩展值“多少跳“)。该值表示远离“当前位置”的指令数,其中当前是后续指令的地址,即
0x0040000c + 0x0004 * 4 = 0x0040001c = target address
* 4,因为在MIPS上,每条指令都是4字节长,每个字节的内存寻址工作,而不是每条指令。
下一个bne
也是如此,操作码本身为0x1509
,偏移为0xfffc
,即-4。 =>
0x00400010 + (-4) * 4 = 0x00400000
绝对跳转使用不同的编码,它是6位操作码0b000010xx
(xx是存储在第一个字节中的两位地址以及j
操作码,在本例中它们是零)然后是26b地址除以4 0x0100000
,因为每条指令必须从对齐的地址开始,因此编码两个最低有效位将是浪费,它们总是00
。 0x100000 * 4 = 0x00400000
...我太懒了,无法检查MIPS是如何工作的,但我认为j
定义位2-27,0-1是零,28-31是从当前复制的可能pc
?使CPU能够在完整的4GiB地址范围内工作,但是可能有一些特殊的方法如何在不同的“库”之间跳转(pc
的高4位))..我不确定,我从来没有做过代码对于MIPS,所以我没有阅读CPU规格。
无论如何,如果您说again:
位于0x10010020
,则可以重新计算所有这些内容,以便生成准备好在0x10010020
执行的生产函数代码(尽管j
pc
1}}会很棘手,你必须确定如何组成总地址,如果复制了高4位或者是什么)。
beq
用于计算目标地址也是1个指令“稍后”一个,因此真正的MIPS的正确代码将在add
之前具有0x0004
,但相对偏移仍然是{{1}} }。 :)简单呃?如果它对您没有意义,请检查MARS设置(默认情况下,延迟分支的模拟已关闭,以免混淆学生),并搜索谷歌以获得更好的解释。很好的小搞笑CPU,那是MIPS。 :)
答案 1 :(得分:1)
每个标签对应于内存中的唯一地址。因此,在您的示例中,并且与您所声明的内容一致,如果nop
指令存在于0x00400000,那么again
将对应于(不是点 - 在一秒钟内更多)指向同一地址。 / p>
标签可以存在于文本和数据段中。但是,在您的示例中,标签显示在.text:
细分中。因此,它表示指令的地址而不是变量。
以下是重要的区别:
标签是大多数ISA的一部分,使人们更轻松地编写程序集。但是,重要的是要记住汇编是不最终的代码形式。换句话说,在二进制表示中,您的标签将不再是标签。
所以,这将会发生:
汇编程序将识别与每个标签指令关联的内存地址。让我们保持运行的0x00400000示例。然后,在每个跳转指令中,它将获取该地址并使用它来替换操作码中的标签。 Poof ,没有更多的标签,绝对没有指针(这意味着我们会在内存中存储另一个存储内存地址的位置)。
当然,内存地址本身对应于示例中文本段中的一个点,因为它与指令匹配。
简单地说,标签的存在是为了让我们的生活更轻松。但是,一旦它们组装好,它们就会转换为它们标记的指令/变量的实际内存地址。
答案 2 :(得分:0)
标签到其对应地址的转换是由您使用的代码汇编器或MIPS模拟器完成的,例如,MARS是MIPS模拟器,因此MARS进行了转换。 MARS会为您找到标签的地址。