Linux學習筆記 核心模組

2021-06-01 00:54:30 字數 4415 閱讀 3366

模組

是linux高效利用微核心,同時不會降低系統效能與優點的一種方法。幾乎linux核心的每個高層元件 --- 檔案系統、裝置驅動、網路,都可以作為模組進行編譯。linux的發布版,充分使用模組方式全面地支援多種品牌型號的硬體。但在某個計算機上只會有效載入其中乙個驅動程式。這樣核心就不會因為裝載那些數以百計的很少使用的程式而變得非常龐大。

當系統程式設計師希望給linux核心增加新功能時,都傾向於把新**作為乙個模組來實現。然而,有些linux**必須被靜態鏈結,在核心編譯時就被包含。這種情況一般發生在元件需要對核心中的某個資料結構或函式進行修改。例如,在描述符或者核心資料結構中引入新字段,或者替換靜態鏈結的**。

核心管理模組的任務主要有兩個:第一是確保核心的其他部分可以訪問該模組的全域性符號,例如指向模組主要實現函式的入口位址。模組還必須知道這些符號在核心及其他模組中的位址。因此,在鏈結模組時,一定要解決模組間的引用關係。第二個任務是記錄模組的使用情況,以便在解除安裝這個模組時,判斷其是否被核心的其他部分使用。系統使用了乙個簡單的引用計數器來記錄每個模組的引用次數。

linux核心許可證gpl嚴格禁止在非gpl許可證下發行相關的源**, 因此,linux核心開發者要求模組開發者在模組源**中使用module_license巨集標出許可證型別。如果許可證是非gpl相容,模組就不能使用核心的許多核心函式和資料結構。而且,使用非gpl許可證的模組會「汙染」核心,核心開發者不會為其提供技術支援。

模組作為elf格式的檔案存放在檔案系統中,並通過執行insmod程式鏈結到核心中。對於每個模組,系統都會分配乙個包含以下資料的記憶體區:

module物件描述乙個模組,所有module物件被乙個雙向迴圈列表串聯起來。鍊錶頭部存放在 modules變數中,而指向相鄰單元的指標存放在每個module物件的list欄位中。

linux/module.h(kernel version 2.6.32)中的module物件描述節選如下:

struct module;

state欄位記錄模組內部狀態,它可以是:

每個模組都有自己的異常表。該錶包括(如果有)模組的修正**的位址。在鏈結模組時,該錶被拷貝到ram中,其開始位址儲存在module物件的extable欄位中。

每個模組都有一組使用計數器,每個cpu乙個,存放在相應module物件的ref欄位中。在模組功能所涉及的操作開始執行時遞增這個計數器,在操作結束時遞減這個計數器。只有所有使用計數器的和為0時,模組才可以被取消鏈結。模組的總的引用計數器就是所有cpu計數器的總和。

當鏈結乙個模組時,必須用合適的位址替換在模組物件**中引用的所有全域性核心符號

(變數和函式)。這個操作與在使用者態編譯程式時鏈結程式所執行的操作非常類似,這是委託給insmod外部程式完成的。核心使用一些專門的核心符號(kernel symbol table),用於儲存模組訪問的符號和相應的位址。它們在核心**段中分三個節:

只有某一現有的模組實際使用的核心符號才會儲存在這個表中。如果需要在某些模組中需要訪問乙個尚未匯出的核心符號,只要在原始碼中增加相應的export_symbol_gpl巨集匯出就可以了。如果許可證不是gpl相容的,就不能為模組合法匯出乙個新符號。已鏈結的模組也可以匯出自己的符號,這樣其他模組就可以訪問這些符號。

當模組b引用另乙個模組a所匯出的符號,在這種情況下,我們就說b裝載在a的上面。為了鏈結模組b,必須首先鏈結模組a。否則,對於模組a所匯出的那些符號的引用就不能適當地鏈結到b中。即兩個模組之間存在著依賴。

模組物件的modules_which_use_me欄位是乙個依賴鍊錶的頭部,該鍊錶儲存其使用的所有模組。鍊錶中的每個元素是乙個小型module_use描述符,該描述符儲存指向鍊錶中相鄰元素的指標及乙個指向相應模組物件的指標。對於上述情況,指向b模組物件的module_use描述符將出現在a的modules_which_use_me鍊錶中。只要有模組裝載在a上,modules_which_use_me鍊錶就必須動態更新。如果a的依賴鍊錶非空,模組a就不能解除安裝。

1. 從命令列中讀取要鏈結的模組名。

2. 確定模組物件**檔案所在的位置,從磁碟讀入存有模組目標**的檔案。

3. 呼叫init_module(),執行sys_init_module()系統呼叫,傳入存有模組目標**的使用者態緩衝區位址、目標**長度和存有insmod程式所需引數的使用者態記憶體區作為引數。

4. 結束。

1. 檢查是否允許使用者鏈結模組,即當前程序必須具有cap_sys_module權能。只要給核心增加功能,安全就是至關重要的。

2. 為模組目標**分配乙個臨時記憶體區,然後拷入作為系統呼叫第乙個引數的使用者態緩衝區資料。

3. 驗證記憶體區中的資料是否是有效的elf模組物件,若不是則返回錯誤碼。

4. 為傳給insmod程式的引數分配乙個記憶體區,並存入使用者態緩衝區的資料,該緩衝區位址是系統呼叫傳入的第三個引數。

