我对汇编语言还很陌生。我正在阅读关于MIPS架构的资料,但是我对跳转目标地址和分支目标地址以及如何计算它们感到困惑。
PC
是分支指令本身的地址。PC+4
是分支指令本身的结束,也是下一条指令的开始(在使用延迟槽的MIPS中,是分支延迟槽)。-2^15到+2^15-1
条指令之间。然而,这并不是真正的问题,因为大多数分支都是局部的。对于跳转指令,MIPS只有26位来确定跳转位置。在MIPS中,跳转是相对于PC的。与分支指令类似,立即跳转值需要对齐到字边界;因此,我们需要将26位地址乘以四。
再次逐步说明:
换句话说,用取指令的低26位左移两位的结果替换PC+4的低28位。
func:
slti $t0, $a0, 2
beq $t0, $zero, cont
ori $v0, $zero, 1
jr $ra
cont:
...
jal func
...
0x400000
- 请注意,该链接还包含了一个很好的解释过程)时也会给出。slti
指令将位于0x400000
,beq
指令将位于0x400004
等等。现在我们就快完成了!对于beq
指令,分支目标地址是cont
的地址(0x400010
),查看MIPS instruction reference,我们可以看到它被编码为相对于下一条指令的16位有符号立即数(除以4,因为所有指令都必须驻留在4字节对齐的地址上)。Current address of instruction + 4 = 0x400004 + 4 = 0x400008
Branch target = 0x400010
Difference = 0x400010 - 0x400008 = 0x8
To encode = Difference / 4 = 0x8 / 4 = 0x2 = 0b10
beq $t0, $zero, cont
的编码
0001 00ss ssst tttt iiii iiii iiii iiii
---------------------------------------
0001 0001 0000 0000 0000 0000 0000 0010
正如您所见,您可以在-0x1fffc .. 0x20000
字节范围内分支。如果由于某种原因,您需要跳转更远,您可以使用一个跳板(一个无条件跳转到实际目标的跳转,该跳转位于给定限制内)。
跳转目标地址与分支目标地址不同,它们使用绝对地址编码(再次除以4)。由于指令编码使用6位用于操作码,这只留下26位用于地址(实际上是28位,因为最后2位将为0),因此PC寄存器的4个最高有效位在形成地址时被使用(除非您打算跨越256 MB边界,否则不会有影响)。
回到上面的例子,jal func
的编码为:
Destination address = absolute address of func = 0x400000
Divided by 4 = 0x400000 / 4 = 0x100000
Lower 26 bits = 0x100000 & 0x03ffffff = 0x100000 = 0b100000000000000000000
0000 11ii iiii iiii iiii iiii iiii iiii
---------------------------------------
0000 1100 0001 0000 0000 0000 0000 0000
slti
,因此我在这里将其更改为slt
):00400000: <func> ; <input:0> func:
00400000: 0000002a ; <input:1> slt $t0, $a0, 2
00400004: 11000002 ; <input:2> beq $t0, $zero, cont
00400008: 34020001 ; <input:3> ori $v0, $zero, 1
0040000c: 03e00008 ; <input:4> jr $ra
00400010: <cont> ; <input:5> cont:
00400010: 0c100000 ; <input:7> jal func
slti
)感兴趣,可以随时向 https://github.com/alanhogan/online-mips-assembler 提交拉取请求。请注意,翻译尽力保持内容原意,同时使语言更加通俗易懂,不包含解释或其他额外信息。 - Alan H.对于像这样的小函数,您可以手动计算从分支指令下面的指令到目标的跳数。如果它向后分支,则将该跳数变为负数。如果该数字不需要所有16位,则对于跳数最高有效位左侧的每个数字,使它们成为1,如果跳数为正,则使它们全部为0。由于大多数分支都靠近它们的目标,因此在大多数情况下,这可以节省您很多额外的算术运算。
我认为计算这些会相当困难,因为分支目标地址是在运行时确定的,并且该预测是由硬件完成的。如果您能更深入地解释问题并描述您正在尝试做什么,那么帮助您会更容易一些。(:
jr
。除非你很傻并将跳转到下一条指令视为未被执行情况的目标地址。 - Peter Cordes
b
一样设计j
是相对的,但它没有。这是一个相当任意的选择,尽管从现代的角度来看,这是一个不幸的选择,因为位置无关代码不能使用j
,而b
的范围有限。 - Peter Cordes