中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

linux中引入模塊機制的好處是什么

發布時間:2023-04-19 10:59:43 來源:億速云 閱讀:147 作者:iii 欄目:建站服務器

本文小編為大家詳細介紹“linux中引入模塊機制的好處是什么”,內容詳細,步驟清晰,細節處理妥當,希望這篇“linux中引入模塊機制的好處是什么”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。

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

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'
 Building modules, stage 2.
 MODPOST 1 modules
make[1]:正在離開目錄 `/usr/src/linux-headers-2.6.35-22-generic'

使用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'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中引入模塊機制的好處是什么”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

山阴县| 桐庐县| 大厂| 扶风县| 石河子市| 湾仔区| 循化| 张掖市| 鲁甸县| 吐鲁番市| 咸宁市| 杂多县| 雷山县| 遂川县| 河北省| 彝良县| 山阴县| 宁津县| 玛纳斯县| 济阳县| 贡嘎县| 长阳| 元朗区| 建阳市| 彭泽县| 安多县| 繁峙县| 乌拉特中旗| 海门市| 德安县| 佳木斯市| 星子县| 卢龙县| 高雄市| 布拖县| 邵阳市| 义乌市| 镇坪县| 汕头市| 连山| 绵阳市|