欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語言 module_init函數(shù)與initcall案例詳解

 更新時間:2021年08月25日 09:13:37   作者:penghan  
這篇文章主要介紹了C語言 module_init函數(shù)與initcall案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下

module_init這個函數(shù)對做驅(qū)動的人來說肯定很熟悉,這篇文章用來跟一下這個函數(shù)的實現(xiàn)。

在include/linux/init.h里面有module_init的定義,自然,因為一個module可以在內(nèi)核啟動時自動加載進(jìn)內(nèi)核,也可以由我們手動在需要時加載進(jìn)內(nèi)核,基于這種場景,內(nèi)核使用了MODULE這個宏,見代碼:

#ifndef MODULE

#ifndef __ASSEMBLY__

...

#define __define_initcall(level,fn,id) \
    static initcall_t __initcall_##fn##id __attribute_used__ \
    __attribute__((__section__(".initcall" level ".init"))) = fn

#define pure_initcall(fn)        __define_initcall("0",fn,0)

#define core_initcall(fn)        __define_initcall("1",fn,1)
#define core_initcall_sync(fn)        __define_initcall("1s",fn,1s)
#define postcore_initcall(fn)        __define_initcall("2",fn,2)
#define postcore_initcall_sync(fn)    __define_initcall("2s",fn,2s)
#define arch_initcall(fn)        __define_initcall("3",fn,3)
#define arch_initcall_sync(fn)        __define_initcall("3s",fn,3s)
#define subsys_initcall(fn)        __define_initcall("4",fn,4)
#define subsys_initcall_sync(fn)    __define_initcall("4s",fn,4s)
#define fs_initcall(fn)            __define_initcall("5",fn,5)
#define fs_initcall_sync(fn)        __define_initcall("5s",fn,5s)
#define rootfs_initcall(fn)        __define_initcall("rootfs",fn,rootfs)
#define device_initcall(fn)        __define_initcall("6",fn,6)
#define device_initcall_sync(fn)    __define_initcall("6s",fn,6s)
#define late_initcall(fn)        __define_initcall("7",fn,7)
#define late_initcall_sync(fn)        __define_initcall("7s",fn,7s)

#define __initcall(fn) device_initcall(fn)

#define module_init(x)    __initcall(x);

#else /* MODULE */

...

#define module_init(initfn)                    \
    static inline initcall_t __inittest(void)        \
    { return initfn; }                    \
    int init_module(void) __attribute__((alias(#initfn)));...

當(dāng)我們使用make menuconfig來配置內(nèi)核時,將某個module配置為m時,MODULE這個宏就被定義了,而當(dāng)配置為y時,則沒有定義,具體的實現(xiàn)在kernel的根Makefile(-DMODULE)里。

現(xiàn)在我們先看下第一種情況,即把module配置為m的情況,即else分支的代碼。

先看下initcall_t的定義:

typedef int (*initcall_t)(void);

它是一個接收參數(shù)為void, 返回值為int類型的函數(shù)指針。這樣就明白了,其實前兩句話只是做了一個檢測,當(dāng)你傳進(jìn)來的函數(shù)指針的參數(shù)和返回值與initcall_t不一致時,就會有告警。
重點在第三句,是使用alias將initfn變名為init_module,我們知道,kernel 2.4版本之前都是用init_module來加載模塊的。這樣做應(yīng)該是為了不用修改load module的那塊代碼吧。

當(dāng)我們調(diào)用insmod將module加載進(jìn)內(nèi)核時,會去找init_module作為入口地址,即是我們的initfn, 這樣module就被加載了。

取nvme.ko為例,我們可以通過objdump -t nvme.ko 查看該模塊的符號表,發(fā)現(xiàn)init_module和nvme_init指向同一個偏移量。如下:

現(xiàn)在看第二種情況,即我們選擇將模塊編進(jìn)內(nèi)核,讓它隨內(nèi)核啟動而加載。

這種情況下module_init最終會調(diào)用__define_initcall宏,這個宏的作用就是將我們的初始化函數(shù)放在".initcall" level ".init"中。

在這里是.initcall6.init, 它的位置可以在Vmlinux.lds.h里面找到:

#define INITCALLS                            \
      *(.initcall0.init)                        \
      *(.initcall0s.init)                        \
      *(.initcall1.init)                        \
      *(.initcall1s.init)                        \
      *(.initcall2.init)                        \
      *(.initcall2s.init)                        \
      *(.initcall3.init)                        \
      *(.initcall3s.init)                        \
      *(.initcall4.init)                        \
      *(.initcall4s.init)                        \
      *(.initcall5.init)                        \
      *(.initcall5s.init)                        \
    *(.initcallrootfs.init)                        \
      *(.initcall6.init)                        \
      *(.initcall6s.init)                        \
      *(.initcall7.init)                        \
      *(.initcall7s.init)

而INITCALL可以在vmlinux.lds.S里面找到:

.init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {
      __init_begin = .;
    _sinittext = .;
    *(.init.text)
    _einittext = .;
  }
  .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) }
  . = ALIGN(16);
  .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) {
      __setup_start = .;
    *(.init.setup)
      __setup_end = .;
   }
  .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
      __initcall_start = .;
    INITCALLS
      __initcall_end = .;
  }
  .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) {
      __con_initcall_start = .;
    *(.con_initcall.init)
      __con_initcall_end = .;
  }

