在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 }

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

我想把某一个函数放入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. }

复制代码

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

__attribute__ ((__section__ (".init.text")))的更多相关文章

  1. linux,__attribute__用法

    转载:http://hi.baidu.com/twinspace/item/24365251e837c2948d12edf1 1. gcc的__attribute__编译属性 要了解Linux Ker ...

  2. Linux 内核常见宏定义

    我们在阅读Linux内核是,常见到这些宏 __init, __initdata, __initfunc(), asmlinkage, ENTRY(), FASTCALL()等等.它们定义在 /incl ...

  3. 如何切入 Linux 内核源代码

    Makefile不是Make Love 从前在学校,混了四年,没有学到任何东西,每天就是逃课,上网,玩游戏,睡觉.毕业的时候,人家跟我说Makefile我完全不知,但是一说Make Love我就来劲了 ...

  4. GNU C 扩展(转)

    GNU CC 是一个功能非常强大的跨平台 C 编译器,它对 C 语言提供了很多扩展,这些扩展对优化.目标代码布局.更安全的检查等方面提供了很强的支持.这里对支持支持 GNU 扩展的 C 语言成为 GN ...

  5. Linux内核学习方法

    Makefile不是Make Love 从前在学校,混了四年,没有学到任何东西,每天就是逃课,上网,玩游戏,睡觉.毕业的时候,人家跟我说Makefile我完全不知,但是一说Make Love我就来劲了 ...

  6. attribute section的用法

    1. gcc的__attribute__编译属性 要了解Linux Kernel代码的分段信息,需要了解一下gcc的__attribute__的编绎属性,__attribute__主要用于改变所声明或 ...

  7. GCC扩展(转--对看kernel代码有帮助

    http://my.oschina.net/senmole/blog?catalog=153878 Linux Kernel的代码,上次就发现一个结构体的定义形式看不懂,后来才知道它用的不是标准的AN ...

  8. linux初始化宏__init, __exit

    我们在内核中经常遇到初始化函数是这样定义的:static int __init init_func(); ,与普通函数相比,定义中多了__init.那么,__init是什么意思呢?还有与其匹配的__e ...

  9. Linux内核(3) - 分析内核源码如何入手(下)

    下面的分析,米卢教练说了,内容不重要,重要的是态度.就像韩局长对待日记的态度那样,严谨而细致. 只要你使用这样的态度开始分析内核,那么无论你选择内核的哪个部分作为切入点,比如USB,比如进程管理,在花 ...

随机推荐

  1. win2003 sp2+iis 6.0上部署.net 2.0和.net 4.0网站的方法

    网站环境 IIS6.0,操作系统Windows server2003 sp2,服务器之前已经部署了.net 2.0和asp的网站,现在要部署新开发的.net 4.0网站.本来认为很简单,却遇到了很多问 ...

  2. centos 卸载vsftpd方法

    centos 卸载vsftpd方法 在服务器上安装了vsftpd,配置出错需要卸载vsftpd.卸载vsftpd的命令如下: 1 [root@localhost ~]# rpm -aq vsftpd2 ...

  3. JavaScript typeof function()的注意事项

    首先,上一段代码: var f = function g() { return 23; }; console.log(typeof g); //输出undefined //console.log(ty ...

  4. 继续完成昨天的第一个点:更改DJANGO的ADMIN后台的表单显示

    遇到的问题是MANYTOMANY的选项太多,默认的DJANGO一个多选框搞得人蛋疼, 于是作了一个扩展,不是最好的,但方便多啦.. 也是在昨天说过的各个app的admin.py里操作: from dj ...

  5. Android List去掉重复数据

    今天用数据库获取数据发现有个字段的数据重复了,于是就写了下面这个方法去除重复的数据. public static List<String> removeDuplicate(List< ...

  6. Android ExpandableListView使用+获取SIM卡状态信息

    ExpandableListView 是一个可以实现下拉列表的控件,大家可能都用过QQ,QQ中的好友列表就是用ExpandableListView实现的,不过它是自定义的适配器.本篇 博客除了要介绍E ...

  7. URAL1017. Staircases

    链接 简单递推 #include <iostream> #include<cstdio> #include<cstring> #include<algorit ...

  8. mapreduce实现"浏览该商品的人大多数还浏览了"经典应用

    输入: 日期    ...cookie id.        ...商品id.. xx            xx                        xx 输出: 商品id        ...

  9. 放在jsp头部的代码

    String path = request.getContextPath(); String basePath = request.getScheme()+"://"+reques ...

  10. [FOJ 1752] A^B mod C

    Problem 1752 A^B mod C Accept: 750    Submit: 3205Time Limit: 1000 mSec    Memory Limit : 32768 KB   ...