PC 指針為何不等于執行地址?
ARM 嵌入式開發中,直接讀 PC(R15)獲取"當前執行指令地址"必出錯——執行地址0x08000100時,PC 可能是0x08000104(Cortex-M3/M4)或0x08000108(經典 ARM)。核心原因只有兩個:流水線并行執行與架構規范固化,以下聚焦 Cortex-M3/M4講(jiang)透關鍵。
一、先明確兩個核心概念
- 執行地址:CPU 當前正在"執行(Execute)"的指令地址(如正在運算的
ADD指令地址) - PC 指針:CPU 下一個要"取指(Fetch)"的指令地址(告訴 CPU 下條指令在哪)
PC 天然指向"執(zhi)行地址的后面",差異僅(jin)在于偏移多少——由流水線和(he)架(jia)構決定。
二、根本原因:流水線 + 架構規范
1. 流水線機制:并行執行的必然結果
ARM 用 3 級流水線(取指→譯碼→執行)實現指令并行:當指令 A(執行地址)在執行時,指令 B 在譯碼,指令 C 在取指,PC 此時指(zhi)向指(zhi)令 C 的地址。
例:經典 ARM(32 位指令)中,執行地址0x00(A)→ PC0x08(C),偏(pian)移 +8;但 Cortex-M3/M4 有(you)額(e)外(wai)規范。
2. 架構規范:Cortex-M3/M4 的"強制偏移"
Cortex-M3/M4 僅支持 Thumb/Thumb-2 指令集(16/32 位指令),ARMv7-M 架構強制規定:無論指令是 16 位還是 32 位,PC = 執行地址 + 4。
- 執行 16 位指令(地址
0x00)→ PC0x04 - 執行 32 位指令(地址
0x00)→ PC0x04
目的是(shi)簡(jian)化開發:無需判斷指令長(chang)度,偏移規則統一。
三、Cortex-M3/M4 實戰:正確獲取執行地址
1. 手動計算:PC - 4
因PC = 執行地址 + 4,減 4 即得(de)真實執行地址(zhi):
; 獲取當前執行地址,存入R0
GetCurrentAddr:
MRS R0, PC ; R0 = PC(執行地址+4)
SUB R0, R0, #4 ; R0 = 執行地址(正確)
BX LR
2. 用偽指令:避免手動算偏移
日常開發優先用ADR/LDR =label,編譯器自動處理 PC 偏移:
ADR R0, DataBuf ; 短距離:自動生成PC相對尋址(修正偏移)
LDR R1, =ConfigAddr ; 長距離:從字面池讀地址(無需關心PC)
DataBuf: DCD 0x11223344
ConfigAddr: DCD 0x00001234
四、3 個必避誤區
- 誤區 1:按指令長度算偏移(16 位 +2、32 位 +4)→ 錯!Cortex-M 強制 +4
- 誤區 2:混用架構規則(把經典 ARM 的 +8 套到 Cortex-M)→ 錯!Cortex-M 只 +4
- 誤區 3:手動算偏移不用偽指令→ 錯!
ADR/LDR =label更穩定,避免代碼修改后偏移失效
五、總結
PC≠執(zhi)行地址,是 ARM"效率(lv)(流水線并行)"與"易(yi)用性(架(jia)構規(gui)范)"的(de)平衡結果。對(dui) Cortex-M3/M4 開(kai)發者,只需記(ji)住(zhu):
PC = 執行地址 + 4- 獲取執行地址用
PC-4 - 日常用偽指令處理地址
無需深究(jiu)流水線細節(jie),按規則用即(ji)可。
