• __init的用法


    http://blog.csdn.net/eroswang/article/details/2317771

    在kernel中有很多__init,这个东东到底是何方神圣捏?且听小生我一一道来。
    下面是其定义:
    file:/include/linux/init.h
     43 #define __init      __attribute__ ((__section__ (".init.text"))) __cold
     44 #define __initdata  __attribute__ ((__section__ (".init.data")))
     45 #define __exitdata  __attribute__ ((__section__(".exit.data")))
     46 #define __exit_call __attribute_used__ __attribute__ ((__section__ (".exitcall.exit")))

    也许你会问那 __attribute__ ((__section__ (".init.text"))) __cold是什么东东阿?
    且看 info gcc C Extensions Attribute Syntax
    section ("SECTION-NAME")'
         Normally, the compiler places the objects it generates in sections
         like `data' and `bss'.  Sometimes, however, you need additional
         sections, or you need certain particular variables to appear in
         special sections, for example to map to special hardware.  The
         `section' attribute specifies that a variable (or function) lives
         in a particular section.  For example, this small program uses
         several specific section names:
              struct duart a __attribute__ ((section ("DUART_A"))) = { 0 };
              struct duart b __attribute__ ((section ("DUART_B"))) = { 0 };
              char stack[10000] __attribute__ ((section ("STACK"))) = { 0 };
              int init_data __attribute__ ((section ("INITDATA"))) = 0;

              main()
              {
                /* Initialize stack pointer */
                init_sp (stack + sizeof (stack));

                /* Initialize initialized data */
                memcpy (&init_data, &data, &edata - &data);

                /* Turn on the serial ports */
                init_duart (&a);
                init_duart (&b);
              }

         Use the `section' attribute with an _initialized_ definition of a
         _global_ variable, as shown in the example.  GCC issues a warning
         and otherwise ignores the `section' attribute in uninitialized
         variable declarations.

         You may only use the `section' attribute with a fully initialized
         global definition because of the way linkers work.  The linker
         requires each object be defined once, with the exception that
         uninitialized variables tentatively go in the `common' (or `bss')
         section and can be multiply "defined".  You can force a variable
         to be initialized with the `-fno-common' flag or the `nocommon'
         attribute.

         Some file formats do not support arbitrary sections so the
         `section' attribute is not available on all platforms.  If you
         need to map the entire contents of a module to a particular
         section, consider using the facilities of the linker instead.

    简单来说是指示gcc把标记的数据或者函数放到指定sector。
    linux中把一些启动及初始化时候用的数据用__init标识,然后在适当的时候把它们释放,回收内存。
    说到这个__init,就不能不说module_init,subsys_initcall。
    在init.h中我们能够找到 #define subsys_initcall(fn)     __define_initcall("4",fn,4)
    又是一个宏定义,简直是无极中的圆环套圆环之城阿。
    file:/include/linux/init.h
    100 /* initcalls are now grouped by functionality into separate
    101  * subsections. Ordering inside the subsections is determined
    102  * by link order.
    103  * For backwards compatibility, initcall() puts the call in
    104  * the device init subsection.
    105  *
    106  * The `id' arg to __define_initcall() is needed so that multiple initcalls
    107  * can point at the same handler without causing duplicate-symbol build errors.
    108  */
    109

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


    subsys_initcall(usb_init)转换后就变成了 static initcall_t  __initcall_usbinit4   __attribute_used__ /
    __attribute__((__section__(".initcall 4.init"))) = usb_init
    就是把usb_init的函数入口指针存放在.initcall4.init中。
    file:/include/asm-generic/vmlinux.lds.h
    239 #define INITCALLS                           /
    240     *(.initcall0.init)                      /
    241     *(.initcall0s.init)                     /
    242     *(.initcall1.init)                      /
    243     *(.initcall1s.init)                     /
    244     *(.initcall2.init)                      /
    245     *(.initcall2s.init)                     /
    246     *(.initcall3.init)                      /
    247     *(.initcall3s.init)                     /
    248     *(.initcall4.init)                      /
    249     *(.initcall4s.init)                     /
    250     *(.initcall5.init)                      /
    251     *(.initcall5s.init)                     /
    252     *(.initcallrootfs.init)                     /
    253     *(.initcall6.init)                      /
    254     *(.initcall6s.init)                     /
    255     *(.initcall7.init)                      /
    256     *(.initcall7s.init)


    file:/arch/kernel/vmlinux_32.lds.S
    144   .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
    145     __initcall_start = .;
    146     INITCALLS
    147     __initcall_end = .;
    148   }

    展开
       .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
         __initcall_start = .;
         *(.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_end = .;
       }


    那么系统是如何执行这些函数呢?
    此话就长了阿~ 话说盘古开天芙蓉姐姐补天后我们来到了main.c这个linux中举足轻重的文件
    进入start_kernel
    start_kernel  -->rest_init() -->kernel_init()  --> do_basic_setup()  -->do_initcalls()

    这个do_initcalls()就是调用这些函数的地方。
    file:/init/main.c
    662 static void __init do_initcalls(void)
    663 {
    664     initcall_t *call;
    665     int count = preempt_count();
    666
    667     for (call = __initcall_start; call < __initcall_end; call++) {
    668         ktime_t t0, t1, delta;
    669         char *msg = NULL;
    670         char msgbuf[40];
    671         int result;
    672
    673         if (initcall_debug) {
    674             printk("Calling initcall 0x%p", *call);
    675             print_fn_descriptor_symbol(": %s()",
    676                     (unsigned long) *call);
    677             printk("/n");
    678             t0 = ktime_get();
    679         }
    680
    681         result = (*call)();
    682
    683         if (initcall_debug) {
    684             t1 = ktime_get();
    685             delta = ktime_sub(t1, t0);
    686
    687             printk("initcall 0x%p", *call);
    688             print_fn_descriptor_symbol(": %s()",
    689                     (unsigned long) *call);
    690             printk(" returned %d./n", result);
    691
    692             printk("initcall 0x%p ran for %Ld msecs: ",
    693                 *call, (unsigned long long)delta.tv64 >> 20);
    694             print_fn_descriptor_symbol("%s()/n",
    695                 (unsigned long) *call);
    696         }
    697
    698         if (result && result != -ENODEV && initcall_debug) {
    699             sprintf(msgbuf, "error code %d", result);
    700             msg = msgbuf;
    701         }
    702         if (preempt_count() != count) {
    703             msg = "preemption imbalance";
    704             preempt_count() = count;
    705         }
    706         if (irqs_disabled()) {
    707             msg = "disabled interrupts";
    708             local_irq_enable();
    709         }
    710         if (msg) {
    711             printk(KERN_WARNING "initcall at 0x%p", *call);
    712             print_fn_descriptor_symbol(": %s()",
    713                     (unsigned long) *call);
    714             printk(": returned with %s/n", msg);
    715         }
    716     }
    717
    718     /* Make sure there is no pending stuff from the initcall sequence */
    719     flush_scheduled_work();
    720 }

    上一篇:如何阅读源代码 下一篇:系统调用

    <script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
    阅读(321) | 评论(0) | 转发(1) |
    0

    上一篇:linux内核MKDEV()宏

    下一篇:gcc和g++的区别

    给主人留下些什么吧!~~
    评论热议
  • 相关阅读:
    [CSP校内集训]hotel
    DP小技巧——悬线法
    [SDOI2015]寻宝游戏/异象石(LCA)
    [HAOI2006]旅行
    [SDOI2013]泉(搜索+hash+容斥)
    [NOIP校内集训]home
    [AHOI2014/JSOI2014]骑士游戏(SPFA的本质)
    欧拉函数模板
    开学考试题8:神奇的集合(multiset) 动态开点线段树
    开学考试题5:2017黑龙江省选
  • 原文地址:https://www.cnblogs.com/ztguang/p/12647447.html
Copyright © 2020-2023  润新知