Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> Linux 教學

Linux 內核鏈接腳本 vmlinux.lds 格式詳解與架構適配

編輯:Linux 教學

vmlinux.lds 是 Linux 內核鏈接階段的核心腳本,定義內核映像的虛擬地址佈局、段屬性、符號邊界。位於 arch/<arch>/kernel/vmlinux.lds.S,通過預處理器生成最終 vmlinux.lds,再由鏈接器 ld 解析。本文以 ARM 架構為例,解析通用模板 asm-generic/vmlinux.lds.h 的宏定義與段組織邏輯。

一、 鏈接腳本核心結構

OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(stext)                    /* 內核入口點 */

SECTIONS
{
    . = TEXT_OFFSET;            /* 內核加載地址,ARM 通常 0x80008000 */
    
    /* ===== 初始化段(啟動後可釋放)===== */
    __init_begin = .;
    HEAD_TEXT_SECTION           /* head.S 入口代碼 */
    INIT_TEXT_SECTION(PAGE_SIZE)/* .text.init 初始化函數 */
    INIT_DATA_SECTION(...)      /* .data.init 初始化數據 */
    PERCPU(PAGE_SIZE)           /* per-CPU 變量 */
    __init_end = .;

    /* ===== 正文段(只讀代碼)===== */
    _stext = .;
    TEXT_SECTION = 0            /* .text 普通代碼 */
    _etext = .;

    /* ===== 數據段 ===== */
    _sdata = .;
    RO_DATA_SECTION(PAGE_SIZE)  /* .rodata 只讀數據 */
    RW_DATA_SECTION(...)        /* .data 可讀寫數據 */
    _edata = .;

    /* ===== 特殊段 ===== */
    EXCEPTION_TABLE(...)        /* 異常表 */
    NOTES                       /* 構建元數據 */

    /* ===== BSS 段(零初始化)===== */
    BSS_SECTION(0, 0, 0)
    _end = .;                   /* 內核映像結束地址 */

    /* ===== 調試信息 ===== */
    STABS_DEBUG
    DWARF_DEBUG

    /* ===== 丟棄段 ===== */
    DISCARDS                    /* 必須放最後:.exit.text, .comment 等 */
}

二、 關鍵宏定義(vmlinux.lds.h)

宏展開內容說明
HEAD_TEXT_SECTION*(.head.text)架構相關啟動代碼(head.S)
INIT_TEXT_SECTION(align)*(.init.text) *(.init.text.*)標記 __init 的函數,啟動後釋放
INIT_DATA_SECTION(align)*(.init.data) *(.init.data.*)標記 __initdata 的數據
PERCPU(align)*(.data.percpu)每 CPU 變量區
TEXT_SECTION*(.text) *(.text.*) *(.gnu.linkonce.t.*)常駐代碼段
RO_DATA_SECTION(align)*(.rodata) *(.rodata.*)只讀數據,映射為只讀頁
RW_DATA_SECTION(align)*(.data) *(.data.*)讀寫數據
BSS_SECTION(page, align, stop)*(.bss) *(.bss.*) COMMON零頁,運行時清零
DISCARDS*(.exit.text) *(.exit.data) *(.comment)鏈接後丟棄,不進入映像

三、 關鍵符號與地址邊界

  • __init_begin / __init_end:初始化段範圍,free_initmem() 釋放。
  • _stext / _etext:代碼段邊界,kallsyms、模塊加載器校驗用。
  • _sdata / _edata:已初始化數據段邊界。
  • _end:內核映像物理結束地址,啟動分配器起始位置。
  • __initramfs_start / __initramfs_end:內嵌 initramfs 範圍。
  • __nosave_begin / __nosave_end:休眠不保存內存區域。

四、 架構適配要點

  1. TEXT_OFFSET:內核加載物理地址。ARM 通常 0x80008000(物理 0x80000000 + 0x8000),x86 為 0x100000。
  2. PAGE_SIZE:頁大小對齊參數,ARM 4KB,某些架構 64KB/16KB。
  3. 輸出格式:OUTPUT_FORMAT 指定 ELF 類型(32/64 位、大小端)。
  4. 入口點:ENTRY(stext) 對應 arch/arm/kernel/head.S 入口標號。
  5. 模塊段:arch/arm/kernel/module.lds 定義模塊鏈接佈局。

五、 調試與驗證

# 查看生成的鏈接腳本
cat vmlinux.lds

# 反彙編驗證段分佈
objdump -h vmlinux | head -30

# 關鍵符號地址
nm vmlinux | grep -E '^(__init_begin|_stext|_end|_sdata)'

六、 常見問題

  • 段溢出:.text 超過架構限制(如 ARM 32MB),需調整 CONFIG_KERNEL_TEXT_OFFSET 或啟用 CONFIG_RELOCATABLE。
  • 對齊故障:PERCPU、RO_DATA 未按 PAGE_SIZE 對齊導致頁屬性衝突。
  • 符號缺失:__initcall_start 未正確收集,檢查 initcall 宏定義。
Copyright © Windows教程網 All Rights Reserved