利用__attribute__((section()))构建初始化函数表【转】

 转自:

https://mp.weixin.qq.com/s?__biz=MzAwMDUwNDgxOA==&mid=2652663356&idx=1&sn=779762953029c0e0946c22ef2bb0b754&chksm=810f28a1b678a1b747520ba3ee47c9ed2e8ccb89ac27075e2d069237c13974aa43537bff4fba&mpshare=1&scene=1&srcid=0111Ys4k5rkBto22dLokVT5A&pass_ticket=bGNWMdGEbb0307Tm%2Ba%2FzAKZjWKsImCYqUlDUYPZYkLgU061qPsHFESXlJj%2Fyx3VM#rd

本文详细讲解了利用__attribute__((section()))构建初始化函数表,以及Linux内核各级初始化的原理。

 

作者简介:

    廖威雄,2016年本科毕业于暨南大学,目前就职于珠海全志科技股份有限公司从事linux嵌入式系统(Tina Linux)的开发,主要负责文件系统和存储的开发和维护,兼顾linux测试系统的设计和持续集成的维护。

    拆书帮珠海百岛分舵的组织长老,二级拆书家,热爱学习,热爱分享。

利用__attribute__((section()))构建初始化函数表【转】_第1张图片

欢迎投稿:

2018年给Linuxer投稿原创Linux技术文章,一经录取,赠送人民邮电出版社任意在售图书,获得读者红包打赏,和公众号站长宋宝华200元微信红包。

Linuxer-"Linux开发者自己的媒体"第五月稿件和赠书名单

 

欢迎关注Linuxer

利用__attribute__((section()))构建初始化函数表【转】_第2张图片

问题导入

传统的应用编写时,每添加一个模块,都需要在main中添加新模块的初始化

 

利用__attribute__((section()))构建初始化函数表【转】_第3张图片

 

使用__attribute__((section()))构建初始化函数表后,由模块告知main:“我要初始化“,添加新模块再也不需要在main代码中显式调用模块初始化接口。

利用__attribute__((section()))构建初始化函数表【转】_第4张图片

以此实现main与模块之间的隔离,main不再关心有什么模块,模块的删减也不需要修改main。

那么,如何实现这个功能呢?如何实现DECLARE_INIT呢?联想到内核驱动,所有内核驱动的初始化函数表在哪里?为什么添加一个内核驱动不需要修改初始化函数表?

下文会从 构建初始化函数表的原理分析、分析内核module_init实现、演练练习 的3个角度给小伙伴分享。

构建初始化函数表的原理分析

__attribute__((section(”name“)))是gcc编译器支持的一个编译特性(arm编译器也支持此特性),实现在编译时把某个函数/数据放到name的数据段中。因此实现原理就很简单了:

 

1.       模块通过__attribute__((section("name")))的实现,在编译时把初始化的接口放到name数据段中

2.       main在执行初始化时并不需要知道有什么模块需要初始化,只需要把name数据段中的所有初始化接口执行一遍即可

 

首先: gcc -c  test.c -o test.o

此时编译过程中处理了__atribute__((section(XXX))),把标记的变量/函数放到了test.o的XXX的数据段,可用 readelf命令查询。

最后:ld -T  test.o -otest.bin

链接时,test.o的XXX数据段(输入段),最终保存在test.bin的XXX数据段(输出段),如此在bin中构建了初始化函数表。

由于自定义了一个数据段,而默认链接脚本缺少自定义的数据段的声明,因此并不能使用默认的链接脚本。

ld链接命令有两个关键的选项:

ld -T 
                    
                    

你可能感兴趣的:(利用__attribute__((section()))构建初始化函数表【转】)