contributed by < lintin528
>
看完這個教材後,剛開始有個粗淺的觀念:核心模組的掛載是為了在不重新編譯 kernel 的情況下加入新的功能。以下寫出各個節點所遇到的問題。
在第一步了解核心模組是如何被編譯的,在當前目錄新增了 hello.c
與 Makefile
,並且透過指令
$ make -C /lib/modules/`uname -r`/build M=`pwd` modules
完成編譯並產出 .ko
檔案,這邊可以看出是透過在 /lib/modules/
uname -r/build
目錄下的 Makefile
裡描述編譯操作,但就產出一個疑問,為何我需要建立在當前目錄的 Makefile
?
目前想出的解釋只有需要指定目標模組 obj-m
,以及可以寫一些自定義的規則,所以才需要在當前目錄建立 Makefile
。
之後以 fibdrv
為例去探討如何在 linux 核心中掛載模組,在看這部分內容時,其實一開始有點茫然,但看完之後可以大約總結為將每一個 MODULE_XXX
巨集分別透過 __UNIQUE_ID
產生一個獨特的名稱,並且從以下這一段
可以看出來,產出的名稱其實就是 tag 所對應到的標籤,如 author, license
等等,並且在之後的 __stringify(tag) "=" info
,將其內容轉換為 "操作 = 參數"
的這個形式後,透過
__used __attribute__((section(".modinfo"), unused, aligned(1)))
,在最後所產出的 ELF 格式 object file 中,將先前所生成的字串寫入對應的 .modinfo
section。然後去觀察使用 objdump
產出的內容資訊
在 .modinfo section
裡面的其中一小段,第一段 0010
為此段訊息的十六進制 offset
,代表該段數據的偏移量,後面的 76657273
其實是對應到該段文字的 ASCII 碼 , 76
對應到 v
, 65
對應到 e
,以此類推,至此就是編譯過程中是如何透過 MODULE_XXX
系列的巨集將 module 的資訊寫入此 object 檔案的過程。
下一部分在分析使用 insmod
時,是如何透過系統呼叫將編譯出的 kernel object (.ko) 檔案掛載進 linux 核心中,在最後的總結中可以看出 insmod
實際執行的系統呼叫中主要是透過
去配置記憶體空間以及加入初始化模組函數的起始位置,而細部觀察 finit_module
系統呼叫的實作,在最後呼叫 load_module
,且實際的記憶體配置就在裡面的 layout_and_allocate
,最後執行 do_init_module
,在其實作中的 ret = fn();
做實際的模組初始化,另外在讀取 .ko
檔案後事透過 do_init_module
函式實作中的 ret = do_one_initcall(mod->init);
去讀取透過 module_init
將使用者自己寫的 init funciton ,在此情況透過 finit_module
所執行的模組初始化就會更改為使用者自定義的 init_fib_dev
。