首頁 > 運維 > linux運維 > linux中引入模組機制有什麼好處

linux中引入模組機制有什麼好處

青灯夜游
發布: 2023-04-06 15:28:34
原創
1367 人瀏覽過

linux中引入模組機制的好處:1、應用程式在退出時,可以不管資源的釋放或其他的清除工作,但是模組的退出函數卻必須仔細此撤銷初始化函數所做的一切;2 、此機制有助於縮短模組的開發週期,即註冊和卸載都很靈活方便。

linux中引入模組機制有什麼好處

本教學操作環境:linux7.3系統、Dell G3電腦。

Linux中引入模組機制有什麼好處?

首先,模組是預先註冊自己以便服務於將來的某個請求,然後他的初始化函數就立即結束。換句話說,模組初始化函數的任務就是為以後呼叫函數預先作準備。

好處:

  • 1) 應用程式在退出時,可以不管資源的釋放或其他的清除工作,但是模組的退出函數必須仔細此撤銷初始化函數所做的一切。

  • 2) 此機制有助於縮短模組的開發週期。即:註冊和卸載都很靈活方便。

Linux模組機制淺析

Linux允許使用者透過插入模組,實現幹預核心的目的。一直以來,對linux的模組機制都不夠清晰,因此本文對核心模組的載入機制進行簡單分析。

模組的Hello World!

我們透過建立一個簡單的模組來測試。首先是原始檔main.c和Makefile。

florian@florian-pc:~/module$ cat main.c

#include<linux/module.h>
#include<linux/init.h>
 
static int __init init(void)
{
    printk("Hi module!\n");
    return 0;
}
 
static void __exit exit(void)
{
    printk("Bye module!\n");
}
 
module_init(init);
module_exit(exit);
登入後複製

其中init為模組入口函數,在模組載入時被呼叫執行,exit為模組出口函數,在模組卸載被呼叫執行。

florian@florian-pc:~/module$ cat Makefile

obj-m += main.o
#generate the path
CURRENT_PATH:=$(shell pwd)
#the current kernel version number
LINUX_KERNEL:=$(shell uname -r)
#the absolute path
LINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL)
#complie object
all:
    make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
#clean
clean:
    make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean
登入後複製

其中,obj-m指定了目標檔案的名稱,檔案名稱需要和來源檔案名稱相同(副檔名除外),以便於make自動推導。

然後使用make指令編譯模組,得到模組檔main.ko。

florian@florian-pc:~/module$ make

make -C /usr/src/linux-headers-2.6.35-22-generic M=/home/florian/module modules
make[1]: 正在进入目录 `/usr/src/linux-headers-2.6.35-22-generic&#39;
  Building modules, stage 2.
  MODPOST 1 modules
make[1]:正在离开目录 `/usr/src/linux-headers-2.6.35-22-generic&#39;
登入後複製

使用insmod和rmmod指令對模組進行載入和卸載操作,並使用dmesg列印核心日誌。

florian@florian-pc:~/module$ sudo insmod main.ko;dmesg | tail -1
[31077.810049] Hi module!
登入後複製
florian@florian-pc:~/module$ sudo rmmod main.ko;dmesg | tail -1
[31078.960442] Bye module!
登入後複製

透過核心日誌訊息,可以看出模組的入口函數和出口函數都被正確調用執行。

模組檔案

使用readelf指令檢視模組檔案main.ko的資訊。

florian@florian-pc:~/module$ readelf -h main.ko

ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2&#39;s complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          1120 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           40 (bytes)
  Number of section headers:         19
  Section header string table index: 16
登入後複製

我們發現main.ko的文件類型為可重定位目標文件,這和一般的目標文件格式沒有任何區別。我們知道,目標檔案是不能直接執行的,它需要經過連結器的位址空間分配、符號解析和重定位的過程,轉換為執行檔才能執行。

那麼,核心將main.ko載入後,是否對其進行了連結呢?

模組資料結構

首先,我們先了解模組的核心資料結構。

