国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
小白學Linux之內(nèi)核模塊編程-tiger
Linux內(nèi)核模塊編程
Linux內(nèi)核模塊編程是一個很重要的知識點。尤其是編寫底層驅(qū)動程序時,一定會涉及到它。內(nèi)核模塊編程也是Tiger哥學習Linux時第一節(jié)課所接觸的知識。由此可以看出它的important,也可以看出其實它很easy。

一前言:
1. 什么是內(nèi)核模塊
1> 內(nèi)核模塊是具有獨立功能的程序。它可以被單獨編譯,但是不能單獨運行,它的運行必須被鏈接到內(nèi)核作為內(nèi)核的一部分在內(nèi)核空間中運行。
2> 模塊編程和內(nèi)核版本密切相連,因為不同的內(nèi)核版本中某些函數(shù)的函數(shù)名會有變化。因此模塊編程也可以說是內(nèi)核編程。
3>特點:
模塊本身不被編譯進內(nèi)核映像,從而控制了內(nèi)核的大??;
模塊一旦被加載,就和內(nèi)核中的其他部分完全一樣。

2 .用戶層編程和內(nèi)核模塊編程的區(qū)別
 
 應用程序  內(nèi)核模塊程序 
使用函數(shù)  libc庫  內(nèi)核函數(shù) 
運行空間  用戶空間  內(nèi)核空間 
運行權限  普通用戶  超級用戶 
入口函數(shù)  main()  module_init 
出口函數(shù)  exit()  module_exit 
編譯  gcc  makefile 
鏈接  gcc  insmod 
運行  直接運行  insmod 
調(diào)試  gdb  kdbug、kdb、kgdb 

 二.說了這么多,那么怎么編寫一個內(nèi)核模塊的程序呢?
1.我們先來看兩個最簡單的函數(shù)實例,也是幾乎所有程序員在學習一門新語言時都會編寫的程序:輸出 hello world!
現(xiàn)在我們分別用模塊編程輸出hello world!,和在用戶層編程輸出hello wrold!。通過這兩個程序我們來分析下如何來編寫一個內(nèi)核模塊程序。

用戶層編程:hello.c
#include<stdio.h>
int main(void)
{
       printf("hello world\n");

}

內(nèi)核編程: module.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
    printk(KERN_ALERT "hello,I am edsionte\n");
    return 0;
}
static void hello_exit(void)
{
    printk(KERN_ALERT "goodbye,kernel\n");
}
module_init(hello_init);
module_exit(hello_exit);
//可選
MODULE_AUTHOR("Tiger-John");
MODULE_DESCRIPTION("This is a simple example!\n");
MODULE_ALIAS("A simplest example");

Tiger-John說明:
1.>相信只要是學過C語言的同學對第一個程序都是沒有問題的。但是也許大家看了第二個程序就有些不明白了。
可能有人會說:Tiger哥你沒瘋吧,怎么會把printf()這么簡單的函數(shù)錯寫成了printk()呢。
也有的人突然想起當年在大學學C編程時,老師告訴我們“一個C程序必須要有main()函數(shù),并且系統(tǒng)會首先進入main()函數(shù)執(zhí)行",那么你的程序怎么沒有main()函數(shù)呢?沒有main()函數(shù)程序是怎么執(zhí)行的呢?
可能也會有更仔細的人會發(fā)現(xiàn):怎么兩個程序頭文件不一樣呢?不是要用到輸入和輸出函數(shù)時,一定要用到<stdio.h>這個頭文件,你怎么沒有呢?

--------------------------------------------------------------------------------------------
Tiger哥很淡定的告訴大家其實第二個程序是正確的,現(xiàn)在我們就來看看到底如何來編寫一個內(nèi)核模塊程序。
2.內(nèi)核模塊編程的具體實現(xiàn)
第一步: 首先我們來看一下程序的頭文件
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/init.h>
這三個頭文件是編寫內(nèi)核模塊程序所必須的3個頭文件 。
Tiger-John說明:
1>由于內(nèi)核編程和用戶層編程所用的庫函數(shù)不一樣,所以它的頭文件也和我們在用戶層編寫程序時所用的頭文件也不一樣。
2>我們在來看看在L inux中又是在那塊存放它們的頭文件

a.內(nèi)核頭文件的位置 :/usr/src/linux-2.6.x/include/
b.用戶層頭文件的位置:   /usr/include/
現(xiàn)在我們就明白了。其實我們在編寫內(nèi)核模塊程序時所用的頭文件和系統(tǒng)函數(shù)都和用層 編程時所用的頭文件和系統(tǒng)函數(shù)是 不同的。
第二步: 編寫內(nèi)核模塊時必須要有的兩個函數(shù):
1>注冊函數(shù):
 

static int    init_fun(void)
{
//初始化代碼
}
 

函數(shù)實例:
static int hello_init(void)// 不加 void 在調(diào)試時會出現(xiàn)報警
{
         printk("hello world!\n");
         return 0;
}
2>卸載函數(shù) 無返回值

static void    cleaup_fun(void)
{
//釋放代碼
}
函數(shù)實例:

 
static void hello_exit(void)// 不加 void 會出現(xiàn)報警 , 若改為 static int 也會報錯 , 因為出口函數(shù)是不能返會值的
{
printk("bye,bye\n");
}
在模塊編程中必須要有上面這兩個函數(shù);
Tiger-John補充:
注冊函數(shù)和卸載函數(shù)還有另一中寫法:
1> 注冊函數(shù)
static int __init init_fun(void)
{
//初始化代碼
}
函數(shù)實例:
static int  __init  hello_init(void)
{
printk("hello tiger\n");
return 0;
}
2>卸載函數(shù)  無返回值

static void __exit cleaup_fun(void)
{
//釋放代碼
}
函數(shù)實例:
static void __exit exit(void)
{
printk("bye bye!\n");
}
Tiger-John補充:
通過比較我們可以發(fā)現(xiàn)第二中函數(shù)的寫法與第一中函數(shù)的寫法主要不同就是加了__init 和__exit前綴。(init 和exit前面都是兩個下劃線)

那么第二種方法比第一種有什么好處呢:

__init和__exit是Linux內(nèi)核的一個宏定義,使系統(tǒng)在初始化完成后釋放該函數(shù),并釋放其所占內(nèi)存。 因此它的優(yōu)點是顯而易見的。所以建議大家啊在編寫入口函數(shù)和出口函數(shù)時采用第二中方法。
3 >現(xiàn)在我們來看一下printk()函數(shù)
a.上面已經(jīng)說了,我們在內(nèi)核 編程時所用的庫函數(shù)和在用戶態(tài)下的是不一樣的。 printk 是內(nèi)核態(tài)信息打印函數(shù),功能和比準 C 庫的 printf 類似。 printk 還有信息打印級別。
b.現(xiàn)在我們來看一下printk()函數(shù)的原型:
int printk(const char *fmt, ...)

消息打印級別:
fmt----消息級別:
#define KERN_EMERG "<0>" /*緊急事件消息,系統(tǒng)崩潰之前提示,表示系統(tǒng)不可用 */
#define KERN_ALERT "<1>" /*報告消息,表示必須立即采取措施 */
#define KERN_CRIT "<2>" /*臨界條件,通常涉及嚴重的硬件或軟件操作失敗 */
#define KERN_ERR "<3>" /*錯誤條件,驅(qū)動程序常用 KERN_ERR來報告硬件的錯誤 */
#define KERN_WARNING "<4>" /*警告條件,對可能出現(xiàn)問題的情況進行警告 */
#define KERN_NOTICE "<5>" /*正常但又重要的條件,用于提醒。常用于與安全相關的消息 */
#define KERN_INFO "<6>" /*提示信息,如驅(qū)動程序啟動時,打印硬件信息 */
#define KERN_DEBUG "<7>" /*調(diào)試級別的消息 */
Tiger-John說明:
不同級別使用不同字符串表示,數(shù)字越小,級別越高。
c. 為什么內(nèi)核態(tài)使用 printk() 函數(shù),而在用戶態(tài)使用 printf() 函數(shù)。
printk() 函數(shù)是直接使用了向終端寫函數(shù) tty_write() 。而 printf() 函數(shù)是調(diào)用 write() 系統(tǒng)調(diào)用函數(shù)向標準輸出設備寫。所以在用戶態(tài)(如進程 0 )不能夠直接使用 printk() 函數(shù),而在內(nèi)核態(tài)由于它已是特權級,所以無需系統(tǒng)調(diào)用來改變特權級,因而能夠直接使用 printk() 函數(shù)。 printk 是內(nèi)核輸出,在終端是看不見的。我們可以看一下系統(tǒng)日志。
但是我們可以使用命令:cat  /var/log/syslog ,或者使用 dmesg 命令看一下輸出的信息。
第三步: 加載模塊和卸載模塊 
1>module_init(hello_init)
a.告訴內(nèi)核你編寫模塊程序從那里開始執(zhí)行。
b.module_init()函數(shù)中的參數(shù)就是注冊函數(shù)的函數(shù)名。

2>module_exit(hello_exit)
a. 告訴內(nèi)核你編寫模塊程序從那里離開。
b.module_exit()中的參數(shù)名就是卸載函數(shù)的函數(shù)名。
Tiger-John說明:
我們一般在注冊函數(shù)里進行一些初始化比如申請內(nèi)存空間注冊設備號等 。那么我們就要在卸載函數(shù)進行釋放我們所占有的資源。
第四步: 許可權限的聲明
1>函數(shù)實例:
MODULE_LICENSE("Dual BSD/GPL");
2> 此處可有可無,可以不加系統(tǒng)默認 ( 但是會報警 )
模塊聲明描述內(nèi)核模塊的許可權限,如果不聲明 LICENSE ,模塊被加載時,將收到內(nèi)核的警告。
在 Linux2.6 內(nèi)核中,可接受的 LICENSE 包括" GPL","GPL v2","GPL and additional rights","Dual BSD/GPL","Dual MPL/GPL","Proprietary"。
第五部: 模塊的聲明與描述(可加可不加)  
MODULE_AUTHOR(“author”);// 作者
MODULE_DESCRIPTION(“description”);// 描述
MODULE_VERSION(”version_string“);// 版本
MODULE_DEVICE_TABLE(“table_info”);// 設備表
MODULE_ALIAS(”alternate_name“);// 別名
Tiger-John:總結
經(jīng)過以上五步(其實只要前四步)一個完整的模塊編程就完成了。
 
但是,前面我們已經(jīng)說過了。內(nèi)核編程和用戶層編程它們之間的編譯
鏈接也不相同。那么我們 如何對模塊程序進行編譯,鏈接,運行呢?
現(xiàn)在我么繼續(xù)深入來學習Makefile文件的編寫:
三.   make 的使用以及 Makefile 的編寫
1.什么是Makefile,make
1>Makefile是一種腳本,這種腳本主要是用于多文件的編譯
2> make 程序可以維護具有相互依賴性的源文件,但某些文件發(fā)生改變時,它能自動識別出,
并只對相應文件進行自動編譯
2.Makefile的寫法
Makefile 文件由五部分組成:顯示規(guī)則 含規(guī)則 變量定義 makefile 指示符和注釋

一條Make 的規(guī)則原型為:
目標 ... :依賴 ..
命令
...
makefile 中可以使用Shell 命令,例如pwd ,uname
簡單的makefile 文件:
obj-m := hello.o
kernel_path=/usr/src/linux-headers-$(shell uname -r)
all:
             make -C $(kernel_path) M=$(PWD) modules
clean:
              make -C $(kernel_path) M=$(PWD) clean
obj-m:= hello.o // 產(chǎn)生hello 模塊的目標
kernel_path // 定義內(nèi)核源文件目錄
all :
                  make -C $(kernel_path) M=$(PWD) modules
// 生成內(nèi)核模塊參數(shù)為內(nèi)核源代碼目錄以及模塊所在目錄
clean:
                  make -C $(kernel_path) M=$(PWD) clean
// 清除生成的模塊文件以及中間文件
Tiger-John說明:
在all和clean下面的一行,即make之前必須用Table符隔開,不能用空
格隔開,否則編譯錯誤。

3.函數(shù)實例:
 
  1 obj-m:=module.o
  2
  3
  4 CURRENT_PATH :=$(shell pwd)
  5 VERSION_NUM  :=$(shell uname -r)
  6 LINUX_PATH   :=/usr/src/linux-headers-$(VERSION_NUM)
  7
  8 all :
  9         make -C $(LINUX_PATH) M=$(CURRENT_PATH) modules
 10 clean :
 11         make -C $(LINUX_PATH) M=$(CURRENT_PATH) clean
 
 
----------------------------------------------------------------------

經(jīng)過上面的模塊編程和Makefile的編程,我們就可以對我們的程序進行編譯鏈接和運行了
四. 內(nèi)核模塊的操作過程

1> 在控制臺輸入 make 進行編譯鏈接
2> 正確后在控制臺輸入 sudo insmod module.ko (加載模塊)
3> 在控制臺輸入 dmesg 查看結果
4> 在控制臺輸入 rmmod tiger( 卸載模塊 )
5> 輸入 dmesg 查看結果
( 或者用 cat /var/log/syslog 查看系統(tǒng)日志文件)
6>make clean( 去除中間生成的文件)
----------------------------------------------------------------------
現(xiàn)在我們就總體來實踐一下,來體驗一下。編寫內(nèi)核模塊程序的樂趣
 
module.c
 

1 #include<linux/kernel.h>
2 #include<linux/init.h>
3 #include<linux/module.h>
4 MODULE_LICENSE("Dual BSD/GPL");
5
6 static  int __init hello_init(void)
7 {
8         printk("Hello world\n");
9         return 0;
10 }
11
12 static void __exit hello_exit(void)
13 {
14         printk("Bye Corne\n");
15
16 }
17 module_init(hello_init);
18 module_exit(hello_exit);

 
Makefile
 

 
  1 obj-m:=module.o
  2
  3
  4 CURRENT_PATH :=$(shell pwd)
  5 VERSION_NUM  :=$(shell uname -r)
  6 LINUX_PATH   :=/usr/src/linux-headers-$(VERSION_NUM)
  7
  8 all :
  9         make -C $(LINUX_PATH) M=$(CURRENT_PATH) modules
 10 clean :
 11         make -C $(LINUX_PATH) M=$(CURRENT_PATH) clean
在終端輸入 make
think@ubuntu:~/work/moudule/mokua_biancheng$ make
make -C /usr/src/linux-headers-2.6.32-25-generic M=/home/think/work/moudule/mokua_biancheng modules
make[1]: 正在進入目錄 `/usr/src/linux-headers-2.6.32-25-generic'
  Building modules, stage 2.
  MODPOST 1 modules
make[1]:正在離開目錄 `/usr/src/linux-headers-2.6.32-25-generic'
think@ubuntu:~/work/moudule/mokua_biancheng$

[19011.002597] Hello world
 
 
Tiger-John:當程序沒有錯誤時,當我們輸入dmesg時就可以看到程序運行的結果了。
 
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/tigerjb/archive/2010/11/15/6010997.aspx#1607120
本站僅提供存儲服務,所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Linux內(nèi)核之旅
linux內(nèi)核編程(一)
linux設備驅(qū)動歸納總結(二):模塊的相關基礎概念
Linux驅(qū)動程序入門—Hello World - 藍博芯科
ldd3之模塊學習總結(頁 1) - 文檔專區(qū) - 無分類文檔 - Linux論壇 - p...
編寫簡單的Linux2.6內(nèi)核模塊(1)
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服