MIPS 分支而不是跳转
MIPS branch instead of jump
为什么要使用预定条件的分支,比如这样:
beq [=10=], [=10=], TEST
而不是像这样使用跳跃?
j TEST
分支用于测试条件,但在本例中,分支使用的条件始终为真。那么为什么要在跳跃上使用它呢?它以某种方式更快吗?
我遇到了这个 answer,但我不知道它是否确实是我问题的正确答案,因为我对搬迁一无所知。
J
指令编码如下:
----------------------------
| opcode | instr_index |
----------------------------
instr_index
是目标地址的最低有效 28 位,右移 2 位得到 26 位值。你最终跳转到的地址是 (PC & 0xF0000000) | (instr_index << 2)
BEQ
变体编码如下:
-----------------------------
| opcode | 0 | 0 | offset |
-----------------------------
你最终要跳转到的地址是 PC + sign_extend(offset << 2)
。
(注意,在这两种情况下,PC
是紧跟在 branch/jump 指令之后的指令地址,而不是 branch/jump 指令本身)。
现在,假设您有以下代码:
main:
j foo
nop
foo:
并且此代码原本打算加载到地址 0x00400024
。 foo
的地址将是 0x0040002c
,而 J
指令将被编码为 (2 << 26) | (0x0040002c >> 2)
= 0x0810000b
.
但随后您决定要重新定位此代码(将其复制到内存中的某个其他位置并在该位置执行)。假设您的代码现在正在 0x00410000
处执行。在这种情况下,我们希望 J
指令跳转到 0x00410008
,但它仍然会跳转到 0x0040002c
((0x00410004 & 0xF0000000) | (0x010000b << 2)
= 0x0040002c
)。
另一方面,如果您使用了 BEQ
,您将得到指令词 0x10000001
((4 << 26) | (4 >> 2)
)。即使代码被重新定位,您仍然会最终分支到正确的地址:0x00410004 + (1 << 2)
= 0x00410008
。
为什么要使用预定条件的分支,比如这样:
beq [=10=], [=10=], TEST
而不是像这样使用跳跃?
j TEST
分支用于测试条件,但在本例中,分支使用的条件始终为真。那么为什么要在跳跃上使用它呢?它以某种方式更快吗?
我遇到了这个 answer,但我不知道它是否确实是我问题的正确答案,因为我对搬迁一无所知。
J
指令编码如下:
----------------------------
| opcode | instr_index |
----------------------------
instr_index
是目标地址的最低有效 28 位,右移 2 位得到 26 位值。你最终跳转到的地址是 (PC & 0xF0000000) | (instr_index << 2)
BEQ
变体编码如下:
-----------------------------
| opcode | 0 | 0 | offset |
-----------------------------
你最终要跳转到的地址是 PC + sign_extend(offset << 2)
。
(注意,在这两种情况下,PC
是紧跟在 branch/jump 指令之后的指令地址,而不是 branch/jump 指令本身)。
现在,假设您有以下代码:
main:
j foo
nop
foo:
并且此代码原本打算加载到地址 0x00400024
。 foo
的地址将是 0x0040002c
,而 J
指令将被编码为 (2 << 26) | (0x0040002c >> 2)
= 0x0810000b
.
但随后您决定要重新定位此代码(将其复制到内存中的某个其他位置并在该位置执行)。假设您的代码现在正在 0x00410000
处执行。在这种情况下,我们希望 J
指令跳转到 0x00410008
,但它仍然会跳转到 0x0040002c
((0x00410004 & 0xF0000000) | (0x010000b << 2)
= 0x0040002c
)。
另一方面,如果您使用了 BEQ
,您将得到指令词 0x10000001
((4 << 26) | (4 >> 2)
)。即使代码被重新定位,您仍然会最终分支到正确的地址:0x00410004 + (1 << 2)
= 0x00410008
。