为什么ARM PC寄存器指向下一个要执行的指令后?

时间:2014-06-06 22:29:00

标签: assembly arm

根据ARM IC。

  

在ARM状态下,PC的值是当前指令的地址加上8个字节。

     

在Thumb状态:

     
      
  • 对于B,BL,CBNZ和CBZ指令,PC的值是当前指令的地址加上4个字节。
  •   
  • 对于使用标签的所有其他指令,PC的值是当前指令的地址加上4个字节,结果的位[1]清零,使其字对齐。
  •   

简单地说,PC寄存器的值指向下一条指令后的指令。这是我没有得到的。通常(特别是在x86上)程序计数器寄存器用于指向要执行的下一条指令的地址。

那么,基础是什么?有条件执行,也许?

2 个答案:

答案 0 :(得分:49)

这是一个令人遗憾的遗留抽象泄漏。

最初的ARM设计有一个3级流水线(fetch-decode-execute)。为了简化设计,他们选择将PC读取为当前指令获取地址线上的值,而不是2个周期前当前正在执行的指令的值。由于大多数PC相关地址是在链接时计算的,因此装配器/链接器更容易补偿该2指令偏移量,而不是设计所有逻辑以“校正”PC寄存器。

当然,这一切都坚定地依赖于“30年前有意义的事情”。现在想象一下如何在今天的15个阶段,多个问题,无序管道中保持一个有意义的价值,你可能会理解为什么现在很难找到一个CPU设计师,他们认为将PC暴露在注册是一个好主意。

然而,在好的方面,至少它并不像delay slots那么可怕。相反,与您的假设相反,让每条指令有条件地执行实际上只是围绕该预取偏移的另一种优化。在分支条件代码(或者仍然像管道疯狂的人一样执行管道中的任何内容)时,不必总是必须采取管道刷新延迟,而是可以完全避免非常短的分支;管道保持繁忙,当标志与 * 不匹配时,解码的指令可以作为NOP执行。同样,这些天我们有了有效的分支预测器,它最终成为一个障碍而不是帮助,但1985年它很酷。

* "...the instruction set with the most NOPs on the planet."

答案 1 :(得分:1)

这是真的......

下面是一个例子: C程序:

int f,g,y;//global variables
int sum(int a, int b){
     return (a+b);
}
int main(void){
    f = 2;
    g = 3;
    y = sum(f, g);
    return y;
}

编译为程序集:

    00008390 <sum>:
int sum(int a, int b) {
return (a + b);
}
    8390: e0800001 add r0, r0, r1
    8394: e12fff1e bx lr
    00008398 <main>:
int f, g, y; // global variables
int sum(int a, int b);
int main(void) {
    8398: e92d4008 push {r3, lr}
f = 2;
    839c: e3a00002 mov r0, #2
    83a0: e59f301c ldr r3, [pc, #28] ; 83c4 <main+0x2c> 
    83a4: e5830000 str r0, [r3]
g = 3;
    83a8: e3a01003 mov r1, #3
    83ac: e59f3014 ldr r3, [pc, #20] ; 83c8 <main+0x30>
    83b0: e5831000 str r1, [r3]
y = sum(f,g);
    83b4: ebfffff5 bl 8390 <sum>
    83b8: e59f300c ldr r3, [pc, #12] ; 83cc <main+0x34>
    83bc: e5830000 str r0, [r3]
return y;
}
83c0: e8bd8008 pop {r3, pc}
83c4: 00010570 .word 0x00010570
83c8: 00010574 .word 0x00010574
83cc: 00010578 .word 0x00010578

查看上述LDR的PC值 - 这里用于将变量f,g,y的地址加载到r3。

    83a0: e59f301c ldr r3, [pc, #28];83c4 main+0x2c
    PC=0x83c4-28=0x83a8-0x1C = 0x83a8

PC的值只是当前正在执行的指令的下一条指令。因为ARM使用32位指令,但它使用字节地址,所以+ 8表示8字节,两个指令&#39;长度。

如此附加的ARM archi的5阶段管道获取,解码,执行,内存,回写

ARM's 5 stage pipeline

PC寄存器每个时钟加4,所以当指令冒泡执行时 - 当前指令,PC寄存器已经通过了2个时钟!现在它是+ 8.这实际上意味着:PC指向&#34; fetch&#34;指令,当前指令意味着&#34;执行&#34;指令,所以PC意味着下一个要执行的。

顺便说一句: 该图片来自Harris的数字设计和计算机体系结构ARM版

一书