讀Kernel感悟-Linux核心啟動-連結指令碼

來源:互聯網
上載者:User

文章來源:http://www.top-e.org/jiaoshi/class/

一般來說,使用者是不需要關心section的具體位置的。在使用者態,核心會解析elf可執行檔的各個section,然後把它映射到虛擬位址空間。然而,在核心啟動時,一切得從零開始。很多在使用者態下應用程式不需要操心的東西,例如映射section的任務不得不由核心自己來完成。上一篇感悟揭示了核心如何建立頁表,並且把自身的一部分映射到虛擬位址。核心還要負責對BSS段(所有在代碼中未定義的全域變數)的初始化(設定為0),這就要求核心知道section的具體位置(否則如何知道該映射哪一部分呢?)

此外,在開啟頁面映射的過程中,我最為疑惑的是幾個常量(頁目錄swapper_pg_dir,頁表pg0等等)是如何確定的。擴充一下。gcc連結可執行檔時,是如何確定變數的地址的?按理說應該有某種途徑(命令列參數或者檔案)告訴連結器ld如何定位這些變數。最普通如hello world。為什麼_start的地址是0x80482e0?於是想到,我們需要一個檔案來指定各個section的虛擬位址。在核心原始碼裡,還看到這個檔案arch/i386/kernel/vmlinux.lds.S。不像是普通的彙編檔案。原來這就是linker scripts連結器指令碼。

在連結器指令碼中,.表示當前location counter地址計數器的值。預設為0。

017   . = __KERNEL_START;

表示地址計數器從__KERNEL_START(0xc00100000)開始。

.text:{...}

表示.text section包含了哪幾個section

031   . = ALIGN(16);

則表示對齊。

具體格式可以調用info ld查看Linker Scripts一節。

連結器指令碼指定了各個section的起始位置和結束位置。它還允許程式員在指令碼中對變數進行賦值。這使核心可以通過__initcall_start和__initcall_end之類的變數獲得段的起始地址和結束位址,從而對某些段進行操作。

根據連結器指令碼,以及nm vmlinux的結果,核心中各個section的虛擬位址就很清楚了。以我的機子為例(粗略):

地址分配

text section:

從_text:c0100000 A _text

到_etext:c0436573 A _etext

Exception table

從__start___ex_table:c0436580 A __start___ex_table

到__stop___ex_table:c04370b8 A __stop___ex_table

RODATA read only section

.data writable section

.data_nosave section

從__nosave_begin:c050f000 A __nosave_begin

到__nosave_end:c050f000 A __nosave_end

.data.page_aligned section

.data.cacheline_aligned section

.data.read_mostly section

.data.init_task section

init section

從__init_begin c0514000 A __init_begin

到__init_end c0540000 A __init_end

其中.initcall.init section:

從__initcall_start:c053b570 A __initcall_start

到__initcall_end:c053b8c0 A __initcall_end

BSS section

從__bss_start c0540000 A __bss_start

到__bss_end c0594c78 A __bss_stop

其中 swapper進程的頁表

從c0540000 B swapper_pg_dir

到c0541000

共一頁

empty_zero_page

從c0541000 B empty_zero_page

到c0542000

共一頁

pg0 頁目錄0

從c0595000 A pg0

到init_pg_tables_end

.exitcall.exit

 section

stab section

幾個比較重要的section:

bss section,存放在代碼裡未初始化的全域變數,最後初始化為0。

init sections,所有只在初始化時調用的函數和變數,包括所有在核心啟動時調用的函數,以及核心模組初始化時調用的函數。其中最特別的是.initcall.init section。通過__initcall_start和__initcall_end,核心可以調用裡面所有的函數。這些section在使用一次後就可以釋放,從而節省記憶體。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.