在Ubuntu下如何編譯第一個內核模塊?
Ubuntu系統屬于linux系統,本文介紹了在Ubuntu下編譯的***個內核模塊的方法,具體內容如下所述。
內核模塊是Linux內核向外部提供的一個插口,其全稱為動態可加載內核模塊(LoadableKernelModule,LKM),我們簡稱為模塊。Linux內核之所以提供模塊機制,是因為它本身是一個單內核(monolithickernel)。單內核的***優點是效率高,因為所有的內容都集成在一起,但其缺點是可擴展性和可維護性相對較差,模塊機制就是為了彌補這一缺陷。
一、什么是模塊
模塊是具有獨立功能的程序,它可以被單獨編譯,但不能獨立運行。它在運行時被鏈接到內核作為內核的一部分在內核空間運行,這與運行在用戶空間的進程是不同的。模塊通常由一組函數和數據結構組成,用來實現一種文件系統、一個驅動程序或其他內核上層的功能。
應用程序與內核模塊的比較
為了加深對內核模塊的了解,表一給出應用程序與內核模塊程序的比較。
表一應用程序與內核模塊程序的比較

從表一我們可以看出,內核模塊程序不能調用libc庫中的函數,它運行在內核空間,且只有超級用戶可以對其運行。另外,模塊程序必須通過module_init()和module-exit()函數來告訴內核“我來了”和“我走了”。
二、編寫一個簡單的模塊
模塊和內核都在內核空間運行,模塊編程在一定意義上說就是內核編程。因為內核版本的每次變化,其中的某些函數名也會相應地發生變化,因此模塊編程與內核版本密切相關。以下例子針對Ubuntu9.10內核2.6.31-14-generic
1.程序舉例
- #include
- #include
- #include
- MODULE_LICENSE("GPL");
- staticint__initlkp_init(void)
- {
- printk(KERN_ALERT"HelloWorld!\n");
- return0;
- }
- staticvoid__exitlkp_cleanup(void)
- {
- printk(KERN_ALERT"ByeWorld!\n");
- }
- module_init(lkp_init);
- module_exit(lkp_cleanup);
- MODULE_AUTHOR("heyutao");
- MODULE_DESCRIPTION("hello");
說明
所有模塊都要使用頭文件module.h,此文件必須包含進來。
頭文件kernel.h包含了常用的內核函數。
頭文件init.h包含了宏_init和_exit,它們允許釋放內核占用的內存。
lkp_init是模塊的初始化函數,它必需包含諸如要編譯的代碼、初始化數據結構等內容。
使用了printk()函數,該函數是由內核定義的,功能與C庫中的printf()類似,它把要打印的信息輸出到終端或系統日志。
lkp_cleanup是模塊的退出和清理函數。此處可以做所有終止該驅動程序時相關的清理工作。
module_init()和cleanup_exit()是模塊編程中最基本也是必須的兩個函數。
module_init()是驅動程序初始化的入口點。而cleanup_exit()注銷由模塊提供的所有功能。
2編寫Makefile文件,與hello.c放在同一個目錄里
- obj-m:=hello.oKERNELBUILD:=/lib/modules/$(shelluname-r)/builddefault:make-C$(KERNELBUILD)M=$(shellpwd)modulesclean:rm-rf*.o*.ko*.mod.c.*.cmd*.markers*.order*.symvers.tmp_versions
(注意makefile里面要求的tab)
KERNELBUILD:=/lib/modules/$(shelluname-r)/build是編譯內核模塊需要的Makefile的路徑,Ubuntu下是
/lib/modules/2.6.31-14-generic/build
make-C$(KERNELBUILD)M=$(shellpwd)modules編譯內核模塊。-C將工作目錄轉到KERNELBUILD,調用該目錄下的Makefile,并向這個Makefile傳遞參數M的值是$(shellpwd)modules。
3.編譯模塊
#sudomake(調用***個命令default)
這時,在hello.c所在文件夾就會有hello.ko,這個就是我們需要的內核模塊啦
#sudomakeclean
清理編譯垃圾,hello.ko也會清理掉。
4.插入模塊,讓其工作。注意必須是root權限
#sudoinsmod./hello.ko我們用dmesg就可以看到產生的內核信息啦,Helloworld!
如果沒有輸出"hellofromhelloworld",因為如果你在字符終端而不是終端模擬器下運行的話,就會輸出,因為在終端模擬器下時會把內核消息輸出到日志文件/var/log/kern.log中。
#sudormmod./hello再用dmesg可以看到Byeworld!

modutils是管理內核模塊的一個軟件包。可以在任何獲得內核源代碼的地方獲取Modutils(modutils-x.y.z.tar.gz)源代碼,然后選擇***級別的patch.x.y.z等于或小于當前的內核版本,安裝后在/sbin目錄下就會有insomod、rmmod、ksyms、lsmod、modprobe等實用程序。當然,通常我們在加載Linux內核時,modutils已經被載入。1.Insmod命令調用insmod程序把需要插入的模塊以目標代碼的形式插入到內核中。在插入的時候,insmod自動調用init_module()函數運行。注意,只有超級用戶才能使用這個命令,其命令格式為:#insmod[path]modulename.ko2.rmmod命令調用rmmod程序將已經插入內核的模塊從內核中移出,rmmod會自動運行cleanup_module()函數,其命令格式為:#rmmod[path]modulename.ko3.lsmod命令調用lsmod程序將顯示當前系統中正在使用的模塊信息。實際上這個程序的功能就是讀取/proc文件系統中的文件/proc/modules中的信息,其命令格式為:#lsmod4.ksyms命令
ksyms這個程序用來顯示內核符號和模塊符號表的信息。與lsmod相似,它的功能是讀取/proc文件系統中的另一個文件/proc/kallsyms。
這就是在2.6.xx下一個最簡單的模塊編寫過程。
總結:
希望本文介紹的在Ubuntu下編譯的***個內核模塊的方法能夠對讀者有所幫助,更多有關linux系統的知識還有待于讀者去探索和學習。
【編輯推薦】