PC 指針為何(he)不(bu)等于執行地(di)址?
ARM 嵌入式開發中,直接讀 PC(R15)獲取"當前執行指令地址"必出錯——執行地址0x08000100時,PC 可能是0x08000104(Cortex-M3/M4)或0x08000108(經典 ARM)。核心原因只有兩個:流水線并行執行與架構規范固化,以下聚焦 Cortex-M3/M4講透關鍵。
一、先明確兩個核心概念
- 執行地址:CPU 當前正在"執行(Execute)"的指令地址(如正在運算的
ADD指令地址) - PC 指針:CPU 下一個要"取指(Fetch)"的指令地址(告訴 CPU 下條指令在哪)
PC 天然指向"執行(xing)地址的(de)后(hou)面",差異僅在于偏移多少——由流(liu)水線和(he)架構決(jue)定。
二、根本原因:流水線 + 架構規范
1. 流水線機制:并行執行的必然結果
ARM 用 3 級流水線(取指→譯碼→執行)實現指令并行:當指令 A(執行地址)在執行時,指令 B 在譯碼,指令 C 在取指,PC 此時指向指令(ling) C 的地址。
例:經典 ARM(32 位指令)中,執行地址0x00(A)→ PC0x08(C),偏移 +8;但 Cortex-M3/M4 有額(e)外(wai)規(gui)范。
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)簡化(hua)開(kai)發:無需判斷指令長度,偏移規則(ze)統(tong)一。
三、Cortex-M3/M4 實戰:正確獲取執行地址
1. 手動計算:PC - 4
因PC = 執行地址 + 4,減(jian) 4 即得真實(shi)執行(xing)地址:
; 獲取當前執行地址,存入R0
GetCurrentAddr:
MRS R0, PC ; R0 = PC(執行地址+4)
SUB R0, R0, #4 ; R0 = 執行地址(正確)
BX LR
2. 用偽指令:避免手動算偏移
日常開發優先用ADR/LDR =label,編(bian)譯器自動處理(li) 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)行(xing)地址(zhi),是 ARM"效率(lv)(流水線并行(xing))"與"易(yi)用性(xing)(架(jia)構(gou)規(gui)范)"的(de)平衡結果(guo)。對 Cortex-M3/M4 開發者,只需記住:
PC = 執行地址 + 4- 獲取執行地址用
PC-4 - 日常用偽指令處理地址
無需深(shen)究(jiu)流水線細節,按規則用即可。
