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

KEIL ARM 編譯器 RW/ZI 段處理機制分析:未初始化全域變數歸屬探討

     編輯:關於C語言

ARM 編譯映像段結構

KEIL ARM 編譯器輸出映像包含三大段:

疑問案例:未初始化全域變數為何進入 RW?


int aaa;
int bbb;
int main() {
    aaa = 7;
    bbb = 8;
    return 0;
}

預期:aaa、bbb 未初始化 → 應屬 ZI 段(8 bytes)
實際:--bss_threshold=0 設定下,映像報告:


Program Size: Code=464 RO-data=268 RW-data=8 ZI-data=608

RW-data=8 表示 aaa、bbb 被放入 RW 段而非 ZI。

Map 檔案證據


符號表:
aaa  0x20000000  Data  4  main.o(.data)
bbb  0x20000004  Data  4  main.o(.data)

Execution Region RW_IRAM1 (Base: 0x20000000, Size: 0x268, Max: 0x1000, ABSOLUTE)
Base Addr    Size  Type  Attr  Idx  E  Section Name  Object
0x20000000   0x8   Data  RW    11       .data        main.o

確認兩變數位於 .data 區段(RW),而非 .bss(ZI)。

根因分析:--bss_threshold 機制

ARM 編譯器提供選項 --bss_threshold=size:

  • 預設值:非零(通常為 4 或 8 位元組)
  • 小於閾值的未初始化全域變數 → 歸入 RW (.data)
  • 大於等於閾值 → 歸入 ZI (.bss)

設計考量:極小變數放 RW 而非 ZI,可避免 .bss 段碎片化,提高存取效率(.data 通常靠近程式碼區,快取友善)。

驗證實驗


// 測試 1:大陣列(超過閾值)
int big_array[1000];  // 4000 bytes > 閾值 → 應進 ZI

// 測試 2:明確初始化為 0
int zero_var = 0;     // 標準 C 語意應進 ZI,但 KEIL 可能視為已初始化進 RW

// 測試 3:調整閾值
// --bss_threshold=0  // 強制所有未初始化進 ZI
// --bss_threshold=100 // 提高閾值

初始化非零全域變數同樣進 RW


int ccc = 5;  // 明確非零初始化 → 必須進 RW(需載入初值 5)

符合預期:.data 區段包含所有需載入初值的變數,無論初值為何。

對嵌入式開發的影響

段全稱內容屬性
RORead-Only程式碼、常數、唯讀資料可執行、唯讀
RWRead-Write已初始化非零全域/靜態變數可讀寫、需載入初值
ZIZero-Initialized未初始化或初始化為 0 的全域/靜態變數可讀寫、啟動時清零、無初值載入

最佳實踐建議

  1. 理解專案編譯選項:確認 --bss_threshold 設定值
  2. 大型緩衝區/陣列:自然落入 ZI,無需干預
  3. 關鍵小變數:若需確保 ZI,可改為 static int x = 0; 或調整閾值
  4. 記憶體受限系統:審視 RW 區大小,評估是否可將小變數合併或調整閾值
  5. 交叉編譯器差異:GCC 行為不同(通常未初始化全進 .bss),移植時注意

總結

  1. KEIL ARM 編譯器依 --bss_threshold 決定小型未初始化全域變數歸屬
  2. 預設閾值下,小變數(如單個 int)進 RW (.data) 而非 ZI (.bss)
  3. Map 檔 .data vs .bss 區段可確認變數實際歸屬
  4. 此機制為編譯器最佳化策略,非標準 C 語意強制
  5. 嵌入式開發者需理解此行為,準確評估 ROM/RAM 佔用
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
層面影響對策
RAM 使用統計RW+ZI = 總資料 RAM,但 RW 需儲存初值於 ROMMap 檔詳細分析
ROM 佔用RW 區初值佔用 ROM 空間大量小變數考慮合併結構體
啟動時間ZI 需清零,RW 需從 ROM 複製初值權衡閾值設定
除錯觀察變數地址分佈反映段歸屬熟悉 Map 檔閱讀