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

浙公網安備 33010602011771號