首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

嵌入式核心:從兩條匯編指令理解運行時地址與鏈接地址(ADR vs LDR 偽指令)

     編輯:關於C語言

嵌入式核心:從兩條匯編指令理解運行時地址與鏈接地址(ADR vs LDR 偽指令)

在 ARM 裸機開發(如 S3C2440/210)中,運行時地址與鏈接地址的區別是重定位、啟動代碼編寫的核心。本文通過反匯編分析 adr r0, _start 與 ldr r1, =_start 的機器碼差異,揭示 PC 指針在運行時與鏈接地址空間的雙重映射機制。

一、 四大核心概念

概念定義決定者
運行時地址起始位置晶片上電後首條指令執行位址晶片廠商(不可改)
鏈接地址起始位置鏈接腳本指定的代碼佈局基址程式設計師/鏈接腳本(可改)
運行時地址從運行時起始位置向上延伸的地址空間—
鏈接地址從鏈接地址起始位置向上延伸的地址空間—

例:S3C210 運行時基址 0xD0020010(iRAM),鏈接基址設為 0xD0024000(SDRAM)。

二、 兩條偽指令與反匯編對比

adr r0, _start   ; 偽指令:載入 _start 的運行時地址
ldr r1, =_start  ; 偽指令:載入 _start 的鏈接地址

反匯編結果(鏈接地址視角):

d002401c: e24f0024   sub r0, pc, #36   ; adr 反匯編:pc - 36
d0024020: e59f1048   ldr r1, [pc, #72] ; ldr 反匯編:從 [pc+72] 載入

關鍵差異:adr 直接運算 pc(運行時地址);ldr 訪問 [pc](鏈接地址處的字面池數值)。

三、 PC 指針的雙重身份

  • 讀取 pc(如 sub r0, pc, #36):獲得運行時地址(當前指令在物理記憶體的真實位址)。
  • 讀取 [pc](如 ldr r1, [pc, #72]):訪問鏈接地址空間的字面池,取出鏈接時計算好的絕對地址值。

四、 實測驗證

adr 驗證運行時地址:

  • 指令鏈接地址 0xD002401C,偏移 0x1C。
  • 運行時地址 = 運行時基址 + 偏移 = 0xD0020010 + 0x1C = 0xD002002C。
  • pc = 0xD002002C(ARM 管線 +8 已含指令內)。
  • pc - 36 = 0xD002002C - 0x24 = 0xD0020008?實測加 8(管線)得 0xD0020010 精準命中 _start 運行時基址。

ldr 驗證鏈接地址:

  • 指令鏈接地址 0xD0024020,字面池偏移 72 (0x48)。
  • [pc+72] = 0xD0024020 + 0x48 + 8 = 0xD0024070(字面池位址)。
  • 該位址存儲值 0xD0024000,即 _start 鏈接地址。雙重間接完美命中。

五、 重定位代碼片段

adr r0, _start      @ r0 = _start 運行時地址
ldr r1, =_start     @ r1 = _start 鏈接地址
cmp r0, r1
beq clean_bss       @ 相等無需重定位
copy_loop:
    ldr r3, [r0], #4 @ 從運行時地址讀
    str r3, [r1], #4 @ 寫入鏈接地址
    cmp r1, r2       @ r2 = bss_start(鏈接地址)
    bne copy_loop

此即經典「複製代碼段從運行時位置(iRAM)到鏈接位置(SDRAM)」的重定位邏輯。

六、 總結

  • adr = 短載入(運行時地址,相對 PC 計算,±4KB 範圍)。
  • ldr = = 長載入(鏈接地址,經字面池間接,全 32 位空間)。
  • PC 讀值 = 運行時地址;[PC] 取值 = 鏈接地址空間數值,是 ARM 裸機開發的核心認知。

掌握此機制,才能編寫正確的啟動代碼、散佈加載器、動態重定位邏輯。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved