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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Linux内核之旅

發(fā)布時間:2023/11/27 生活经验 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux内核之旅 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

內(nèi)核模塊是Linux內(nèi)核向外部提供的一個插口,其全稱為動態(tài)可加載內(nèi)核模塊(Loadable Kernel Module,LKM),我們簡稱為模塊。Linux內(nèi)核之所以提供模塊機制,是因為它本身是一個單內(nèi)核(monolithic kernel)。單內(nèi)核的最大優(yōu)點是效率高,因為所有的內(nèi)容都集成在一起,但其缺點是可擴展性和可維護(hù)性相對較差,模塊機制就是為了彌補這一缺陷。

一、 什么是模塊

模塊是具有獨立功能的程序,它可以被單獨編譯,但不能獨立運行。它在運行時被鏈接到內(nèi)核作為內(nèi)核的一部分在內(nèi)核空間運行,這與運行在用戶空間的進(jìn)程是不同的。模塊通常由一組函數(shù)和數(shù)據(jù)結(jié)構(gòu)組成,用來實現(xiàn)一種文件系統(tǒng)、一個驅(qū)動程序或其他內(nèi)核上層的功能。

二、 編寫一個簡單的模塊

模塊和內(nèi)核都在內(nèi)核空間運行,模塊編程在一定意義上說就是內(nèi)核編程。因為內(nèi)核版本的每次變化,其中的某些函數(shù)名也會相應(yīng)地發(fā)生變化,因此模塊編程與內(nèi)核版本密切相關(guān)。以下例子針對2.6內(nèi)核

1.程序舉例

hellomod.c

// hello world driver for Linux 2.6#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>
/* 必要的頭文件*/static int __init lkp_init( void )
{
printk(“<1>Hello,World! from the kernel space…\n”);
return 0;
}static void __exit lkp_cleanup( void )
{
printk(“<1>Goodbye, World! leaving kernel space…\n”);}module_init(lkp_init);module_exit(lkp_cleanup);MODULE_LICENSE(“GPL”);


?

.說明?
第4行:
??????? 所有模塊都要使用頭文件module.h,此文件必須包含進(jìn)來。
第5行:
??????? 頭文件kernel.h包含了常用的內(nèi)核函數(shù)。
第6行:
??????? 頭文件init.h包含了宏_init和_exit,它們允許釋放內(nèi)核占用的內(nèi)存。
建議瀏覽一下該文件中的代碼和注釋。
第9-12行:
??????? 這是模塊的初始化函數(shù),它必需包含諸如要編譯的代碼、初始化數(shù)據(jù)結(jié)構(gòu)等內(nèi)容。
第11行使用了printk()函數(shù),該函數(shù)是由內(nèi)核定義的,功能與C庫中的printf()類似,
它把要打印的信息輸出到終端或系統(tǒng)日志。字符串中的<1>是輸出的級別,
表示立即在終端輸出。
第15-18行:
??????? 這是模塊的退出和清理函數(shù)。此處可以做所有終止該驅(qū)動程序時相關(guān)的清理工作。
第20行:
??????? 這是驅(qū)動程序初始化的入口點。對于內(nèi)置模塊,內(nèi)核在引導(dǎo)時調(diào)用該入口點;
對于可加載模塊則在該模塊插入內(nèi)核時才調(diào)用。
第21行:
??????? 對于可加載模塊,內(nèi)核在此處調(diào)用module_cleanup()函數(shù),而對于內(nèi)置的模塊,
它什么都不做。
第22行:
??????? 提示可能沒有GNU公共許可證。有幾個宏是在2.4版的內(nèi)核中才開發(fā)的(詳情參見modules.h)。

? 函數(shù)module_init()和cleanup_exit()是模塊編程中最基本也是必須的兩個函數(shù)。
module_init()向內(nèi)核注冊模塊所提供的新功能,
而cleanup_exit()注銷由模塊提供的所有功能。

模塊編程屬于內(nèi)核編程,因此,除了對內(nèi)核相關(guān)知識有所了解外,還需要了解與模塊相關(guān)的知識。

1.應(yīng)用程序與內(nèi)核模塊的比較
為了加深對內(nèi)核模塊的了解,表一給出應(yīng)用程序與內(nèi)核模塊程序的比較。
表一 應(yīng)用程序與內(nèi)核模塊程序的比較

