linux內核編程入門 hello world

注意:linux

  • Makefile 文件的命名注意M須要大寫,不然會報錯。
  • 在Makefile文件中make命令前應爲tab製表符。

下文轉載至:https://blog.csdn.net/bingqing07/article/details/5888875shell

首先得了解一下什麼是模塊: 模塊是具備獨立功能的程序,它能夠被單獨編譯,但不能獨立運行。它在運行時被連接到內核做爲內核的一部分在內核空間運行,這與運行在用戶空間的進程是不一樣的。模塊一般由一組函數和數據結構組成,用來實現一種文件系統、一個驅動程序或其餘內核上層的功能。編程

這樣說吧,模塊就是整個內核的一部分。可是跟C程序中函數不同的一點是,內核模塊能夠在它所認爲適當的時候,插入到內核或者從內核中刪除,並且還不影響內核的正常運行。從而能夠在必要的時候對內核進行裁剪,這樣可以更好的適應於用戶的需求。數據結構

廢話少說了。咱們如今就開始進入內核編寫的階段,看一看怎麼樣將一個C程序一步步變成相應的內核模塊。編程語言

每個學習過編程語言的人都知道,第一個示例程序確定是hello world。咱們內核編程的第一個例子也不例外,就是編寫一個hello world模塊。函數

首先讓咱們在電腦裏編寫一段C語言代碼,hello.c。代碼以下:學習

//必要的頭文件
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
//模塊許可證聲明(必須)
MODULE_LICENSE("Dual BSD/GPL");
//模塊加載函數(必須)
static int hello_init(void)
{
    printk(KERN_ALERT "Hello World enter/n");
    return 0;
}
//模塊卸載函數(必須)
static void hello_exit(void)
{
    printk(KERN_ALERT "Hello World exit/n");
}
//模塊的註冊
module_init(hello_init);
module_exit(hello_exit);
//聲明模塊的做者(可選)
MODULE_AUTHOR("XXX");
//聲明模塊的描述(可選)
MODULE_DESCRIPTION("This is a simple example!/n");
//聲明模塊的別名(可選)
MODULE_ALIAS("A simplest example");

以上就是一個最簡單的內核模塊的例子程序。咱們經過這個例子來分析一下內核模塊的特色。.net

一、在內核模塊的開始一部分,跟C語言的通常程序同樣,是模塊所須要的頭文件。日誌

二、模塊許可證聲明,這部分是必須有的。模塊許可證(LICENSE)聲明描述內核模塊的許可權限,若是不聲明LICENSE,模塊被加載時,將收到內核被污染(kernel tainted)的警告。大多數狀況下,內核模塊應遵照GPL兼允許可權。Linux2.6內核模塊最多見的是以MODULE_LICENSE("Dual BSD/GPL")語句聲明模塊採用BSD/GPL雙LICENSE。code

三、模塊加載函數,這部分是必須的。模塊加載函數必須以「module_init(函數名)「的形式被指定。它返回整形值,若初始化成功,應返回0。在上面那個例子當中,hello_init()函數就是模塊加載函數須要執行的,主要是打印一條信息。

四、跟模塊加載函數相對應的就是模塊卸載函數,這部分也是必須的。模塊卸載函數在模塊卸載的時候執行,不返回任何值,必須以「module_exit(函數名)「的形式來指定。在上面的例子中,hello_exit()函數就是模塊卸載函數須要執行的,只要是打印了一條退出信息。

五、函數最後的一部分,是模塊聲明與描述部分。這部分能夠有,也能夠省略。在Linux內核模塊中,咱們能夠用MODULE_AUTHOR,MODULE_DESCRIPTION,MODULE_VERSION,MODULE_DEVICE_TABLE,MODULE_ALIAS分別聲明模塊的做者、描述、版本、設備表和別名。

注:

一、module_init()是驅動程序初始化的入口點。它就至關於c語言程序中的main()函數。對於內置的模塊,內核在引導時調用該引導點,對於可加載模塊則在模塊插入到內核時才調用。

