<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Linux模塊機制淺析

      Linux模塊機制淺析

       

      Linux允許用戶通過插入模塊,實現干預內核的目的。一直以來,對linux的模塊機制都不夠清晰,因此本文對內核模塊的加載機制進行簡單地分析。

      模塊的Hello World!

      我們通過創建一個簡單的模塊進行測試。首先是源文件main.cMakefile。

      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'

      使用insmodrmmod命令對模塊進行加載和卸載操作,并使用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);

          ……

      };

      模塊數據結構的initexit函數指針記錄了我們定義的模塊入口函數和出口函數。

      模塊加載

      模塊加載由內核的系統調用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_moduleSYSCALL_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將模塊卸載。

      結論

      如此看來,內核模塊其實并不神秘。傳統的用戶程序需要編譯為可執行程序才能執行,而模塊程序只需要編譯為目標文件的形式便可以加載到內核,有內核實現模塊的鏈接,將之轉化為可執行代碼。同時,在內核加載和卸載的過程中,會通過函數回調用戶定義的模塊入口函數和模塊出口函數,實現相應的功能。

      參考資料

      http://hi.baidu.com/20065562/item/15dcc4ce92c3d510b67a24af

      http://blog.chinaunix.net/uid-26009923-id-3840337.html 

      posted @ 2014-05-15 21:47  Florian  閱讀(18884)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 久久精品成人免费看| 国产一区二区三区不卡自拍| 精品剧情V国产在线观看| 真人作爱90分钟免费看视频| 熟女蜜臀av麻豆一区二区| 日本老熟女一二三区视频| 91久久精品美女高潮不断| 毛片内射久久久一区| 人人妻人人澡人人爽| japanese无码中文字幕| 国产普通话对白刺激| 98久久人妻少妇激情啪啪| 国产精品无码av不卡| 欧美日韩精品一区二区三区在线| jizz国产免费观看| 蜜臀在线播放一区在线播放| 午夜在线不卡| 国产成人免费午夜在线观看| 国产成人精品一区二区三| 天美传媒mv免费观看完整| 熟女人妻视频| 视频一区二区三区自拍偷拍| 国产无码高清视频不卡 | 国产一区二区三区18禁| 午夜通通国产精品福利| 亚洲日韩久久综合中文字幕| 美欧日韩一区二区三区视频| 精品人妻二区中文字幕| 国产99视频精品免费视频76| 国产久免费热视频在线观看| 延安市| 国产成人亚洲日韩欧美| AV人摸人人人澡人人超碰| 极品少妇无套内射视频| 美女又黄又免费的视频| 国产亚洲欧洲av综合一区二区三区| 精品人妻日韩中文字幕| 亚洲国产一区二区三区| 日韩中文免费一区二区| 国产成人8X人网站视频| 美女午夜福利视频一区二区 |