Assembly 如何计算跳转目标地址和分支目标地址?
我不熟悉汇编语言。我正在阅读有关MIPS体系结构的书籍,我一直在学习跳目标地址和分支目标地址,以及如何计算它们。用硬件完成。如果你能更深入地解释一下这个问题,并描述一下你正在尝试做什么,那么会更容易得到帮助。(:通常您不必担心计算它们,因为您的汇编程序(或链接器)将需要正确计算。假设您有一个小函数:Assembly 如何计算跳转目标地址和分支目标地址?,assembly,mips,machine-code,Assembly,Mips,Machine Code,我不熟悉汇编语言。我正在阅读有关MIPS体系结构的书籍,我一直在学习跳目标地址和分支目标地址,以及如何计算它们。用硬件完成。如果你能更深入地解释一下这个问题,并描述一下你正在尝试做什么,那么会更容易得到帮助。(:通常您不必担心计算它们,因为您的汇编程序(或链接器)将需要正确计算。假设您有一个小函数: func: slti $t0, $a0, 2 beq $t0, $zero, cont ori $v0, $zero, 1 jr $ra cont: ... jal fun
func:
slti $t0, $a0, 2
beq $t0, $zero, cont
ori $v0, $zero, 1
jr $ra
cont:
...
jal func
...
当将上述代码转换成二进制指令流时,汇编器(或链接器,如果您第一次组装成一个对象文件),它将确定函数将驻留在内存中的什么位置(现在我们忽略位置无关的代码)。它将驻留在内存中的位置通常在ABI中指定,或者在您使用模拟器时提供给您(例如,在-注意,链接中还包含对该过程的良好解释)
假设我们讨论的是SPIM案例,我们的函数是内存中的第一个,那么slti
指令将位于0x400000
,beq
位于0x400004
等等。现在我们差不多到了!对于beq
指令,分支目标地址是cont
(0x400010
)查看a,我们看到它被编码为相对于下一条指令的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
如您所见,您可以在-0x1ffc..0x20000
字节内进行分支。如果出于某种原因,您需要进一步跳转,您可以使用蹦床(无条件跳转到给定限制内的实际目标)
与分支目标地址不同,跳转目标地址使用绝对地址(再次除以4)进行编码。由于指令编码使用6位作为操作码,因此地址只剩下26位(如果最后2位为0,则有效为28位)因此,在形成地址时使用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:
00400000:0000002a;slt$t0,$a0,2
00400004:11000002;贝币$t0,$0,续
00400008:34020001;ori$v0,$0,1
0040000c:03e00008;jr$ra
00400010:;续:
00400010:0c100000;日本航空公司
(在下面的图表和文本中,PC
是分支指令本身的地址。PC+4
是分支指令本身的结束和分支延迟槽的开始。绝对跳转图中除外。)
1.分支地址计算
在MIPS中,分支指令只有16位偏移量来确定下一条指令。我们需要将一个寄存器添加到这个16位值来确定下一条指令,而这个寄存器实际上是由体系结构暗示的。它是PC寄存器,因为PC在获取周期中得到更新(PC+4),所以它保存下一条指令的地址
我们还将分支距离限制为分支指令后的指令的-2^15到+2^15-1
指令。但是,这不是真正的问题,因为大多数分支都是本地的
所以一步一步:
- 符号扩展16位偏移值以保留其值
- 将结果值乘以4。这背后的原因是,如果我们要分支某个地址,而PC已经是字对齐的,那么立即值也必须是字对齐的。然而,使立即字对齐是没有意义的,因为强制它们为00会浪费低两位
- 现在我们有一个32位的相对偏移量。将这个值添加到PC+4,这就是您的分支地址
2.跳转地址计算 对于跳转指令,MIPS只有26位来确定跳转位置。在MIPS中,跳转与PC有关。与分支一样,立即跳转值需要字对齐;因此,我们需要将26位地址乘以4 再次一步一步:
- 将26位值乘以4
- 因为我们是相对于PC+4值跳转的,所以将PC+4值的前四位连接到跳转地址的左侧
- 结果地址是跳转值
来源:Bilkent University CS 224课程幻灯片对于这样的小函数,您可以手动计算从分支指令下的指令到目标的跳数。如果它向后分支,则使该跳数为负数。如果该数不为负数
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