在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. 微软职位内部推荐-ATG Engineer II

    微软近期Open的职位: ATG Engineer - GeneralistReady to work on some of the most advanced hardware on the pla ...

  2. 使用Yeoman搭建 AngularJS 应用 (3) —— 让我们搭建一个网页应用

    原文地址:http://yeoman.io/codelab/setup.html 与Yeoman的交互大多数是通过命令行.在苹果机器需要使用Terminal应用,在Linux使用shell.如果使用W ...

  3. ExtJS4.2学习(16)制作表单(转)

    鸣谢:http://www.shuyangyang.com.cn/jishuliangongfang/qianduanjishu/2013-12-10/188.html --------------- ...

  4. oracle srvctl 命令

    SRVCTL命令可以控制RAC数据库中的instance,listener以及services. 通常SRVCTL在ORACLE用户下执行.下面我们来介绍srvctl命令. 1.通过SRVCTL命令来 ...

  5. [BZOJ 1150] [CTSC2007] 数据备份Backup 【贪心 + 链表】

    题目链接:BZOJ - 1150 题目分析 可以看出,我们选的 k 条边一定是相邻两点之间的线段.我们可以将每条边看成一个点,那么我们就是要在 n-1 个点中选出互不相邻的 k 个,使它们的和最小. ...

  6. 日均百万 PV 的站点如何做性能监测?试试「3M口罩」!

    对很多开发者而言,如果网站的日流量达到百万级别,峰值 PV 也突破了 3 万,这样的站点在线下测试的时候总是让人心力交瘁.... 生产环境下的性能监测问题更是尤其让人头疼! 开发同学在想,运维人员也在 ...

  7. SPRING IN ACTION 第4版笔记-第四章ASPECT-ORIENTED SPRING-007-定义切面的around advice

    一.注解@AspectJ形式 1. package com.springinaction.springidol; import org.aspectj.lang.ProceedingJoinPoint ...

  8. 知识总结: Activity的四种启动模式

    通常情况下,一个应用有一个Task,这个Task就是为了完成某个工作的一系列Activity的集合.而这些Activity又被组织成了堆栈的形式.当一个Activity启动时,就会把它压入该Task的 ...

  9. Android SurfaceView实现全屏播放例子

    public class Mymedia extends Activity implements OnBufferingUpdateListener, OnCompletionListener, Me ...

  10. JQuery实现点击div以外的位置隐藏该div窗口

    简单示例代码: <body> <script type="text/javascript" src="http://ajax.googleapis.co ...