为什么ARM汇编语言中的B 25或BEQ 25表示"go to PC + 8 + 100"
Why does B 25 or BEQ 25 in ARM assembly language mean "go to PC + 8 + 100"
我是初学者,我正在学习 32 位 ARM 作为我的计算机组织课程的一部分。 B 25
或 BEQ 25
的含义为 go-to PC + 8 + 100
。我明白 100
是什么意思。它是偏移量,因为 ARM 是字节寻址的,我们需要将程序计数器递增 25*4
。但是 +8
是什么意思?有人可以帮我解决这个问题吗?
当构建第一个 ARM CPU 时,他们尽可能简单。
最简单的设计(需要最少数量的晶体管)导致几乎 (*) 所有读取寄存器的指令的值 (当前指令的地址 + 8) r15
.
出于这个原因,指令ADD R15, R15, #100
(在那些旧的ARM CPUs上)将跳转到当前指令的地址加上108
。
为了与现有程序兼容,这在较新的 ARM CPUs 中没有改变。
(*) 顺便说一句:
对于某些指令,结果正式为(当前指令地址+12)。在较新的 ARM CPU 上,这些指令(例如 ADD r0, r15, r1, lsl r2
)在读取 r15
.
时会导致“不可预测的值”
所以确实有一些指令在第一个 ARM CPUs 上导致可预测的结果,而在现代 ARM CPUs 上不再导致可预测的结果。
可能出于真正的流水线原因,但今天为了反向兼容性,PC 是“领先的”。提前两条指令和 4+4 或 8 字节的全尺寸指令。想想获取、解码、执行,当你执行 pc 的时间提前了两个。
汇编语言特定于汇编器而非目标。 B 25 是该分支指令上的一个奇怪操作数,但根据您的问题,假设是指令中立即编码为单词单位。目标地址将是 PC(B 25 指令!!!)加 25*4 加 8。25 * 4 是因为每个字有 4 个字节。所以目标地址是指令的PC加100加8。
Disassembly of section .text:
00000000 <skip-0x24>:
0: e1a00000 nop ; (mov r0, r0)
4: e1a00000 nop ; (mov r0, r0)
8: e1a00000 nop ; (mov r0, r0)
c: e1a00000 nop ; (mov r0, r0)
10: ea000003 b 24 <skip>
14: e1a00000 nop ; (mov r0, r0)
18: e1a00000 nop ; (mov r0, r0)
1c: e1a00000 nop ; (mov r0, r0)
20: e1a00000 nop ; (mov r0, r0)
00000024 <skip>:
24: eafffffe b 24 <skip>
这里的编码:
10: ea000003 b 24 <skip>
显示 3 为立即数,指令地址为 0x10 所以
0x10 + (3*4) + 8 = 0x10+12+8= 0x10+20 = 0x10+0x14 = 0x24
这个负数编码为 0xFFFFFFFE 乘以 8 是 0xFFFFFFF8
24: eafffffe b 24 <skip>
所以 0x24 + 0xFFFFFFF8 + 8 = 0x24
请注意,反汇编中的 b 24 表示跳转至地址 0x24,而不是像您的问题所暗示的那样立即跳转到地址 25。
对于拇指模式,他们也提前两个,每条指令 16 位或两个字节,提前 4 个字节 2+2。
Disassembly of section .text:
00000000 <skip-0x12>:
0: 46c0 nop ; (mov r8, r8)
2: 46c0 nop ; (mov r8, r8)
4: 46c0 nop ; (mov r8, r8)
6: 46c0 nop ; (mov r8, r8)
8: e003 b.n 12 <skip>
a: 46c0 nop ; (mov r8, r8)
c: 46c0 nop ; (mov r8, r8)
e: 46c0 nop ; (mov r8, r8)
10: 46c0 nop ; (mov r8, r8)
00000012 <skip>:
12: e7fe b.n 12 <skip>
所以对于这个(每条指令两个字节,所以 3 * 2)
8: e003 b.n 12 <skip>
0x08 + (0x3<<1) + 4 = 0x08 + 0x6 + 4 = 0x12
其他指令集可能会在执行期间将 pc 伪造为指令的地址,或者您经常看到它指向下一条指令。这完全是任意的,就是这样,您的代码或机器代码偏移量必须符合架构。
简短的回答看看 acorn 文档,三级流水线,所以想着获取、解码、执行,所以当你执行 pc 时,它会提前获取两条指令。尽管管道更深,但非橡子 ARM 继续采用该方案。
说明 a、b、c、d(不是真正的说明,只是为了演示目的)
0x10 a
0x14 b
0x18 c
0x1C d
PC
0x10 fetch a
0x14 fetch b decode a
0x18 fetch c decode b execute a
0x1C fetch d decode c execute b
所以指令 a 位于地址 0x10 但当它执行时 pc 是 0x18。这是添加到编码中的 8 字节差异。
我是初学者,我正在学习 32 位 ARM 作为我的计算机组织课程的一部分。 B 25
或 BEQ 25
的含义为 go-to PC + 8 + 100
。我明白 100
是什么意思。它是偏移量,因为 ARM 是字节寻址的,我们需要将程序计数器递增 25*4
。但是 +8
是什么意思?有人可以帮我解决这个问题吗?
当构建第一个 ARM CPU 时,他们尽可能简单。
最简单的设计(需要最少数量的晶体管)导致几乎 (*) 所有读取寄存器的指令的值 (当前指令的地址 + 8) r15
.
出于这个原因,指令ADD R15, R15, #100
(在那些旧的ARM CPUs上)将跳转到当前指令的地址加上108
。
为了与现有程序兼容,这在较新的 ARM CPUs 中没有改变。
(*) 顺便说一句:
对于某些指令,结果正式为(当前指令地址+12)。在较新的 ARM CPU 上,这些指令(例如 ADD r0, r15, r1, lsl r2
)在读取 r15
.
所以确实有一些指令在第一个 ARM CPUs 上导致可预测的结果,而在现代 ARM CPUs 上不再导致可预测的结果。
可能出于真正的流水线原因,但今天为了反向兼容性,PC 是“领先的”。提前两条指令和 4+4 或 8 字节的全尺寸指令。想想获取、解码、执行,当你执行 pc 的时间提前了两个。
汇编语言特定于汇编器而非目标。 B 25 是该分支指令上的一个奇怪操作数,但根据您的问题,假设是指令中立即编码为单词单位。目标地址将是 PC(B 25 指令!!!)加 25*4 加 8。25 * 4 是因为每个字有 4 个字节。所以目标地址是指令的PC加100加8。
Disassembly of section .text:
00000000 <skip-0x24>:
0: e1a00000 nop ; (mov r0, r0)
4: e1a00000 nop ; (mov r0, r0)
8: e1a00000 nop ; (mov r0, r0)
c: e1a00000 nop ; (mov r0, r0)
10: ea000003 b 24 <skip>
14: e1a00000 nop ; (mov r0, r0)
18: e1a00000 nop ; (mov r0, r0)
1c: e1a00000 nop ; (mov r0, r0)
20: e1a00000 nop ; (mov r0, r0)
00000024 <skip>:
24: eafffffe b 24 <skip>
这里的编码:
10: ea000003 b 24 <skip>
显示 3 为立即数,指令地址为 0x10 所以
0x10 + (3*4) + 8 = 0x10+12+8= 0x10+20 = 0x10+0x14 = 0x24
这个负数编码为 0xFFFFFFFE 乘以 8 是 0xFFFFFFF8
24: eafffffe b 24 <skip>
所以 0x24 + 0xFFFFFFF8 + 8 = 0x24
请注意,反汇编中的 b 24 表示跳转至地址 0x24,而不是像您的问题所暗示的那样立即跳转到地址 25。
对于拇指模式,他们也提前两个,每条指令 16 位或两个字节,提前 4 个字节 2+2。
Disassembly of section .text:
00000000 <skip-0x12>:
0: 46c0 nop ; (mov r8, r8)
2: 46c0 nop ; (mov r8, r8)
4: 46c0 nop ; (mov r8, r8)
6: 46c0 nop ; (mov r8, r8)
8: e003 b.n 12 <skip>
a: 46c0 nop ; (mov r8, r8)
c: 46c0 nop ; (mov r8, r8)
e: 46c0 nop ; (mov r8, r8)
10: 46c0 nop ; (mov r8, r8)
00000012 <skip>:
12: e7fe b.n 12 <skip>
所以对于这个(每条指令两个字节,所以 3 * 2)
8: e003 b.n 12 <skip>
0x08 + (0x3<<1) + 4 = 0x08 + 0x6 + 4 = 0x12
其他指令集可能会在执行期间将 pc 伪造为指令的地址,或者您经常看到它指向下一条指令。这完全是任意的,就是这样,您的代码或机器代码偏移量必须符合架构。
简短的回答看看 acorn 文档,三级流水线,所以想着获取、解码、执行,所以当你执行 pc 时,它会提前获取两条指令。尽管管道更深,但非橡子 ARM 继续采用该方案。
说明 a、b、c、d(不是真正的说明,只是为了演示目的)
0x10 a
0x14 b
0x18 c
0x1C d
PC
0x10 fetch a
0x14 fetch b decode a
0x18 fetch c decode b execute a
0x1C fetch d decode c execute b
所以指令 a 位于地址 0x10 但当它执行时 pc 是 0x18。这是添加到编码中的 8 字节差异。