1. 程式人生 > >模組的作用及模組Makefile的解析

模組的作用及模組Makefile的解析

在學習編寫Linux核心模組的時候我們首先要清楚的知道核心模組的作用,為什麼要使用核心模組?這是因為Linux核心的整體結構非常的龐大,包含的元件也非常的多,把所有的核心模組都編譯到Linux核心,會導致的問題是核心很大,同時在現有的核心新增或刪除部分功能時,不得不重新編譯核心,可謂相當的費時。而模組的使用就是為了解決這一問題,即動態的在核心中新增或者刪除相應功能。下面以一個經典的程式碼來看是相關的分析:
 
#include
#include

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("xxx");
MODULE_DESCRIPTION("Hello World Module");
MODULE_ALIAS("a simplest module");
 
static int __init hello_init()
{
    printk(KERN_EMERG"Hello World!\n");  //注意比較兩種printk( )引數的不同之處
    return 0;                                                     //即優先順序的用法
}
 
static void __exit hello_exit()
{
    printk("<6>hello exit\n");
}
 
module_init(hello_init);
module_exit(hello_exit);
在閱讀相關的程式碼時我們的入口點不再是main( )函式,而應該是module_init( 函式名 )函式;細心的話就會發現在hello_init()函式前面有一個__init ,它的作用是在連線的時候把標識的函式放在 .init.text這個區段內。此外所有的__init函式在區段 .initcall.init中還儲存了一個函式指標,在初始化的時候核心會通過這些函式指標呼叫這些__init 函式,在完成初始化後釋放掉該區段。
 
printk( )函式和平printf( )函式類似,但是printk( )函式有列印優先順序(數值越低,優先順序越高),如果這個列印優先順序比預設的低,那麼將看不到輸出,所以在使載入和解除安裝模組的過程中如果看不到列印語句,這是一個值得分析的問題。檢視預設優先順序的語句為:cat    /proc/sys/kenel/printk
 
在程式碼的起始部分我們給出瞭如下程式碼:
 
1.  MODULE_LICENSE("Dual BSD/GPL");
2.  MODULE_AUTHOR("xxx");
3.  MODULE_DESCRIPTION("Hello World Module");
4.  MODULE_ALIAS("a simplest module");
 
1.為必須選擇的語句,它是模組的許可許可權,如果不宣告,會出現警告資訊。
 
2.3.4為可選項,其為模組的一些相關資訊。如作者、實現的功能等。
 
最後自然到了module_exit(hello_exit),有載入必須要有解除安裝,呵呵……做事要有始有終嘛,所以這自然就是相關的解除安裝部分了。其中的printk( )和前面的分析完全一樣。
 
外加一點,如果模組有引數的傳遞,那麼還需使用module_param(引數名,引數型別,引數的讀/寫許可權),當引數為陣列時,使用module_param_array(陣列名,陣列型別,陣列長,引數讀/寫許可權)。
 
懂了模組的編寫,接下來就應該是模組的編譯了,在當前路徑下建立一個Makefile檔案,編寫如下程式碼:
 
ifneq ($(KERNELRELEASE),)
 
obj-m := hello.o           //hello為你編寫的模組程式碼儲存名(在此儲存的為hello.c) ,編譯生成目標檔案hello.o(注意:隱式規則)
 
else
 
KDIR := /lib/modules/2.6.18-53.el5/build    //KDIR是本Makefile 依賴的linux核心原始碼路徑  ,如是交叉編譯時就取開發板上執行的原始碼路徑
all:
 make -C $(KDIR) M=$`PWD` modules
 
 //到linux原始碼所在的目錄執行主Makefile 並當前路徑傳給主Makefile,告訴主Makefile執行完後返回到當前目錄,執行Makefile,
clean:
 rm -f *.ko *.o *.mod.o *.mod.c *.symvers
 
endif
 
KERNELRELEASE是在核心原始碼的頂層Makefile中定義的一個變數,在第一次讀取執行此Makefile時, KERNELRELEASE沒有被定義,所以make將讀取執行else之後的內容。如果make的目標是clean,直接執行clean操作,然後結束。當make的目標為all時,-C $(KDIR) 指明跳轉到核心原始碼目錄下讀取那裡的Makefile;M=$(PWD) 表明然後返回到當前目錄繼續讀入、執行當前的Makefile。當從核心原始碼目錄返回時,KERNELRELEASE已被被定義,kbuild也被啟動去解析kbuild語法的語句,make將繼續讀取else之前的內容。else之前的內容為kbuild語法的語句, 指明模組原始碼中各檔案的依賴關係,以及要生成的目標模組名。
 
該Makefile(注意Makefile中的M要大寫,具體原因自己可查資料,在次就不一一講解了)的編寫一般都具有固定的格式,變化很少,可以當成模板來記。