?C語言應(yīng)用程序內(nèi)核模塊程序
使用函數(shù)Libc庫內(nèi)核函數(shù)
運行空間用戶空間內(nèi)核空間
運行權(quán)限普通用戶超級用戶
入口函數(shù)main()module_init()
出口函數(shù)exit()module_exit()
編譯Gcc –cMakefile
連接Gccinsmod
運行直接運行insmod
調(diào)試Gdbkdbug, kdb,kgdb等

從表一我們可以看出,內(nèi)核模塊程序不能調(diào)用libc庫中的函數(shù),它運行在內(nèi)核空間,且只有超級用戶可以對其運行。另外,模塊程序必須通過module_init()和module-exit()函數(shù)來告訴內(nèi)核“我來了”和“我走了”。

2.內(nèi)核符號表(如果對以下第2~4點理解上有困難,可以越過)

如 前所述,Linux內(nèi)核是一個整體結(jié)構(gòu),像一個圓球,而模塊是插入到內(nèi)核中的插件。盡管內(nèi)核不是一個可安裝模塊,但為了方便起見,Linux把內(nèi)核也看作 一個“母”模塊。那么模塊與模塊之間如何進(jìn)行交互呢,一種常用的方法就是共享變量和函數(shù)。但并不是模塊中的每個變量和函數(shù)都能被共享,內(nèi)核只把各個模塊中 主要的變量和函數(shù)放在一個特定的區(qū)段,這些變量和函數(shù)就統(tǒng)稱為符號。到低哪些符號可以被共享? Linux內(nèi)核有自己的規(guī)定。對于內(nèi)核這個特殊的母模塊,在kernel/ksyms.c中定義了從中可以“移出”的符號,例如進(jìn)程管理子系統(tǒng)可以“移出”的符號定義如下:

/* 進(jìn)程管理 */

EXPORT_SYMBOL(do_mmap_pgoff);

EXPORT_SYMBOL(do_munmap);

EXPORT_SYMBOL(do_brk);

EXPORT_SYMBOL(exit_mm);

EXPORT_SYMBOL(schedule);

EXPORT_SYMBOL(jiffies);

EXPORT_SYMBOL(xtime);

你可能對這些變量和函數(shù)已經(jīng)很熟悉。其中宏定義EXPORT_SYMBOL()本身的含義是“移出符號”。為什么說是“移出”呢?因為這些符號本來是內(nèi)核內(nèi)部的符號,通過這個宏放在一個公開的地方,使得裝入到內(nèi)核中的其他模塊可以引用它們。

實際上,僅僅知道這些符號的名字是不夠的,還得知道它們在內(nèi)核地址空間中的地址才有意義。因此,內(nèi)核中定義了如下結(jié)構(gòu)來描述模塊的符號:

struct module_symbol

{

unsigned long value; /*符號在內(nèi)核地址空間中的地址*/

const char *name; /*符號名*/

};

我們可以從/proc/ksyms文件中讀取所有內(nèi)核模塊“移出”的符號,這所有符號就形成內(nèi)核符號表,其格式如下:

內(nèi)存地址 符號名 [所屬模塊]

在模塊編程中,可以根據(jù)符號名從這個文件中檢索出其對應(yīng)的地址,然后直接訪問該地址從而獲得內(nèi)核數(shù)據(jù)。第三列“所屬模塊”指符號所在的模塊名,對于從內(nèi)核這一母模塊移出的符號,這一列為空。

模塊加載后,2.4內(nèi)核下可通過 /proc/ksyms、 2.6 內(nèi)核下可通過/proc/kallsyms查看模塊輸出的內(nèi)核符號

3.模塊依賴

如前所述,內(nèi)核符號表記錄了所有模塊可以訪問的符號及相應(yīng)的地址。當(dāng)一個新的模塊被裝入內(nèi)核后,它所申明的某些符號就會被登記到這個表中,而這些符號可能被其他模塊所引用,這就引出了模塊依賴這個問題。

一個模塊A引用另一個模塊B所移出的符號,我們就說模塊B被模塊A引用,或者說模塊A依賴模塊B。如果要鏈接模塊A,必須先鏈接模塊B。這種模塊間相互依賴的關(guān)系就叫模塊依賴。

4.模塊引用計數(shù)器

