zoukankan      html  css  js  c++  java
  • __attribute__ ((__section__ (".init.text")))

    在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(" ");
    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. ", 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() ",
    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 ", msg);
    715         }
    716     }
    717
    718     /* Make sure there is no pending stuff from the initcall sequence */
    719     flush_scheduled_work();
    720 }

    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    我想把某一个函数放入data段中(放到ram里面去)。
    在这个函数前加了前缀:

    1. void __attribute__((.section ".data.mydata")))myfunc(){
    2.   ……
    3. ……
    4.   ……
    5. }


    编译成功后通过dump文件可以看到myfunc这个函数放在了从0x110 - 0x180这一段(0-0x3ffff是sram)
    所以说_myfunc这个标号的地址应该是0x110,但是通过nm出来的结果却是0x1ad??在0x110处的标号是__gnu__compiled_c。
    所有我的程序在执行这个函数的时候总是跑飞了。请问为什么会出现这样的问题。是不是编译器有错?还是我需要更改参数呢?请各位指教!

    我是直接在data段中写的:

    1. SECTIONS
    2. {
    3. ……
    4. .data 0x100:{

    5. ……
    6. *(.data)
    7. ……
    8. *(.data.mydata)
    9. ……
    10. }

    11. ……
    12. }
    复制代码


    我是这样写的阿。。。会出现这样的情况吗?

  • 相关阅读:
    42. Trapping Rain Water
    223. Rectangle Area
    645. Set Mismatch
    541. Reverse String II
    675. Cut Off Trees for Golf Event
    安装 VsCode 插件安装以及配置
    向上取整 向下取整 四舍五入 产生100以内随机数
    JS 判断是否为数字 数字型特殊值
    移动端初始配置,兼容不同浏览器的渲染内核
    Flex移动布局中单行和双行布局的区别以及使用
  • 原文地址:https://www.cnblogs.com/lixiaofei1987/p/3198638.html
Copyright © 2011-2022 走看看