__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("\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里面去)。
在这个函数前加了前缀:
- void __attribute__((.section ".data.mydata")))myfunc(){
- ……
- ……
- ……
- }
编译成功后通过dump文件可以看到myfunc这个函数放在了从0x110 - 0x180这一段(0-0x3ffff是sram)
所以说_myfunc这个标号的地址应该是0x110,但是通过nm出来的结果却是0x1ad??在0x110处的标号是__gnu__compiled_c。
所有我的程序在执行这个函数的时候总是跑飞了。请问为什么会出现这样的问题。是不是编译器有错?还是我需要更改参数呢?请各位指教!
我是直接在data段中写的:
- SECTIONS
- {
- ……
- .data 0x100:{
- ……
- *(.data)
- ……
- *(.data.mydata)
- ……
- }
- ……
- }
复制代码
我是这样写的阿。。。会出现这样的情况吗?
__attribute__ ((__section__ (".init.text")))的更多相关文章
- linux,__attribute__用法
转载:http://hi.baidu.com/twinspace/item/24365251e837c2948d12edf1 1. gcc的__attribute__编译属性 要了解Linux Ker ...
- Linux 内核常见宏定义
我们在阅读Linux内核是,常见到这些宏 __init, __initdata, __initfunc(), asmlinkage, ENTRY(), FASTCALL()等等.它们定义在 /incl ...
- 如何切入 Linux 内核源代码
Makefile不是Make Love 从前在学校,混了四年,没有学到任何东西,每天就是逃课,上网,玩游戏,睡觉.毕业的时候,人家跟我说Makefile我完全不知,但是一说Make Love我就来劲了 ...
- GNU C 扩展(转)
GNU CC 是一个功能非常强大的跨平台 C 编译器,它对 C 语言提供了很多扩展,这些扩展对优化.目标代码布局.更安全的检查等方面提供了很强的支持.这里对支持支持 GNU 扩展的 C 语言成为 GN ...
- Linux内核学习方法
Makefile不是Make Love 从前在学校,混了四年,没有学到任何东西,每天就是逃课,上网,玩游戏,睡觉.毕业的时候,人家跟我说Makefile我完全不知,但是一说Make Love我就来劲了 ...
- attribute section的用法
1. gcc的__attribute__编译属性 要了解Linux Kernel代码的分段信息,需要了解一下gcc的__attribute__的编绎属性,__attribute__主要用于改变所声明或 ...
- GCC扩展(转--对看kernel代码有帮助
http://my.oschina.net/senmole/blog?catalog=153878 Linux Kernel的代码,上次就发现一个结构体的定义形式看不懂,后来才知道它用的不是标准的AN ...
- linux初始化宏__init, __exit
我们在内核中经常遇到初始化函数是这样定义的:static int __init init_func(); ,与普通函数相比,定义中多了__init.那么,__init是什么意思呢?还有与其匹配的__e ...
- Linux内核(3) - 分析内核源码如何入手(下)
下面的分析,米卢教练说了,内容不重要,重要的是态度.就像韩局长对待日记的态度那样,严谨而细致. 只要你使用这样的态度开始分析内核,那么无论你选择内核的哪个部分作为切入点,比如USB,比如进程管理,在花 ...
随机推荐
- 我的第一个BAE python应用
第一步 用baidu帐号登陆开发者中心 http://developer.baidu.com/ Baidu的引导,帮助说明已经很详细, 这里不重复. 第二步,创建新版本 用svn check out ...
- Amazon Alexa 语音识别2 : 设置
开发者建立的Skill的主要设置项目都在Skill的console内.需要填写的东西大致有以下几个: 1.Skill 名字.这个名字是用户用来唤醒你这个Skill的. 2.Intent Schema: ...
- 解决Matlab启动时 " Can't check 9.0 VCRTs The application has failed to start because……" 的错误
注:转载或引用请注明出处 今天在winserver 2012 r2 上安装matlab 2016b , 安装完成运行时提示: ERROR: Cnn't check 9.0 VCRTs <star ...
- 如何登录mysql? cmd怎么连接mysql数据库
Mysql开源数据库,任何人都可以下载安装使用.那么安装好的mysql如何登陆连接mysql数据库呢? 连接mysql数据库的几种方法 一 Mysql命令行连接 一般对于刚刚安装好的mysql,如果勾 ...
- *[codility]ArrayInversionCount
http://codility.com/demo/take-sample-test/arrayinversioncount 求逆序对数,归并排序并记录逆序次数. // you can also use ...
- Android Binder设计与实现 - 设计篇
要 Binder是Android系统进程间通信(IPC)方式之一.Linux已经拥有管道,system V IPC,socket等IPC手段,却还要倚赖Binder来实现进程间通信,说明Binder具 ...
- css揭秘之linear-gradient
很神奇的背景设置, 看代码, <html> <title>css</title> <style> .content { background: line ...
- 如何从Win7中提取制作Windows PE3.0
在D盘新建文件夹winpe,在winpe中新建sources.pe3和new文件夹,把附件中提供的工具imagex连文件夹一起放到winpe目录中. 制作方法: 1.把windows7光盘(或光盘镜像 ...
- js 获取服务器控件
大致是HtmlControl被服务器发送到页面ID不变,比如<div id="a" runat="sever"></div> WebCo ...
- 从Spring HibernateTemplate模板方法设计模式的实现谈起
概述 模板方法模式是GOF设计模式中很典型的设计模式,其意图是由抽象父类控制顶级逻辑,并把基本操作的实现推迟到子类去实现,这是通过继承的手段来达到对象的复用.Spring模板方法模式实际是模板方法模式 ...