__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,比如进程管理,在花 ...
随机推荐
- 关于tabBar的图片不能正常显示问题
可以先把图片的源文件的名称后面加上@2x 这种图片显示不正常问题原因可能是没有二倍图造成的!!
- .net entity framework 泛型 更新与增加记录
static public bool SaveOrUpdate<T>(T entity) where T: class { bool result = false; using (wech ...
- QR code 乱谈(一)
缘由 促使草人写这一系列(将会是)文章的原因是二维码现在很流行,很容易接触到,而且二维码又是那么容易就生成——就不说有很多在线的生成器,许多应用软件也都有生成二维码的功能,比如Firefox浏览器.Q ...
- [转载]WCF 几种常见错误
WCF标准的配置文件为: <system.serviceModel> <services> <service name=" ...
- 安装,卸载或重装Vmware Workstation时失败的官方解决方案
最近VMware Workstation又放出更新,遂更新之.安装时提示先卸载旧版本.控制面板和其他软件管理器都不能正常卸载,提示" The MSI '' failed",索性直接 ...
- 自定义 Lint 规则简介
上个月,笔者在巴黎 Droidcon 的 BarCamp 研讨会上聆听了 Matthew Compton 关于编写自己的 Lint 规则的讲话.深受启发之后,笔者想就此话题做进一步的探索. 定义 如果 ...
- RxJava开发精要3-向响应式世界问好
原文出自<RxJava Essentials> 原文作者 : Ivan Morgillo 译文出自 : 开发技术前线 www.devtf.cn 转载声明: 本译文已授权开发者头条享有独家转 ...
- Joda-Time
任何企业应用程序都需要处理时间问题.应用程序需要知道当前的时间点和下一个时间点,有时它们还必须计算这两个时间点之间的路径.使用 JDK 完成这项任务将非常痛苦和繁琐.现在来看看 Joda Time,一 ...
- WCF - Creating WCF Service
http://www.tutorialspoint.com/wcf/wcf_creating_service.htm Creating a WCF service is a simple task u ...
- 【转】IOS 怎么获取外设的广播数据AdvData
原文网址:http://www.deyisupport.com/question_answer/wireless_connectivity/bluetooth/f/103/t/73443.aspx N ...