最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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++中二進(jìn)制求補(bǔ)運算符與下標(biāo)運算符的用法

    詳解C++中二進(jìn)制求補(bǔ)運算符與下標(biāo)運算符的用法

    這篇文章主要介紹了C++中二進(jìn)制求補(bǔ)運算符與下標(biāo)運算符的用法,是C++入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2016-01-01
  • Matlab實現(xiàn)遺傳算法的示例詳解

    Matlab實現(xiàn)遺傳算法的示例詳解

    這篇文章主要為大家詳細(xì)介紹了什么是遺傳算法,以及如何利用Matlab從零開始自己寫一個遺傳算法函數(shù),文中的代碼對我們學(xué)習(xí)有一定幫助,需要的可以參考一下
    2022-03-03
  • C++?Qt利用GPU加速計算的示例詳解

    C++?Qt利用GPU加速計算的示例詳解

    這篇文章主要為大家詳細(xì)介紹了在?C++?和?Qt?中如何利用GPU加速計算,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-03-03
  • C語言深入分析浮點型數(shù)據(jù)存儲

    C語言深入分析浮點型數(shù)據(jù)存儲

    使用編程語言進(jìn)行編程時,需要用到各種變量來存儲各種信息。變量保留的是它所存儲的值的內(nèi)存位置。這意味著,當(dāng)您創(chuàng)建一個變量時,就會在內(nèi)存中保留一些空間。您可能需要存儲各種數(shù)據(jù)類型的信息,操作系統(tǒng)會根據(jù)變量的數(shù)據(jù)類型,來分配內(nèi)存和決定在保留內(nèi)存中存儲什么
    2022-08-08
  • 利用C++如何實現(xiàn)一個阻塞隊列詳解

    利用C++如何實現(xiàn)一個阻塞隊列詳解

    這篇文章主要給大家介紹了關(guān)于利用C++如何實現(xiàn)一個阻塞隊列的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • 一文詳解C++關(guān)鍵字nullptr及與NULL的區(qū)別

    一文詳解C++關(guān)鍵字nullptr及與NULL的區(qū)別

    這篇文章主要給大家詳細(xì)介紹了C++關(guān)鍵字nullptr,及?NULL與nullptr的區(qū)別,文中通過代碼示例介紹的非常詳細(xì),需要的朋友可以參考下
    2023-06-06
  • 老生常談C語言鏈表小結(jié)

    老生常談C語言鏈表小結(jié)

    鏈表是一種物理存儲結(jié)構(gòu)上非連續(xù)、非順序的存儲結(jié)構(gòu),數(shù)據(jù)元素的邏輯順序是通過鏈表中的指針鏈接次序?qū)崿F(xiàn)的 ,這篇文章主要介紹了C語言鏈表,需要的朋友可以參考下
    2021-11-11
  • C++實現(xiàn)播放音頻的示例詳解

    C++實現(xiàn)播放音頻的示例詳解

    這篇文章主要為大家詳細(xì)介紹了C++如何利用第三方庫實現(xiàn)播放音頻的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-01-01
  • C/C++判斷素數(shù)的三種方法

    C/C++判斷素數(shù)的三種方法

    這篇文章主要給大家介紹了C/C++判斷素數(shù)的三種方法,常規(guī)的函數(shù)判斷法,埃氏篩法和歐拉篩法這三種方法,并通過代碼示例講解的非常詳細(xì),具有一定的參考價值,需要的朋友可以參考下
    2023-12-12
  • 4組C語言中順序讀寫文件的函數(shù)分享

    4組C語言中順序讀寫文件的函數(shù)分享

    這篇文章主要為大家詳細(xì)介紹了4組C語言中實現(xiàn)順序讀寫文件的函數(shù),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-03-03

最新評論

宁夏| 镶黄旗| 石渠县| 内乡县| 渭源县| 哈密市| 新余市| 高雄市| 白河县| 元阳县| 通州市| 鄱阳县| 灯塔市| 来凤县| 南华县| 平昌县| 呈贡县| 中方县| 桓台县| 资兴市| 唐河县| 卓资县| 城固县| 措勤县| 左贡县| 南平市| 耿马| 柞水县| 荣成市| 亳州市| 若羌县| 定边县| 平阳县| 孝义市| 桑日县| 大名县| 青浦区| 祁东县| 长武县| 连山| 龙海市|