【问题标题】:MIPS jump and branch instructions rangeMIPS 跳转和分支指令范围
【发布时间】:2016-07-26 08:26:36
【问题描述】:

我刚开始学习 MIPS,但我无法理解跳转和分支指令的范围。我知道 PC 可以跳跃和分支的“距离”有限制,但我不明白为什么。

还有两个具体问题,如果PC 的当前值为0x00000000,是否可以对随机地址进行 1 次跳转?如果PC 的当前值为0x00000600,是否可以对随机地址执行 1 BRANCH?

【问题讨论】:

标签: assembly mips machine-code


【解决方案1】:

MIPS 处理器使用固定大小的指令,其中每个指令字是一个字(即 4 字节 == 32 位)。所以只有这么多信息可以塞进这 4 个字节中。

J 和 JAL 指令使用 32 位中的 6 位来指定操作码。这留下了 26 位来指定目标地址。目标地址并没有直接在指令中指定(没有足够的位) - 相反,会发生这种情况:

  • 将目标地址的低 28 位右移 2 位,然后将 26 个最低有效位存储在指令字中。由于所有指令都必须字对齐,因此我们移出的两位将始终为零,因此我们不会丢失任何无法重新创建的信息。
  • 发生跳转时,将这26位左移2位,得到原来的28位,然后与J/JAL后面的指令地址的最高4位组合为形成一个 32 位地址。

这使得可以跳转到跳转指令所在的相同 256MB 范围 (2^28) 中的任何指令(或者如果启用了延迟分支;跳转到与该指令相同的 256MB 范围中的任何指令在延迟槽中)。


对于分支指令,有 16 位可用于指定目标地址。这些存储为相对于分支指令之后的指令的带符号偏移量(同样应用了两位移位,因为没有必要存储我们知道将始终为 0 的东西)。所以还原 2 个最低有效位后的实际偏移量是 18 位,然后将其符号扩展为 32 位,并添加到分支指令之后的指令地址。这使得在分支指令中可以分支到 +/-128kB。


考虑以下在地址 0x00400024 加载的代码:

main:
j foo
nop
foo:
b main
nop

j foo 指令编码为0x0810000b。 26 个最低有效位的值为0x10000b,左移 2 位后变为0x40002c。 j之后的指令地址的最高4位为零,因此目标地址变为(0 << 28) | 0x40002c,等于0x40002c,恰好是foo的地址。

b main 指令编码为0x0401fffd。 16 个最低有效位的值为0xfffd,左移 2 位后变为0x3fff4。将其符号扩展到 32 位给我们0xfffffff4。将其添加到 b 之后的指令地址时,我们得到 0x400030 + 0xfffffff4,它(截断为 32 位时)等于 0x400024,恰好是 main 的地址。


如果要跳转到某个任意地址,请将地址加载到寄存器中并使用jr 或jalr 指令跳转。

【讨论】:

  • 为什么要把指令地址即PC的最高4位加到(26位)的跳转地址上。就像这 4 个 sig 位意味着什么?为什么只有前 4 位。
  • @hsnsd:看我的回答:“发生跳转时,将这26位左移2位得到原来的28位,然后再与最高4位结合J/JAL 之后的指令的地址组成一个 32 位地址”。这就是指令的工作原理。
  • 关于你关于 jr 的最后一句话的问题。这是否意味着 JR 可以跳转到 7FFFFFFF16 以十六进制表示的最高内存地址,因为理论上我们可以跳转到指令指定的寄存器中的任何内容?
  • @curiousX:你可以用jr/jalr跳转到的最高地址是可以存储在寄存器中的最高值,在MIPS32上是0xFFFFFFFF。 jr 不会发生转移;该值按原样使用。当然,地址仍然必须是字对齐的(除非你有一个支持 MIPS16 的 CPU 并且你正在切换到 MIPS16 代码),所以程序员/编译器要确保只使用正确对齐的地址。
猜你喜欢
  • 2014-09-17
  • 1970-01-01
  • 2018-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-14
  • 2023-03-29
  • 1970-01-01
相关资源
最近更新 更多