attribute_用法_section_部分

上传人:l**** 文档编号:134776716 上传时间:2020-06-08 格式:DOC 页数:8 大小:42KB
返回 下载 相关 举报
attribute_用法_section_部分_第1页
第1页 / 共8页
attribute_用法_section_部分_第2页
第2页 / 共8页
attribute_用法_section_部分_第3页
第3页 / 共8页
attribute_用法_section_部分_第4页
第4页 / 共8页
attribute_用法_section_部分_第5页
第5页 / 共8页
点击查看更多>>
资源描述

《attribute_用法_section_部分》由会员分享,可在线阅读,更多相关《attribute_用法_section_部分(8页珍藏版)》请在金锄头文库上搜索。

1、attribute 用法 section 部分1. gcc的_attribute_编译属性要了解LinuxKernel代码的分段信息,需要了解一下gcc的_attribute_的编绎属性,_attribute_主要用于改变所声明或定义的函数或 数据的特性,它有很多子项,用于改变作用对象的特性。比如对函数,noline将禁止进行联扩展、noreturn表示没有返回值、pure表明函数除 返回值外,不会通过其它(如全局变量、指针)对函数外部产生任何影响。但这里我们比较感兴趣的是对代码段起作用子项section。_attribute_的section子项的使用格式为:_attribute_(sect

2、ion(section_name)其作用是将作用的函数或数据放入指定名为section_name输入段。这里还要注意一下两个概念:输入段和输出段输入段和输出段是相对于要生成最终的elf或binary时的Link过程说的,Link过程的输入大都是由源代码编绎生成的目标文件.o,那么这些.o 文件中包含的段相对link过程来说就是输入段,而Link的输出一般是可执行文件elf或库等,这些输出文件中也包含有段,这些输出文件中的段就叫做输 出段。输入段和输出段本来没有什么必然的联系,是互相独立,只是在Link过程中,Link程序会根据一定的规则(这些规则其实来源于Link Script),将不同的输入

3、段重新组合到不同的输出段中,即使是段的名字,输入段和输出段可以完全不同。其用法举例如下:int var _attribute_(section(.xdata) = 0;这样定义的变量var将被放入名为.xdata的输入段,(注意:_attribute_这种用法中的括号好像很严格,这里的几个括号好象一个也不能少。)static int _attribute_(section(.xinit) functionA(void).这个例子将使函数functionA被放入名叫.xinit的输入段。需要着重注意的是,_attribute_的section属性只指定对象的输入段,它并不能影响所指定对象最终会放

4、在可执行文件的什么段。2.linuxKernel源代码中与段有关的重要宏定义. 关于_init、_initdata、_exit、_exitdata及类似的宏打开Linux Kernel源代码树中的文件:include/init.h,可以看到有下面的宏定议:#define _init _attribute_ (_section_ (.init.text) _cold#define _initdata _attribute_ ( _section_ (.init.data)#define _exitdata _attribute_ ( _section_ (.exit.data)#define _

5、exit_call _attribute_used_ _attribute_ ( _section_ (.exitcall.exit)#define _init_refok oninline _attribute_ (_section_ (.text.init.refok)#define _initdata_refok _attribute_ (_section_ (.data.init.refok)#define _exit_refok noinline _attribute_ (_section_ (.exit.text.refok).#ifdef MODULE#define _exit

6、_attribute_ ( _section_ (.exit.text) _cold#else#define _exit _attribute_used_ _attribute_ (_section_ (.exit.text) _cold#endif对于经常写驱动模块或翻阅Kernel源代码的人,看到熟悉的宏了吧:_init, _initdata, _exit, _exitdata。_init 宏最常用的地方是驱动模块初始化函数的定义处,其目的是将驱动模块的初始化函数放入名叫.init.text的输入段。对于_initdata来说,用 于数据定义,目的是将数据放入名叫.init.data的输入

7、段。其它几个宏也类似。另外需要注意的是,在以上定意中,用_section_代替了 section。还有其它一些类似的宏定义,这里不一一列出,其作用都是类似的。. 关于initcall的一些宏定义在该文件中,下面这条宏定议更为重要,它是一条可扩展的宏:#define _define_initcall(level,fn,id) static initcall_t _initcall_#fn#id _attribute_used_ _attribute_ (_section_(.initcall level .init) = fn这条宏带有3个参数:level,fn, id,分析该宏可以看出:.其用

8、来定义类型为initcall_t的static函数指针,函数指针的名称由参数fn和id决定:_initcall_#fn#id,这 就是函数指针的名称,它其实是一个变量名称。从该名称的定义方法我们其学到了宏定义的一种高级用法,即利用宏的参数产生名称,这要借助于#这一符号 组合的作用。. 这一函数指针变量放入什么输入段呢,请看_attribute_ (_section_ (.initcall levle .init),输入段的名称由level决定,如果level=1,则输入段是.initcall1.init,如果level=3s,则输入段是.initcall3s.init。这一函数指针变量就是放在

9、用这种方法决定的输入段中的。. 这一定义的函数指针变量的初始值是什么叫,其实就是宏参数fn,实际使用中,fn其实就是真实定义好的函数。该宏定义并不直接使用,请看接下来的这些宏定义:#define pure_initcall(fn) _define_initcall(0,fn,0)#define core_initcall(fn) _define_initcall(1,fn,1)#define core_initcall_sync(fn) _define_initcall(1s,fn,1s)#define postcore_initcall(fn) _define_initcall(2,fn,2

10、)#define postcore_initcall_sync(fn) _define_initcall(2s,fn,2s)#define arch_initcall(fn) _define_initcall(3,fn,3)#define arch_initcall_sync(fn) _define_initcall(3s,fn,3s)#define subsys_initcall(fn) _define_initcall(4,fn,4)#define subsys_initcall_sync(fn) _define_initcall(4s,fn,4s)#define fs_initcall(

11、fn) _define_initcall(5,fn,5)#define fs_initcall_sync(fn) _define_initcall(5s,fn,5s)#define rootfs_initcall(fn) _define_initcall(rootfs,fn,rootfs)#define device_initcall(fn) _define_initcall(6,fn,6)#define device_initcall_sync(fn) _define_initcall(6s,fn,6s)#define late_initcall(fn) _define_initcall(7

12、,fn,7)#define late_initcall_sync(fn) _define_initcall(7s,fn,7s)这些宏定义出来是为了方便的使用_define_initcall宏定义的,上面每条宏第一次使用时都会产生一个新的输入段。接下来还有一条#define _initcall(fn) device_initcall(fn)这一条其实只是定义了另一个别名,即平常使用的_initcall其实就是这儿的device_initcall,用它定义的函数指定位于段.initcall6.init中。. _setup宏的来源及使用_setup这条宏在Linux Kernel中使用最多的地方就是

13、定义处理Kernel启动参数的函数及数据结构,请看下面的宏定义:#define _setup_param(str, unique_id, fn, early) static char _setup_str_#unique_id _initdata _aligned(1) = str; static struct obs_kernel_param _setup_#unique_id _used _section(.init.setup) _attribute_(aligned(sizeof(long) = _setup_str_#unique_id, fn, early #define _set

14、up(str, fn) _setup_param(str, fn, fn, 0)使用Kernel中的例子分析一下这两条定义:_setup(root=,root_dev_setup);这条语句出现在init/do_mounts.c中,其作用是处理Kernel启动时的像root=/dev/mtdblock3之类的参数的。分解一下这条语句,首先变为:_setup_param(root=,root_dev_setup,root_dev_setup,0);继续分解,将得到下面这段代吗:static char _setup_str_root_dev_setup_id _initdata _aligned(1) = root=;static struct obs_kernel_param _setup_root_dev_setup_id_used _section(.init.setup)_attribute_(aligned(sizeof(long)= _setup_str_root_dev_setup_id, root_dev_setup, 0 ;这段代码定义了两个变量:字符数组变量_setup_str_root_dev_setup_id,其初始化容为root=,由于该变量用 _initdata修饰,它将被放入.init.data输入段;另一变量是结构变量_setup_root_de

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > 工作范文

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号