上面貼出來的代碼是系統(tǒng)啟動時存放初始化數(shù)據(jù)的地方,執(zhí)行完成后不再需要,會被釋放掉。根據(jù)上面的內(nèi)存布局,可以列出初始化宏和內(nèi)存的對應(yīng)關(guān)系:

_init_begin              -------------------

                        |  .init.text       | ---- __init

                        |-------------------|

                        |  .init.data       | ---- __initdata

_setup_start       |-------------------|

                        |  .init.setup      | ---- __setup_param

__initcall_start   |-------------------|

                        |  .initcall1.init  | ---- core_initcall

                        |-------------------|

                        |  .initcall2.init  | ---- postcore_initcall

                        |-------------------|

                        |  .initcall3.init  | ---- arch_initcall

                        |-------------------|

                        |  .initcall4.init  | ---- subsys_initcall

                        |-------------------|

                        |  .initcall5.init  | ---- fs_initcall

                        |-------------------|

                        |  .initcall6.init  | ---- device_initcall

                        |-------------------|

                        |  .initcall7.init  | ---- late_initcall

__initcall_end    |-------------------|

                        |                   |

                        |    ... ... ...    |

                        |                   |

__init_end              -------------------

而各個initcall被調(diào)用的地方在kernel_init-》do_basic_setup-》do_initcalls里面:

static void __init do_initcalls(void)
{
    initcall_t *call;
    int count = preempt_count();

    for (call = __initcall_start; call < __initcall_end; call++) {
        ktime_t t0, t1, delta;
        char *msg = NULL;
        char msgbuf[40];
        int result;

        if (initcall_debug) {
            printk("Calling initcall 0x%p", *call);
            print_fn_descriptor_symbol(": %s()",
                    (unsigned long) *call);
            printk("\n");
            t0 = ktime_get();
        }

        result = (*call)();
...
}

到此這篇關(guān)于C語言 module_init函數(shù)與initcall案例詳解的文章就介紹到這了,更多相關(guān)C語言 module_init函數(shù)與initcall內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 深入了解C++ 結(jié)構(gòu)體(struct)與共用體(union)

    深入了解C++ 結(jié)構(gòu)體(struct)與共用體(union)

    這篇文章主要介紹了C++ 結(jié)構(gòu)體與共用體的的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)c++,感興趣的朋友可以了解下
    2020-08-08
  • C語言中循環(huán)嵌套的應(yīng)用方式

    C語言中循環(huán)嵌套的應(yīng)用方式

    這篇文章主要介紹了C語言中循環(huán)嵌套的應(yīng)用方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • C語言判斷數(shù)是否為素數(shù)與素數(shù)輸出

    C語言判斷數(shù)是否為素數(shù)與素數(shù)輸出

    大家好,本篇文章主要講的是C語言判斷數(shù)是否為素數(shù)與素數(shù)輸出,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • C語言 二級指針詳解及示例代碼

    C語言 二級指針詳解及示例代碼

    本文主要介紹C語言 二級指針,這里整理了C語言中二級指針的基礎(chǔ)資料并附有示例代碼和實現(xiàn)結(jié)果,幫助大家學(xué)習(xí)理解相關(guān)知識,有學(xué)習(xí)的朋友可以參考下
    2016-08-08
  • C語言編程數(shù)據(jù)結(jié)構(gòu)帶頭雙向循環(huán)鏈表全面詳解

    C語言編程數(shù)據(jù)結(jié)構(gòu)帶頭雙向循環(huán)鏈表全面詳解

    這篇文章主要為大家介紹了C語言編程的數(shù)據(jù)結(jié)構(gòu)中帶頭雙向循環(huán)鏈表全面詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助祝大家多多進(jìn)步,早日升職加薪
    2021-10-10
  • C++生成不重復(fù)的隨機(jī)整數(shù)

    C++生成不重復(fù)的隨機(jī)整數(shù)

    這篇文章主要為大家詳細(xì)介紹了C++生成不重復(fù)的隨機(jī)整數(shù),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-09-09
  • C++算法與泛型算法(algorithm、numeric)

    C++算法與泛型算法(algorithm、numeric)

    這篇文章主要介紹了C++算法與泛型算法(algorithm、numeric),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • C語言實現(xiàn)俄羅斯方塊課程設(shè)計

    C語言實現(xiàn)俄羅斯方塊課程設(shè)計

    這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)俄羅斯方塊課程設(shè)計,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • C++ 智能指針的魅力你都了解嗎

    C++ 智能指針的魅力你都了解嗎

    智能指針使用和普通指針類似。解引用一個智能指針返回它指向的對象。如果在一個條件判斷中使用智能指針,效果就是檢測它是否為空,本文給大家介紹C++ 智能指針的相關(guān)知識,感興趣的朋友一起看看吧
    2021-06-06
  • C++?OpenCV中幾種基本的圖像處理方式

    C++?OpenCV中幾種基本的圖像處理方式

    大家好,本篇文章主要講的是C++?OpenCV中幾種基本的圖像處理方式,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01

最新評論