二、模塊加載函數和模塊卸載函數中都用到了printk()函數,該函數是由內核定義的,功能與C庫中的printf()相似,它把要打印的信息輸出到終端或系統日誌中。在本例中,咱們是將初始化的打印信息輸出到日誌中,咱們在看它對應的輸出時,這時能夠用dmesg命令來查看。

編寫完了.c文件,下面咱們就要對其進行對應的操做,要把一個普通的.c文件變成咱們所須要的內核文件。通常咱們理解,應該是應用幾條Linux下的命令就能夠搞定(如gcc,g++……),這裏的理解是對的,咱們就是須要幾個命令就OK。可是咱們知道,編譯這個須要敲打的命令過於多,要輸入內核版本的號,路徑,和編寫模塊的路徑與信息。若是每次都輸入這麼多,那確定是太麻煩。這時咱們就想到了Makefile文件,經過它來管理一個龐大的項目是再好不過的。下面咱們就在剛纔.c文件目錄下編寫一個Makefile文件。對應的代碼以下:

obj-m += hello.o
#generate the path
CURRENT_PATH:=$(shell pwd)
#the current kernel version number
LINUX_KERNEL:=$(shell uname -r)
#the absolute path
LINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL)
#complie object
all:
    make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
#clean
clean:
    make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean

首先第一句話就是指定要編譯的文件。

pwd是得到當前的相對路徑,而後就是得到當前的內核版本號,咱們能夠用uname -r命令,這樣咱們就得到了當前內核的絕對路徑。這樣作的一個好處,就是你能夠在不一樣的內核版本中進行移植,並且可讀性也加強了。

對於其餘的Makefile語法上的問題就不在這裏介紹。不會的,能夠看看相應的語法介紹。

有了Makefile文件後,咱們就離成功不遠了。在.c文件的同一目錄下,執行make命令,系統會在當前目錄下生成好多個文件。其中就有與之相關的.o和.ko文件。hello.ko就是模塊目標文件。到此,模塊編譯好了。

模塊編譯好了,可是還不能爲咱們工做。下面就是將目標模塊插入到內核和從內核中刪除。這裏須要用到兩個命令,insmod和rmmod 咱們光看這兩個命令單詞就能猜出他們的意思。輸入命令:sudo insmod hello.ko(注意要用sudo),這時沒有任何提示,不少人會很奇怪,剛纔不是說過,模塊加載後,程序中要對應輸出一條提示信息,怎麼這裏什麼都沒有。你們不要急,再想想剛纔所用到的打印信息的函數printk(),它與咱們日常C庫的printf()函數不同,不是運行在用戶界面上的,因此確定不會在終端上顯示出信息。要看信息必需要進入到日誌文件中。這時咱們再輸入命令進到系統日誌:dmesg,咱們把界面拖到最後,會發現有一條信息,Hello World enter。哈哈,這正是咱們所須要的,說明咱們剛纔編寫的模塊已經插入到內核當中了。接下來再試一試刪除命令,輸入命令:sudo rmmod hello.ko,這時跟剛纔的插入命令同樣,沒有什麼反應。再輸入命令打開系統日誌,咱們會發如今剛纔 Hello World enter命令後面會有一個新的信息Hello World exit,這說明咱們的模塊卸載成功。這樣咱們就大功告成,慶祝一下吧。

除了加載和刪除模塊,咱們也能夠用命令 lsmod 來查看當前系統中加載的全部模塊及模塊間的依賴關係。若是剛纔咱們加載了hello模塊並無刪除,用這個命令,咱們會在其中找到hello這一項,這樣也能夠說明咱們本身編寫的模塊加載成功。相應的,若是咱們刪除了該模塊,用這個命令後,hello模塊不會出現。lsmod命令實際上讀取並分析/proc/modules文件。

使用modinfo <模塊名> 命令能夠得到模塊的信息,包括模塊的做者,說明,參數……也就是咱們剛纔編寫模塊時可選的幾個部分。

相關文章
相關標籤/搜索