模組程式設計屬於核心程式設計,因此,除了對核心相關知識有所了解外,還需要了解與模組相關的知識。
1.應用程式與核心模組的比較
為了加深對核心模組的了解,表一給出應用程式與核心模組程式的比較。
表一 應用程式與核心模組程式的比較
c語言應用程式 ??? 核心模組程式
使用函式 ??? libc庫 ????????????????? 核心函式
執行空間 ??? 使用者空間 ?? ? ? ? ? ?? 核心空間
執行許可權 ??? 普通使用者 ????????????? 超級使用者
入口函式 ??? main() ????????????????? module_init()
出口函式 ??? exit() ??????????????????? module_exit()
編譯 ?????????? gcc –c ?? ? ? ? ? ? ? ? makefile
連線 ?? ? ? ? ? gcc ????????????????????? insmod
執行 ?????????? 直接執行 ????????????? insmod
除錯 ?????????? gdb ???????????????????? kdbug, kdb,kgdb等
從表一我們可以看出,核心模組程式不能呼叫libc庫中的函式,它執行在核心空間,且只有超級使用者可以對其執行。另外,模組程式必須通過module_init()和module-exit()函式來告訴核心「我來了」和「我走了」。
2.核心符號表(如果對以下第2~4點理解上有困難,可以越過)
如前所述,linux核心是乙個整體結構,像乙個圓球,而模組是插入到核心中的外掛程式。儘管核心不是乙個可安裝模組,但為了方便起見,linux把核心也看作乙個「母」模組。那麼模組與模組之間如何進行互動呢,一種常用的方法就是共享變數和函式。但並不是模組中的每個變數和函式都能被共享,核心只把各個模組中主要的變數和函式放在乙個特定的區段,這些變數和函式就統稱為符號。到低哪些符號可以被共享? linux核心有自己的規定。對於核心這個特殊的母模組,在kernel/ksyms.c中定義了從中可以「移出」的符號,例如程序管理子系統可以「移出」的符號定義如下:
/* 程序管理 */
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); …
你可能對這些變數和函式已經很熟悉。其中巨集定義export_symbol()本身的含義是「移出符號」。為什麼說是「移出」呢?因為這些符號本來是核心內部的符號,通過這個巨集放在乙個公開的地方,使得裝入到核心中的其他模組可以引用它們。
struct module_symbol ;
我們可以從/proc/ksyms檔案中讀取所有核心模組「移出」的符號,這所有符號就形成核心符號表,其格式如下:
記憶體位址 符號名 [所屬模組]
在模組程式設計中,可以根據符號名從這個檔案中檢索出其對應的位址,然後直接訪問該位址從而獲得核心資料。第三列「所屬模組」指符號所在的模組名,對於從核心這一母模組移出的符號,這一列為空。
模組載入後,2.4核心下可通過 /proc/ksyms、 2.6 核心下可通過/proc/kallsyms檢視模組輸出的核心符號
3.模組依賴
如前所述,核心符號表記錄了所有模組可以訪問的符號及相應的位址。當乙個新的模組被裝入核心後,它所申明的某些符號就會被登記到這個表中,而這些符號可能被其他模組所引用,這就引出了模組依賴這個問題。
乙個模組a引用另乙個模組b所移出的符號,我們就說模組b被模組a引用,或者說模組a依賴模組b。如果要鏈結模組a,必須先鏈結模組b。這種模組間相互依賴的關係就叫模組依賴。
4.模組引用計數器
為了確保模組安全地解除安裝,每個模組都有乙個引用計數器。當執行模組所涉及的操作時就遞增計數器,在操作結束時就遞減這個計數器;另外,當模組b被模組a引用時,模組b的引用計數就遞增,引用結束,計數器遞減。什麼時候可以解除安裝這個模組?當然只有這個計數器值為0的時候,例如,當乙個檔案系統還被安裝在系統上時就不能將其解除安裝,當這個檔案系統不再被使用時,引用計數器就為0,於是可以解除安裝。
四.模組編譯
linux 中最重要的軟體開發工具是 gcc。gcc 是 gnu 的 c 和 c++ 編譯器。但是,在大型的開發專案中,通常有幾十到上百個的原始檔,如果每次均手工鍵入 gcc 命令進行編譯的話,則會非常不方便。因此,人們通常利用 make 工具來自動完成編譯工作。利用這種自動編譯可大大簡化開發工作,避免不必要的重新編譯。這些工作包括:如果僅修改了某幾個原始檔,則只重新編譯這幾個原始檔;如果某個標頭檔案被修改了,則重新編譯所有包含該標頭檔案的原始檔。
1.編譯工具make
實際上,make 工具通過乙個稱為 makefile 的檔案來完成並自動維護編譯工作。makefile 需要按照某種語法進行編寫,其中說明了如何編譯各個原始檔並連線生成可執行檔案,並定義了原始檔之間的依賴關係。下面給出2.6 核心模組的makefile模板(請參看makefile的寫法)
# makefile2.6
obj-m += hellomod.o??????? # 產生hellomod 模組的目標檔案
current_path := $(shell pwd)?? #模組所在的當前路徑
linux_kernel := $(shell uname -r)??? #linux核心源**的當前版本
linux_kernel_path := /usr/src/linux-headers-$(linux_kernel) #linux核心源**的絕對路徑
all:
make -c $(linux_kernel_path) m=$(current_path) modules?? #編譯模組了
clean:
make -c $(linux_kernel_path) m=$(current_path) clean??? #清理
注意: 在每個命令前(例如make命令前)要鍵入乙個製表符(按tab鍵產生)
有了makefile,執行make命令,會自動形成相關的字尾為.o和.ko檔案。
到此,模組編譯好了,該把它插入到核心了:
如:$insmod hellomod.ko
當然,要以系統員的身份才能把模組插入。
成功插入後,可以通過dmesg命令檢視,螢幕最後幾行的輸出就是你程式中輸出的內容:hello,world! from the kernel space…
當模組不再需要時,可以通過rmmod命令移去,例如
$rmmod hellomod
核心模組程式設計之入門(二) 必備知識
模組程式設計屬於核心程式設計,因此,除了對核心相關知識有所了解外,還需要了解與模組相關的知識。1 應用程式與核心模組的比較 為了加深對核心模組的了解,表一給出應用程式與核心模組程式的比較。表一 應用程式與核心模組程式的比較 c語言應用程式 核心模組程式 使用函式 libc庫 核心函式 執行空間 使用...
核心模組程式設計入門之二
模組程式設計屬於核心程式設計,因此,除了對核心相關知識有所了解外,還需要了解與模組相關的知識。1 應用程式與核心模組的比較 為了加深對核心模組的了解,表一給出應用程式與核心模組程式的比較。表一 應用程式與核心模組程式的比較 c語言應用程式 核心模組程式 使用函式 libc庫 核心函式 執行空間 使用...
核心模組程式設計入門總結 1
1.出現編譯的模組不符合當前模組的問題 原因 基本都是因為在用gcc編譯的時候加入了 i引數指定原始碼樹,但是所指定的版本和當前的核心版本衝突的問題。比如我碰到的是2.4.20 8custom rh9.0自帶的核心 的問題,和我們後來編譯的2.4.20 8的衝突。解決 修正.include linu...