為 了確保模塊安全地卸載,每個模塊都有一個引用計數(shù)器。當(dāng)執(zhí)行模塊所涉及的操作時就遞增計數(shù)器,在操作結(jié)束時就遞減這個計數(shù)器;另外,當(dāng)模塊B被模塊A引用 時,模塊B的引用計數(shù)就遞增,引用結(jié)束,計數(shù)器遞減。什么時候可以卸載這個模塊?當(dāng)然只有這個計數(shù)器值為0的時候,例如,當(dāng)一個文件系統(tǒng)還被安裝在系統(tǒng)上 時就不能將其卸載,當(dāng)這個文件系統(tǒng)不再被使用時,引用計數(shù)器就為0,于是可以卸載。

四.模塊編譯

Linux 中最重要的軟件開發(fā)工具是 GCC。GCC 是 GNU 的 C 和 C++ 編譯器。但是,在大型的開發(fā)項目中,通常有幾十到上百個的源文件,如果每次均手工鍵入 gcc 命令進(jìn)行編譯的話,則會非常不方便。因此,人們通常利用 make 工具來自動完成編譯工作。利用這種自動編譯可大大簡化開發(fā)工作,避免不必要的重新編譯。這些工作包括:如果僅修改了某幾個源文件,則只重新編譯這幾個源文件;如果某個頭文件被修改了,則重新編譯所有包含該頭文件的源文件。

1.編譯工具make

實際上,make 工具通過一個稱為 Makefile 的文件來完成并自動維護(hù)編譯工作。Makefile 需要按照某種語法進(jìn)行編寫,其中說明了如何編譯各個源文件并連接生成可執(zhí)行文件,并定義了源文件之間的依賴關(guān)系。下面給出2.6 內(nèi)核模塊的Makefile模板(請參看Makefile的寫法)

?

# Makefile2.6
obj-m += hellomod.o ? ? ? ?# 產(chǎn)生hellomod 模塊的目標(biāo)文件
CURRENT_PATH := $(shell pwd) ? #模塊所在的當(dāng)前路徑
LINUX_KERNEL := $(shell uname -r) ? ?#Linux內(nèi)核源代碼的當(dāng)前版本
LINUX_KERNEL_PATH := /usr/src/linux-headers-$(LINUX_KERNEL) #Linux內(nèi)核源代碼的絕對路徑
all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules ? #編譯模塊了
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean ? ?#清理

注意: 在每個命令前(例如make命令前)要鍵入一個制表符(按TAB鍵產(chǎn)生)

有了Makefile,執(zhí)行make命令,會自動形成相關(guān)的后綴為.o和.ko文件。
到此,模塊編譯好了,該把它插入到內(nèi)核了:
如:$insmod hellomod.ko

? 當(dāng)然,要以系統(tǒng)員的身份才能把模塊插入。

? 成功插入后,可以通過dmesg命令查看,屏幕最后幾行的輸出就是你程序中輸出的內(nèi)容:Hello,World! from the kernel space…

?
當(dāng)模塊不再需要時,可以通過rmmod命令移去,例如

$rmmod hellomod

modutils是管理內(nèi)核模塊的一個軟件包。可以在任何獲得內(nèi)核源代碼的地方獲取Modutils(modutils-x.y.z.tar.gz)源代碼,然后選擇最高級別的patch.x.y.z等于或小于當(dāng)前的內(nèi)核版本,安裝后在/sbin目錄下就會有insomod、rmmod、ksyms、lsmod、modprobe等實用程序。當(dāng)然,通常我們在加載Linux內(nèi)核時,modutils已經(jīng)被載入。
1.Insmod命令
調(diào)用insmod程序把需要插入的模塊以目標(biāo)代碼的形式插入到內(nèi)核中。在插入的時候,insmod自動調(diào)用init_module()函數(shù)運行。注意,只有超級用戶才能使用這個命令,其命令格式為:
# insmod??[path] modulename.c
2. rmmod命令
調(diào)用rmmod程序?qū)⒁呀?jīng)插入內(nèi)核的模塊從內(nèi)核中移出,rmmod會自動運行cleanup_module()函數(shù),其命令格式為:
#rmmod??[path] modulename.c
3.lsmod命令
調(diào)用lsmod程序?qū)@示當(dāng)前系統(tǒng)中正在使用的模塊信息。實際上這個程序的功能就是讀取/proc文件系統(tǒng)中的文件/proc/modules中的信息,其命令格式為:
#lsmod
4.ksyms命令
ksyms這個程序用來顯示內(nèi)核符號和模塊符號表的信息。與lsmod相似,它的功能是讀取/proc文件系統(tǒng)中的另一個文件/proc/kallsyms。

總結(jié)

以上是生活随笔為你收集整理的Linux内核之旅的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。