MIPS汇编中的跳转指令

nod*_*nja 7 assembly mips

这是我为测试跳转指令而编写的一些MIPS汇编代码:

addi $a0, $0, 1
j next
next:
j skip1
add $a0, $a0, $a0
skip1:
j skip2:
add $a0, $a0, $a0
add $a0, $a0, $a0
skip2:
j skip3
loop:
add $a0, $a0, $a0
add $a0, $a0, $a0
add $a0, $a0, $a0
skip3:
j loop
Run Code Online (Sandbox Code Playgroud)

当我运行汇编程序时,结果如下:

[0x000000]  0x20040001  # addi $a0, $zero, 1 ($a0 = 1)
[0x000004]  0x08000002  # j 0x0002 (jump to addr 0x0008)
[0x000008]  0x08000004  # j 0x0004 (jump to addr 0x0010)
[0x00000C]  0x00842020  # add $a0, $a0, $a0 ($a0 = $a0 + $a0)
[0x000010]  0x08000007  # j 0x0007 (jump to addr 0x001C)
[0x000014]  0x00842020  # add $a0, $a0, $a0 ($a0 = $a0 + $a0)
[0x000018]  0x00842020  # add $a0, $a0, $a0 ($a0 = $a0 + $a0)
[0x00001C]  0x0800000B  # j 0x000B (jump to addr 0x002C)
[0x000020]  0x00842020  # add $a0, $a0, $a0 ($a0 = $a0 + $a0)
[0x000024]  0x00842020  # add $a0, $a0, $a0 ($a0 = $a0 + $a0)
[0x000028]  0x00842020  # add $a0, $a0, $a0 ($a0 = $a0 + $a0)
[0x00002C]  0x08000008  # j 0x0008 (jump to addr 0x0020)
Run Code Online (Sandbox Code Playgroud)

查看跳转指令的机器代码,这就是我所看到的:

1st jump (just jumps to next instruction) 0x08000002
2nd jump (skips 1 instruction) 0x08000004
3rd jump (skips 2 instructions) 0x08000007
4th jump (skips 3 instructions) 0x0800000B
5th jump (skips 3 instructions backwards) 0x08000008
Run Code Online (Sandbox Code Playgroud)

通过查看这些指令,看起来机器代码以跳转指令的08开头,最后的数字告诉跳转指令去哪里.但是,我无法弄清楚这个数字是如何计算出来的.此外,没有什么可以向我表明第五跳是向后跳跃.

如何计算跳跃值?

flo*_*olo 15

请查看参考手册,了解有关操作码编码的更多详细信息.

短版本:在32位指令中,不能包含32位跳转目标.操作码使用6位,为指令留下26位.通过取指令后面的j指令地址的前4位构造目标地址,然后将2个零位附加到跳转指令操作数的26位.(由于指令是32位,对齐很有用,允许省略最后两个0.)

向后跳转:地址是绝对的,不是相对的,所以它只取决于跳转指令的地址,无论是向前跳跃还是向后跳转.

编辑:更详细的描述:我们在地址x跳转指令j.设t代表j的跳跃操作数.t是26位宽.下一条指令的地址位模式计算如下:

upper_6_bits_of(x+4),t,0,0
Run Code Online (Sandbox Code Playgroud)

所以跳跃总是绝对的.没有相对跳跃.当结果小于x然后它是向后跳跃,当它更大时它是向前跳跃(并且如果你想要一些愚蠢的东西,你使它相等;-).

那么让我们来看看你的例子的第5跳:

跳转目标的前6位是:000000,因为跳转后面的指令的地址的高6位是000000.

接下来的26位是跳转指令的最低26位,即00000000000000000000001000

最后2位是:00,因为始终附加.

我们一起有:0000000000000000000000000000100000,它是十六进制20.并且在该地址正是流应该继续的标签/指令.

  • @Michael Dorgan:向后跳跃很好:它显示为...... 08.那个08左移两个(我提到的两个2个零)是32,它是十六进制0x20.跳转的指令是0x..20.所以它非常适合(与其他4次跳跃相同). (2认同)
  • @ z-buffer:是的(除了6个最高位). (2认同)

nin*_*alj 6

在MIPS中,J是一个J型指令:

J-type instructions (Jumps)
3    22
1    65                        0
+----+-------------------------+
| op |         target          |
+----+-------------------------+
Run Code Online (Sandbox Code Playgroud)

所以我们有一个target26位长.它与下一条指令的PC结合如下:

I
I+1 PC <- (PC & 0xf0000000) | (target << 2)
Run Code Online (Sandbox Code Playgroud)

它向左移2位,因为MIPS指令(忽略MIPS16扩展)是32位长,这意味着它们都从低2位为零的地址开始.