簡單例項講解linux的module模組編譯步驟
本文將直接了當的帶你進入linux的模組編譯。當然在介紹的過程當中,我也會新增一些必要的註釋,以便初學者能夠看懂。之所以要寫這篇文章,主要是因為從書本上學的話,可能要花更長的時間才能學會整個過程,因為看書的話是一個學習過程,而我這篇文章更像是一個培訓。所以實踐性和總結性更強。通過本文你將會學到編譯一個模組和模組makefile的基本知識。以及載入(解除安裝)模組,檢視系統訊息的一些知識;
第一步:準備原始碼
首先我們還是要來編寫一個符合linux格式的模組檔案,這樣我們才能開始我們的模組編譯。假設我們有一個原始檔mymod.c。它的原始碼如下:
mymod.c
#include #include #include MODULE_AUTHOR("Yu Qiang"); MODULE_LICENSE("GPL"); static int nbr = 10; module_param(nbr, int, S_IRUGO); static int __init yuer_init(void) { int i; for(i=0; i { printk(KERN_ALERT "Hello, How are you. %d\n", i); } return 0; } static void __exit yuer_exit(void) { printk(KERN_ALERT"I come from yuer's module, I have been unlad.\n"); } module_init(yuer_init); module_exit(yuer_exit);
我們的原始檔就準備的差不多了,這就是一個linux下的模組的基本結構。第9行是匯出我們的符號變數nbr。這樣在你載入這個模組的時候可以動態修改這個變數的值。稍後將演示。yuer_init()函式將在模組載入的時候執行,通過輸出的結果可以看到我們的模組是否載入成功。
第二步:編寫Makefile檔案
首先還是來看看我們Makefile的原始檔,然後我們再來解釋;
Makefile
obj-m :=modules.o #要生成的模組名 modules-objs:= mymod.o #生成這個模組名所需要的目標檔案 KDIR := /lib/modules/`uname -r`/build PWD := $(shell pwd) default: make -C $(KDIR) M=$(PWD) modules clean: rm -rf *.o .* .cmd *.ko *.mod.c .tmp_versions
現在我來說明一下這個Makefile。請記住是大寫的Makefile而不是小寫的makefile;
obj-m :這個變數是指定你要聲稱哪些模組模組的格式為 obj-m :=<模組名>.o
modules-objs:這個變數是說明聲稱模組modules需要的目標檔案 格式要求 <模組名>-objs := <目標檔案>
切記:模組的名字不能取與目標檔案相同的名字。如在這裡模組名不能取成 mymod;
KDIR :這是我們正在執行的作業系統核心編譯目錄。也就是編譯模組需要的環境
M= :指定我們原始檔的位置
PWD :這是當前工作路徑$(shell )是make的一個內建函式。用來執行shell命令。
第三步:編譯模組
現在我們已經準備好了我們所需要的原始檔和相應的Makefile。我們現在就可以編譯了。在終端進入原始檔目錄輸入make
執行結果:
make[1]: Entering directory `/usr/src/linux-headers-2.6.24-24-generic' CC [M] /home/yuqiang/桌面/mymodule/mymodules.o LD [M] /home/yuqiang/桌面/mymodule/modules.o Building modules, stage 2. MODPOST 1 modules CC /home/yuqiang/桌面/mymodule/modules.mod.o LD [M] /home/yuqiang/桌面/mymodule/modules.ko make[1]: Leaving directory `/usr/src/linux-headers-2.6.24-24-generic'
第四步:載入/解除安裝我們的模組
從上面的編譯中我可以看到。已經有一個modules.ko生成了。這就是我們的模組了。現在我們就可以來載入了。
首先在終端輸入:sudoinsmod modules.ko
現在我們來看看我們的模組載入成功沒有呢?
在終端輸入:dmesg| tail-12 這是檢視核心輸出資訊的意思。tail-12 顯示最後12條;
顯示結果如下:
[17945.024417] sd 9:0:0:0: Attached scsi generic sg2 type 0 [18046.790019] usb 5-8: USB disconnect, address 9 [19934.224812] Hello, How are you. 0 [19934.224817] Hello, How are you. 1 [19934.224818] Hello, How are you. 2 [19934.224820] Hello, How are you. 3 [19934.224821] Hello, How are you. 4 [19934.224822] Hello, How are you. 5 [19934.224824] Hello, How are you. 6 [19934.224825] Hello, How are you. 7 [19934.224826] Hello, How are you. 8 [19934.224828] Hello, How are you. 9
看到了吧。我們的模組的初始化函式yuer_init();已經成功運行了。說明我們的模組已經載入成功;
現在我們再來解除安裝模組試試看。
在終端輸入:sudormmod modules
在終端輸入:dmesg| tail -3
[19934.224826] Hello, How are you. 8 [19934.224828] Hello, How are you. 9 [20412.046932] I come from yuer's module, I have been unlad.
可以從列印的資訊中看到,我們的模組的退出函式已經被執行了。說明我們的模組已經被成功的解除安裝了。到目前位置我們就已經算是對模組的編譯到編譯執行算是有了一個整體上的認識了。對於以後深入的學習還是應該有點幫助的。下面我們將在看看於模組相關的一些簡單的操作。
第五步:載入模組時傳遞引數
在終端輸入:sudoinsmod module_name.ko nbr=4
在終端輸入:dmesg| tail -6
顯示結果如下:
[20800.655694] Hello, How are you. 9 [21318.675593] I come from onefile module, I have been unlad. [21334.425373] Hello, How are you. 0 [21334.425378] Hello, How are you. 1 [21334.425380] Hello, How are you. 2 [21334.425381] Hello, How are you. 3
這樣我們就可以看到在模組載入的時候動態設定了我們的一個變數。初始化函式中的迴圈只執行了4次。
可能你會問我怎麼知道一個模組可以設定那些變數呢。當然,你可以先不設變數載入一次。然後可以在終端輸入ls/sys/module//parameters/來檢視。在這裡我們是這樣輸入的
在終端輸入:ls/sys/moedle/modules/parameters/
顯示結果:
nbr
如果我們的模組載入成功了。最後我們還可以通過modinfo來檢視我們的模組資訊。如下
在終端輸入:sudomodinfo modules.ko
顯示結果:
filename: modules.ko license: GPL author: Yu Qiang srcversion: 20E9C3C4E02D130E6E92533 depends: vermagic: 2.6.24-24-generic SMP mod_unload 586 parm: nbr:int
本文總結:
本文的相關知識都好像有一點淺嘗轍止的感覺。因為本篇文章主要是通過一條線式方式來講解了模組編寫的相關過程,其實在這個過程中還有很多可以發散的地方。例如:
在寫到MODULE_AUTHOR("Yu Qiang")的時候,你應該想到還有
MODULE_DESCRIPTION(模組用途的簡單描述);
MODULE_VERSION(模組的版本字串);
MODULE_ALIAS(模組的別名);
...
在寫到module_param(nbr, int, S_IRUGO);的時候,你應該想到還有
EXPORT_SYMBOL(name); 可以匯出模組的函式,這也是模組編寫的最終目的
...
在用到insmod 和 modinfo的時候。你應該想到還有
depmod 分析可載入模組的依賴性,並生成modules.dep檔案和對映檔案
modprobe Linux核心新增刪除模組