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

ARM裸機啟動代碼分析:start.S BSS段清零與鏈接腳本詳解

     編輯:關於C語言

start.S 核心流程

ARM 裸機啟動代碼(`start.S`)執行順序:

  1. 異常向量表:`_start` 處設置分支指令跳轉至 `reset`,其他異常預留處理函數地址
  2. Reset 處理:
    • 保存現場(`push {fp, ip, lr, pc}`)
    • 設置幀指針 `fp`
    • 調用 `clr_bss` 清零 BSS 段
    • 調用 `entry` 進入 C 主函數
    • 棧空間預留(多次 `sub sp`)並恢復現場返回
  3. 中斷處理框架:SVC、IRQ、FIQ 等異常入口保存上下文、調用 C 處理函數、恢復返回
  4. BSS 清零實現(`clr_bss`):
    clr_bss:
        ldr r0, _bss_start    @ __bss_start 地址
        ldr r1, _bss_end      @ __bss_end 地址
        mov r2, #0
    forclrbss:
        cmp r0, r1
        bge endclrbss
        strb r2, [r0], #1     @ 逐字節清零,後增寻址
        b forclrbss
    endclrbss:
        ...

鏈接腳本 ld.lds 關鍵定義

OUTPUT_FORMAT("elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)

SECTIONS {
    . = 0x40008000;           @ 載入地址

    .text : {
        start.o(.text);       @ 啟動代碼優先
        *(.text);             @ 其餘代碼段
    }

    . = ALIGN(4);
    .data : { *(.data); }     @ 已初始化全局/靜態變量

    . = ALIGN(4);
    __bss_start = .;          @ BSS 起始標記(關鍵符號)
    .bss : { *(.bss); }       @ 未初始化全局/靜態變量
    __bss_end = .;            @ BSS 結束標記
}

關鍵符號關聯

符號定義位置用途
`__bss_start`鏈接腳本BSS 段起始地址,`start.S` 通過 `_bss_start` 訪問
`__bss_end`鏈接腳本BSS 段結束地址,`start.S` 通過 `_bss_end` 訪問
`_start`start.S程序入口,鏈接腳本 `ENTRY(_start)` 指定
`entry`C 代碼用戶主函數(如 `main`),啟動代碼 `bl entry` 調用

為什麼必須清零 BSS?

C 標準規定:靜態存儲期變量未顯式初始化時,默認初始化為 0。鏈接器不為 BSS 分配文件空間(僅記錄大小),加載器也不保證內存為零,因此啟動代碼必須在進入 `main` 前將 `__bss_start` 到 `__bss_end` 區間清零。

常見問題排查

  • 全局變量非零:檢查 `clr_bss` 是否被調用、地址符號是否匹配、鏈接腳本 BSS 定義是否正確
  • 大端/小端不匹配:`OUTPUT_FORMAT` 需與目標 CPU 一致
  • 棧溢出:啟動代碼預留棧空間(示例中連續 `sub sp` 共 1KB)需滿足中斷嵌套深度
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved