日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

构造和运行模块

發布時間:2023/12/18 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 构造和运行模块 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者:蔡倫輝
寫在前面
作者一直支持GPL的精神。允許任何人自由使用、轉載、復制和再分發,但必須保留作者署名,必須保證全文完整轉載,包括完整的版權聲明。
由于作者水平有限,因此不能保證文章內容準確無誤,請批判閱讀。如果你發現任何錯誤或對文章內容有任何建議,歡迎你與我聯系:
Email: caiallen@tom.com??QQ群: 14765968
設置測試系統
在該小節中,有以下一段話:
“不管內核來自哪里,想要為2.6x內核構造模塊,還必須在自己的系統中配置并構造好內核樹。這一要求和先前版本的內核不同,先前的內核只要有一套內核頭文件就夠了。但因為2.6內核的模塊要和內核源代碼樹中的文件連接,通過這種方式,可得到一個更加健壯的模塊裝載器,但也需要這些目標文件存在于內核目錄樹中。”
這段話說出了2.4和2.6兩種版本的驅動模塊的編寫的一個不同之處。問題來自,我用的操作系統是Fedora Core 5。FC5在安裝時是不安裝源代碼樹在PC上的。所以我必須在我的FC5上建立內核源代碼樹。最好在構造內核模塊時運行的恰好是目標內核。書上的例子是在版本2.6.10中構造的,用命令uname -r查看,FC5的版本信息為:2.6.15-1.2054_FC5。所以我要建立的內核源代碼樹的版本為2.6.15。下面詳細介紹其建立過程。
1。??下載內核rpm包
rpm包名稱:kernel-2.6.15-1.2054_FC5.src.rpm
下載地址:http://download.fedora.redhat.com/pub/fedora/linux/core/5/source/SRPMS/
kernel-2.6.15-1.2054_FC5.src.rpm
2。? ? 安裝rpm包
以root身份登陸,以下步驟都以root身份執行。進入保存rpm包的目錄下,運行命令:
#rpm -Uvh kernel-2.6.15-1.2054_FC5.src.rpm
? ?? ?? ?? ?該命令將rpm的內容寫到路徑/usr/src/redhat/SOURSE和/usr/src/redhat/SPECS下。
3。? ?build源碼包
? ?? ?? ?? ?#cd /usr/src/redhat/SPECS
#rpmbuild -bp --target i686 kernel-2.6.spec
該命令將會把內核源碼樹放到目錄
/usr/src/redhat/BUILD/kernel-2.6.15/kernel-2.6.15.686
4。? ? 配置內核
Fedora Core 5附帶的內核配置文件在內核源碼樹的configs/目錄下。
例如,i686 SMP 配置文件被命名為
configs/kernel-version-i686-smp.config。
但我的PC機為i686,單CPU,所以不是SMP,應該選的內核配置文件是:kernel-2.6.15-i686.config
注意:如果你的PC是單CPU的,而選 configs/kernel-version-i686-smp.config進行內核配置,則在建立代碼樹后運行后面的insmod hello.ko會失敗,失敗原因我在文件/var/log/messages中找到如下:Nov 23 04:55:02 localhost kernel: hello: version magic '2.6.15-1.2054_FC5 SMP 686 REGPARM 4KSTACKS gcc-4.1' should be '2.6.15-1.2054_FC5 686 REGPARM 4KSTACKS gcc-4.1'
一對比:
'2.6.15-1.2054_FC5 SMP 686 REGPARM 4KSTACKS gcc-4.1'
'2.6.15-1.2054_FC5 686 REGPARM 4KSTACKS gcc-4.1‘
看出區別了吧,原因是我選的配置文件不對。我一開始就犯了這個錯誤錯誤,結果不得不又從頭開始進行漫長的編譯。
使用下列命令來將需要的配置文件復制到合適的位置,用來編譯:
#cd /usr/src/redhat/BUILD/kernel-2.6.15/linux-2.6.15.i686?
#cp configs/kernel-version-i686.config .config你也可以在 /lib/modules/version/build/.config 這個位置找到與您當前的內核匹配的 .config 文件。因為build是個連接,其連接目標就是/usr/src/redhat/BUILD/kernel-2.6.15/linux-2.6.15.i686
用以下命令調出內核配置菜單。
#make menuconfig
配置如下:
Loadable module support --->

  • Enable loadable module support
  • Module unloading
    [ ] Module versioning support (EXPERIMENTAL)
  • Automatic kernel module loading? ?? ??
    5。? ? 修改Makefile
    每個內核的名字都包含了它的版本號,這也是 uname -r 命令顯示的值。內核Makefile 的前四行定義了內核的名字。為了保護官方的內核不被破壞,Makefile經過了修改,以生成一個與運行中的內核不同的名字。在一個模塊插入運行中的內核前,這個模塊必須針對運行中的內核進行編譯。為此,你必須編輯內核的Makefile。
    例如,如果 uname -r 返回字符串 2.6.15-1.2054_FC5,就將 EXTRAVERSION 定義從:
    EXTRAVERSION = -prep
    修改為:
    EXTRAVERSION = -1.2054_FC5
    也就是最后一個連字符后面的所有內容。
    6。? ? 編譯內核
    在目錄/usr/src/redhat/BUILD/kernel-2.6.15/linux-2.6.15.i686下即Makefile所在的目錄使用下面命令編譯內核:
    #make bzImage? ?? ?? ???編譯內核?
    #make modules? ?? ?? ???編譯模塊?
    #make modules_install? ?安裝模塊這一步可是一個漫長的過程啊,花去我差不多一個小時


    7。? ? 完成“內核樹”的安裝
    以上這一步如果沒什么錯誤,到此就完成了內核代碼樹的建立。
    目錄“/usr/src/redhat/BUILD/kernel-2.6.15/kernel-2.6.15.686/”中就是所謂的“內核代碼樹”,同時“/lib/modules/2.6.15-1.2054_FC5/build”是個符號鏈接,也指向這個目錄,所以這里也可以叫做“內核代碼樹”。
    以上的建立步驟是在參考《在Linux 2.6內核下編譯可以加載的內核模塊》(原文地址http://blog.csdn.net/wooin/archive/2007/05/21/1619141.aspx)同時結合自己的實踐而得出,增加一些說明并修正了其中的一些錯誤。
    完成以上的步驟,便為我們后面的實踐打下了基礎。
    Hello World模塊
    要想驗證我們的內核代碼樹是否成功建立,可以寫個內核模塊測試一下,就從Hello world程序開始。以下是名為hello.c的文件的代碼:
    ? ? ? ? ? ? ? ??
    ? ? ? ? ? ? ? ? #include linux/init.h>
    #include linux/module.h>
    MODULE_LICENSE("Dual BSD/GPL");//(1)
    static int hello_init(void)//(2)?
    {
    ? ?printk(KERN_ALERT "Hello, World!\n");//(3)
    ? ?return 0;
    }
    static void hello_exit(void)?
    {
    ? ?printk(KERN_ALERT "Goodbye, cruel World!\n");
    }
    module_init(hello_init);//(4)
    module_exit(hello_exit);//(5)
    代碼說明:
    ? ? (1):
    MODULE_LICENSE是一個特殊的宏,用來告訴內核,該模塊采用自由許可證;可以不要這樣的聲明,但不要的話,運行ismod hello.ko時會出現"hello: module
    license 'unspecified' taints
    kernel.",詞典上對taints的解釋是"感染,污點",即內核在裝載該模塊時會產生抱怨

    ,內核有情緒?!還要注意的一點是,這句不要寫到最后,放到(5)后面,還是會出現內核污染的提示。
    ? ? (2):對模塊內的函數一般需要加上static關鍵字進行修飾,這樣可防止模塊外訪問該函數,這是應該養成的一個好習慣。
    ? ? (3):printk函數相當于C標準庫函數printf, KERN_ALERT是指的輸出消息的優先級別。
    ? ? (4)(5):模塊初始化和模塊退出時有專門的函數,這個函數在2.4和2.6兩種版本的內核有所區別。
    然后編寫該程序的Makefile:
    # Makefile for hello.c
    obj-m:=hello.o
    KDIR:=/lib/modules/2.6.15-1.2054_FC5/build
    PWD:=$(shell pwd)
    default:
    ? ? $(MAKE) -C $(KDIR) M=$(PWD) modules
    .PHONY:clean
    clean:
    ? ? rm -f *.o *~ *.ko
    該Makefile為何這樣寫,可以參考相關資料,如我轉載的《2.6驅動移植系列之Getting started(2)--模塊編譯》和在內核代碼的/Documentation/kbuild目錄下的makefile.txt這篇文檔。簡單解析下,$(MAKE) -C $(KDIR) M=$(PWD) modules命令首先改變目錄到-C選項指定的位置(即內核源代碼目錄),其中保存有內核的頂層Makefile文件,因為build腳本會首先判斷有無必要重新編譯內核,所以如果需要先重新編譯內核的話,編譯過程會運行一段時間。M=選項讓該Makefile在構造modules目標之前返回到模塊源代碼目錄。然后,modules目標指向obj-m變量中設定的模塊。
    有一點需要注意的,Makefile文件名一定要大寫,不能寫出makefile,否則在你make時會出現“沒有規則可以創建目標。停止”類似的提示。
    執行make命令進行編譯就行了, 執行完畢后,會生成幾個文件:
    hello.ko
    hello.mod.c
    hello.mod.o
    hello.o
    注意:2.6內核的模塊后綴名為.ko
    運行命令:
    #insmod hello.ko掛載成功,但看不到輸出:Hello World!。
    然后再運行命令:
    #rmmod hello同樣卸載成功但也看不到輸出:Goodbye, cruel world!
    后來查看日志文件/var/log/messages,哈哈,原來輸出到這里來了!后來查找原因,原來在GNOME環境(即圖形界面)信息不會輸出到終端,在在控制臺下則可以看到輸出信息。按換到控制臺模式,以root身份登陸,再運行insmod hello.ko,果然看到輸出。再按可以切換回GNOME環境。
    如果你在運行insmod hello.ko時出現以下提示:
    insmod: error inserting 'hello.ko': -1 Invalid module format
    可能的原因有:
    ? ? 1。內核源代碼樹沒有建立好。
    ? ? 2。編譯器的版本不對。可以查看內核文檔中的Documentation/Changes文件列出的需要的工具版本。
    ? ? 3。Makefile編寫不對。
    核心模塊與應用程序的對比
    內核模塊與應用程序的不同之處有:
    ? ? 1。大多數小規模及中規模應用程序是從頭到尾執行單個任務,而模塊只是預先注冊自己以便服務于將來的某個請求,然后它的初始化函數就立即結束。
    ? ? 2。應用程序在退出時,可以不管資源的釋放或者其他的清除工作,但模塊的退出卻必須仔細撤銷初始化函數所做的一切,否則,在系統重新引導之前某些東西就會殘留在系統中。
    ? ? 3。模塊運行在所謂的內核空間里,而應用程序運行在所謂的用戶空間中。
    用戶空間和內核空間
    操作系統的作用是為應用程序提供一個對計算機硬件的一致視圖,除此之外,還必須負責程序的獨立操作并保護資源不受非法訪問。
    這兩種運行模式都有自己的內存映射,也即自己的地址空間。
    每當應用程序執行系統調用或者被硬件中斷掛起時,linux將執行模式從用戶空間切換到內核空間。而處理硬件中斷的內核代碼和進程是異步的,與任何一個特定的進程無關。
    模塊化代碼在內核空間中運行,用于擴展內核功能。通常來講,一個驅動程序要執行兩類任務:模塊中的某些函數作為系統調用的一部分而執行,而其他函數則負責中斷處理。
    當前進程
    內核代碼可以通過訪問全局項current來獲得當前進程。current指針指向當前正在運行的進程。在open,read等系統調用的執行過程中,當前進程指的是調用這些系統調用的進程。
    與早期linux內核版本不同,2.6中current不再是全局變量。然而,設備驅動程序只要包含頭文件即可以引用當前進程。
    編譯模塊
    實際上hello world的makefile的一個更容易的寫法是:
    # 如果已定義KERNELRELEASE,則說明是從內核構造系統調用的。
    # 因此可以利用其內建語句
    ifneq ($(KERNELRELEASE),)?
    ? ? obj-m := hello.o
    # 否則是直接從命令行調用
    # 這時要調用內核構造系統
    else?
    ? ? KERNELDIR ?= /lib/modules/$(shell uname -r)/build?
    ? ? PWD := $(shell pwd)?
    default:?
    ? ? $(MAKE) -C $(KERNELDIR) M=$(PWD) modulesendif?
    KERNELRELEASE是在內核源碼的頂層Makefile中定義的一個變量,在第一次讀取執行此Makefile時,KERNELRELEASE沒
    有被定義,
    所以make將讀取執行else之后的內容。如果make的目標是clean,直接執行clean操作,然后結束。當make的目標為all時,-C
    $(KDIR) 指明跳轉到內核源碼目錄下讀取那里的Makefile;M=$(PWD)
    表明然后返回到當前目錄繼續讀入、執行當前的Makefile。當從內核源碼目錄返回時,KERNELRELEASE已被被定義,kbuild也被啟動去
    解析kbuild語法的語句,make將繼續讀取else之前的內容。else之前的內容為kbuild語法的語句,
    指明模塊源碼中各文件的依賴關系,以及要生成的目標模塊名。
    (continue...)

轉載于:https://www.cnblogs.com/dayuhope/p/3286481.html

總結

以上是生活随笔為你收集整理的构造和运行模块的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。