You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

关于ARM 32位架构中BL指令执行时PC未偏移8字节的疑问

关于ARM 32位架构中BL指令执行时PC未偏移8字节的疑问

我来帮你理清楚这个ARM 32位架构里BL指令的PC偏移问题,其实核心是要区分指令执行阶段的PC值BL指令分支地址计算的PC基准值这两个容易混淆的点:

首先先明确ARM 32位的流水线特性:平时我们说PC是当前指令地址+8,是因为ARM采用三级流水线(取指、译码、执行)——当一条指令处于执行阶段时,PC已经指向了当前指令之后的第2条指令(每条ARM指令4字节,所以+8)。但BL指令的分支地址计算逻辑,和这个常规执行阶段的PC偏移是两码事!

为什么BL跳转后PC是0xA00而不是0xA08?

BL指令的分支目标地址,是基于当前BL指令的地址+4作为基准来计算的,而不是执行阶段的PC(+8)。举个具体的例子:
假设你的BL指令本身在地址0x400,那它计算分支偏移时用的基准PC是0x400 + 4 = 0x404。如果要跳转到子例程的入口0xA00,那指令编码里的偏移量就是0xA00 - 0x404 = 0x5FC。当BL指令执行时,硬件会直接把这个计算出的目标地址0xA00加载到PC中——这是分支指令的本质:直接跳转到目标地址开始执行,所以PC就会是0xA00,而不会再加8。毕竟子例程的第一条指令就在0xA00,PC直接指向这里,流水线才能从正确的位置开始取指、译码、执行。

再说说LR寄存器存的0x404为什么是对的

你提到LR会存储返回地址0x404,这个完全正确。BL指令的另一个作用,就是把当前BL指令的下一条指令地址(也就是BL所在地址+4)存入LR。当子例程执行完后,只要把LR的值加载回PC,程序就能回到0x404继续执行后续指令。这和常规的PC+8偏移也不冲突:当回到0x404这条指令时,它进入执行阶段后,PC自然会变成0x404 + 8 = 0x40C,回到正常的流水线偏移逻辑里。

最后给你划两个关键的区分点,避免再混淆:

  • 常规指令执行阶段的PC:当前指令地址+8,这是流水线工作机制导致的
  • BL分支的目标地址计算:以当前BL指令地址+4为基准,执行时PC直接设为计算出的目标地址
  • LR存储的返回地址:固定是BL指令的下一条指令地址(BL地址+4),确保返回后程序流不会断

这样说应该就把你疑惑的点都讲透了吧😉

火山引擎 最新活动