linux3.5.2/kernel/module.h:220

struct module
{
    ……
    /* Startup function. */
    int (*init)(void);
    ……
    /* Destruction function. */
    void (*exit)(void);
    ……
};
登入後複製

模組資料結構的init和exit函數指標記錄了我們定義的模組入口函數和出口函數。

模組載入

模組載入由核心的系統呼叫init_module完成。

linux3.5.2/kernel/module.c:3009

/* This is where the real work happens */
SYSCALL_DEFINE3(init_module, void __user *, umod,
       unsigned long, len, const char __user *, uargs)
{
    struct module *mod;
    int ret = 0;
    ……
    /* Do all the hard work */
    mod = load_module(umod, len, uargs);//模块加载
    ……
    /* Start the module */
    if (mod->init != NULL)
       ret = do_one_initcall(mod->init);//模块init函数调用
    ……
    return 0;
}
登入後複製

系統呼叫init_module由SYSCALL_DEFINE3(init_module. ..)實現,其中有兩個關鍵的函數呼叫。 load_module用於模組加載,do_one_initcall用於回調模組的init函數。

函數load_module的實作為。

linux3.5.2/kernel/module.c:2864

/* Allocate and load the module: note that size of section 0 is always
   zero, and we rely on this for optional sections. */
static struct module *load_module(void __user *umod,
                unsigned long len,
                const char __user *uargs)
{
    struct load_info info = { NULL, };
    struct module *mod;
    long err;
    ……
    /* Copy in the blobs from userspace, check they are vaguely sane. */
    err = copy_and_check(&info, umod, len, uargs);//拷贝到内核
    if (err)
       return ERR_PTR(err);
    /* Figure out module layout, and allocate all the memory. */
    mod = layout_and_allocate(&info);//地址空间分配
    if (IS_ERR(mod)) {
       err = PTR_ERR(mod);
       goto free_copy;
    }
    ……
    /* Fix up syms, so that st_value is a pointer to location. */
    err = simplify_symbols(mod, &info);//符号解析
    if (err < 0)
       goto free_modinfo;
    err = apply_relocations(mod, &info);//重定位
    if (err < 0)
       goto free_modinfo;
    ……
}
登入後複製

函數load_module內有四個關鍵的函數呼叫。 copy_and_check將模組從使用者空間拷貝到核心空間,layout_and_allocate為模組進行位址空間分配,simplify_symbols為模組進行符號解析,apply_relocations為模組進行重定位。

由此可見,模組載入時,核心為模組檔案main.ko進行了連結的過程!

至於函數do_one_initcall的實作就比較簡單了。

linux3.5.2/kernel/init.c:673

int __init_or_module do_one_initcall(initcall_t fn)
{
    int count = preempt_count();
    int ret;
    if (initcall_debug)
       ret = do_one_initcall_debug(fn);
    else
       ret = fn();//调用init module
    ……
    return ret;
}
登入後複製

即呼叫了模組的入口函數init 。

模組卸載

模組卸載由核心的系統呼叫delete_module完成。

linux3.5.2/kernel/module.c:768

SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
        unsigned int, flags)
{
    struct module *mod;
    char name[MODULE_NAME_LEN];
    int ret, forced = 0;
    ……
    /* Final destruction now no one is using it. */
    if (mod->exit != NULL)
       mod->exit();//调用exit module
    ……
    free_module(mod);//卸载模块
    ……
}
登入後複製
#

透過回呼exit完成模組的出口函數功能,最後呼叫free_module將模組卸載。

結論

如此看來,核心模組其實並不神祕。傳統的使用者程式需要編譯為可執行程式才能執行,而模組程式只需要編譯為目標檔案的形式便可以載入到內核,有內核實現模組的鏈接,將其轉化為可執行程式碼。同時,在核心載入和卸載的過程中,會透過函數回呼使用者定義的模組入口函數和模組出口函數,實現對應的功能。

相關推薦:《Linux影片教學

以上是linux中引入模組機制有什麼好處的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板