5. 查詢modules鍊錶,以驗證模組未被鏈結。通過比較模組名(module物件的name欄位)進行這一檢查。

6. 為模組核心可執行**分配乙個記憶體區,並存入模組相應節的內容。

7. 為模組初始化**分配乙個記憶體區,並存入模組相應節的內容。

8. 為新模組確定模組物件位址,物件映像儲存在模組elf檔案的正文段gnu.linkonce.this_module一節,而模組物件儲存在第6步中的記憶體區。

9. 將第6和7步中分配的記憶體區位址存入模組物件的module_code和module_init欄位。

10. 初始化模組物件的modules_which_use_me鍊錶。當前執行cpu的計數器設為1,而其餘所有的模組引用計數器設為0。

11. 根據模組物件許可證型別設定模組物件的license_gplok標誌。

12. 使用核心符號表與模組符號表,重置模組目標碼。這意味著用相應的邏輯位址偏移量替換所有外部與全域性符號的例項值。

13. 初始化模組物件的syms和gpl_syms欄位,使其指向模組匯出的記憶體中符號表。

14. 模組異常表儲存在模組elf檔案的_extable一節,因此它在第6步中已拷入記憶體區,將其位址存入模組物件的extable欄位。

15. 解析insmod程式的引數,並相應地設定模組變數的值。

16. 註冊模組物件mkobj欄位中的kobject物件,這樣在sysfs檔案系統的module目錄中就有乙個新的子目錄。

17. 釋放第2步中分配的臨時記憶體區。

18. 將模組物件追加到modules鍊錶。

19. 將模組狀態設為module_state_coming。

20. 如果模組物件的init方法已定義,則執行它。

21. 將模組狀態設為module_state_live。

22. 結束並返回0(成功)。

1. 從命令列中讀取要取消的模組的名字。

2. 開啟/proc/modules檔案,其中列出了所有鏈結到核心的模組,檢查待取消模組是否有效鏈結。

3. 呼叫delete_module()系統呼叫,向其傳遞要解除安裝的模組名。

4. 結束。

1. 檢查是否允許使用者取消模組鏈結,即當前程序必須具有cap_sys_module權能。

2. 將模組名存入核心緩衝區。

3. 從modules鍊錶查詢模組的module物件。

4. 檢查模組的modules_which_use_me依賴鍊錶,如果非空就返回乙個錯誤碼。

5. 檢查模組狀態,如果不是module_ state_ live,就返回錯誤碼。

6. 如果模組有自定義init方法,函式就要檢查是否有自定義exit方法。如果沒有自定義exit方法,模組就不能解除安裝,返回乙個退出碼。

7. 為了避免競爭條件,除了執行sys_delete_module()服務例程的cpu外,暫停系統中所有cpu的執行。

8. 把模組狀態設為module_state_going。

9. 如果所有模組引用計數器的累加值大於0,就返回錯誤碼。

10. 如果已定義模組的exit方法,則執行它。

11. 從modules鍊錶刪除模組物件,並且從sysfs檔案系統登出該模組。

12. 從剛才使用的模組依賴鍊錶中刪除模組物件。

13. 釋放相應記憶體區,其中存有模組可執行**、module物件及有關符號和異常表。

14. 返回0(成功)。

模組可以在系統需要其所提供的功能時自動進行鏈結,之後也可以自動刪除。為了自動鏈結模組,核心要建立乙個核心執行緒來執行modprobe外部程式,該程式鏈結命令列中指定的模組,同時考慮由於模組依賴所引起的所有可能因素,並遞迴地鏈結命令列中模組所使用的所有其他模組。對模組依賴進行解析,以及對模組進行查詢的操作最好都在使用者態中實現,因為這需要查詢和訪問檔案系統中的模組物件檔案。

modprobe之所以能夠知道模組間的依賴關係,又是依靠系統啟動時執行的一條depmod命令。該命令查詢放在/lib/module目錄下,為正在執行的核心而編譯的所有模組。然後它就把所有的模組間依賴關係寫入乙個名為modules.dep的檔案。這樣,modprobe就可以對該檔案中存放的資訊和/proc/module檔案產生的鏈結模組鍊錶進行比較。

實際上,modprobe只檢查模組依賴關係,每個模組的實際的鏈結工作是通過建立乙個程序並執行insmod命令來實現的。

LINUX學習筆記21 核心模組

一 linux 核心模組 的開發 1.如何使用需要的元件 a 把所有的元件都編譯進核心檔案 i.缺陷1 核心檔案過大 ii.缺陷2 如果要新增或刪除某個元件,需要重新編譯整個核心 b 使用 核心模組 的機制 i.模組本身並不被編譯進核心檔案 ii.以根據需求,在核心執行期間動態的安裝或解除安裝。2....

Linux核心驅動模組學習

ko檔案在是elf excutable and link format 格式,是一種可重定位的目標檔案。在編譯驅動模組時,我們在makefile中用obj m o來指定生成核心驅動模組檔案,即.ko檔案。首先insmod會通過檔案系統將ko讀到使用者空間的一塊記憶體中,然後執行系統呼叫sys ini...

核心模組筆記

1 解壓核心原始碼到目錄檔案 tar xjvf linux 2.6.22.6.tar.bz2 c home guoqian test4 1 1 cd home guoqian test4 1 1 linux 2.6.22.6 make distclean 2 配置檔案 cp boot config ...