在阅读源代码的过程中,发现一个头文件有引用:
/** The address of the first device table entry. */
extern device_t devices[];
 
/** The address after the last device table entry. */
extern device_t devices_end[];
 
/** The address of the first "driver_t". */
extern driver_t driver_table_start[];
 
/** The address after the last "driver_t". */
extern driver_t driver_table_end[];
 
然后我翻遍源文件目录,还是没有在任何.c文件里发现曾经定义devices。
(当然最开始,我没注意是extern,所以我先找是在哪里初始化的,然后我发现,并没有初始化。)
 
后来我用grep搜索,总算得到了一点信息,在ld脚本里发现下面一段话:
 
  /*
   * Device table.
   */
  .device_table : ALIGN(64)
  {
    PROVIDE (devices = .);
    KEEP(*(.device_table_base))
    KEEP(*(.device_table))
    KEEP(*(.device_table_end))
    PROVIDE (devices_end = .);
  } >data AT>physmem :data
 
我大致猜测device_table正好是在device_table_base和device_table_end之间,而device_table_base和device_table_end在device_table.c中有定义。
(非常可恨的是它们的实际名字是base_devices和end_devices)
我认为我明白了怎么回事,device_table确实没有定义,只是在链接脚本里定义了。
 
我以同样的方式寻找driver_table_start和driver_table_end,我以为会同样很简单的找到,但是见鬼了,根本没有,怎么回事?
 
我然后找了一个驱动程序,我倒要看看,【既然driver_table不主动添加驱动程序,而驱动程序又怎么添加进driver_table里面的。】
我找到了一个i2cm的driver_t的定义。
//! Add a new "driver" entry.
static const __DRIVER_ATTR driver_t driver_i2cm = {
  .shim_type = I2CM_DEV_INFO__TYPE_VAL_I2CM,
  .name = "i2cm",
  .desc = "I2C Master",
  .ops = &i2cm_ops,
  .stilereq = 1,
};
我发疯了,这是很平常的事啊,这是怎么回事?我注意到注释里那句
//! Add a new "driver" entry.
这样就添加了?那才是见鬼了。
然后我才注意到到那个不同寻常的宏。
/** Magic attribute for "driver_t" definitions. */
#define __DRIVER_ATTR __attribute__((used, section(".driver_table")))
又是__attribute__搞的鬼,上网上略微搜了一下,__attribute__((used, section(".driver_table")))的基本含义是把函数或者数据放到名为driver_table的段。
那么其实每定义一个句 __DRIVER_ATTR driver_t driverXXX就把一个驱动给加载到这个段里。
 
然后我返回来看device_table.c时发下一个我忽视的细节:
 
static const __DEVICE_ATTR_BASE device_t base_devices[] =
static const __DEVICE_ATTR_END device_t end_devices[] =
 
其实这两个变量也是这么定义的。清楚了,清楚了,一下子清楚了,当然要其作用,需要ld链接脚本的支持。
 
后来发现这位仁兄和我有同样的问题。
内核原文件里面extern了一堆变量:extern char _ftext, _etext, _fdata, _edata, _end;但是用source insight在内核的源码目录里面压根就找不到这些变量的定义。最初怀疑这些变量定义在汇编文件中,于是使用命令:
grep _ftext `find ./ -name *.S`查找,令我惊讶的是没有找到。既然源文件中都没有,那么又是什么神奇的力量让程序在链接的时候又能正常链接通过呢?
原来大家都是跟内核学习的啊。
http://my.oschina.net/u/180497/blog/177206 讲了利用gcc的__attribute__编译属性section子项构建初始化函数表。
 
不知道黑客们会不把.init段后面加上自己的函数?
 

链接加载文件gcc __attribute__ section的更多相关文章

  1. 如何使用Class和ClassLoader加载文件

    很多时候我们都需要在程序中加载各种文件,比如在加载配置文件,加载properties文件,或者只是加载一个文本文件,然后输出其中的内容,我在初学java的时候,就对加载文件非常头疼,今天又遇见了加载文 ...

  2. java类加载器加载文件

    例子:采用配置文件加反射的方式创建ArrayList和HashSet的实例对象. //第一种方式:类加载器加载文件 InputStream ips = ReflectTest2.class.getCl ...

  3. spark 加载文件

    spark 加载文件 textFile的参数是一个path,这个path可以是: 1. 一个文件路径,这时候只装载指定的文件 2. 一个目录路径,这时候只装载指定目录下面的所有文件(不包括子目录下面的 ...

  4. 从xib加载文件

    一般自定义View, 如果从xib加载文件, 定义一个类方法, 返回xib + (instancetype)dropdown { return [[[NSBundle mainBundle] load ...

  5. 安装SQL2008时遇到"未能加载文件或"file:///d:microsoft..sql.chainer.packagedata.dll"或它的某个依赖项

    安装SQL2008时遇到"未能加载文件或"file:///d:microsoft..sql.chainer.packagedata.dll"或它的某个依赖项,如下图所示 ...

  6. Java中加载配置文件的集中方式,以及利用ClassLoader加载文件 .

    我们往常进行文件的加载的时候 用到的都是  FileInputStream进行 文件的加载比如下面一个例子 : InputStream in=FileInputStream("1.prope ...

  7. 关于前端本地压缩图片,兼容IOS/Android/PC且自动按需加载文件之lrz.bundle.js

    一.介绍说明主要特点: ①在前端压缩好要上传的图片可以更快的发送给后端,因此也特别适合在移动设备上使用. ②兼容IOS/Android,修复了IOS/Android某些版本已知的BUG. ③按需加载文 ...

  8. 使用PSR-4配合composer autoload 自动加载文件夹

    require 文件很麻烦,使用PSR-4搭配composer一次加载,终生受用. 感觉类似java中的import了,自己先记录一下最近理解的. 用composer管理自己的包吧 安装compose ...

  9. php 开启 opcache 之后 require、include 还会每次都重新加载文件吗?

    当前目录有以下两个文件 index.php <?php var_dump(require 'A.php'); A.php <?php return 123; 接着运行: php -S 0. ...

随机推荐

  1. Annoy解析

    Annoy是高维空间求近似最近邻的一个开源库. Annoy构建一棵二叉树,查询时间为O(logn). Annoy通过随机挑选两个点,并使用垂直于这个点的等距离超平面将集合划分为两部分. 如图所示,图中 ...

  2. 论文翻译 - Multiagent Bidirectionally-Coordinated Nets Emergence of Human-level Coordination in Learning to Play StarCraft Combat Games

    (缺少一些公式的图或者效果图,评论区有惊喜) (个人学习这篇论文时进行的翻译[谷歌翻译,你懂的],如有侵权等,请告知) Multiagent Bidirectionally-Coordinated N ...

  3. ubuntu安装显卡驱动和cuda

    NVIDIA-linux.run安装后,会出现登录页面循环,解决办法是在运行命令后加入-no-opengl-files 打开nvidia x server Settings软件,显示:You do n ...

  4. NO3——BFS

    #include <stdio.h> #include <string.h> #include <queue> using namespace std; struc ...

  5. 修改CodeSmith中的SchemaExplorer.MySQLSchemaProvider

    修改C:\Program Files (x86)\CodeSmith\v6.5\Samples\Projects\CSharp\MySQLSchemaProvider\MySQLSchemaProvi ...

  6. System and Device power management.

    Advanced Configuration and Power Management Interface(ACPI)是由Intel,Microsoft等厂家订的一套Spec,规范了OS,APP对于电 ...

  7. 全局 Ajax 事件处理器

    jQuery中将Ajax请求和响应分成了若干(5)个阶段 并且允许开发者在Ajax请求和响应的不同阶处理不同的逻辑, 这些方法用于注册事件处理器,用来处理页面上的任何 Ajax 请求,当某些事件触发后 ...

  8. Java语言常用的运算符和表达式详解

    Java提供了丰富的运算符,如算术运算符.关系运算符.逻辑运算符.位运算符等等.Java的表达式就是用运算符连接起来的符合Java规则的式子.运算符的优先级决定了表达式中运算执行的先后顺序.在编写程序 ...

  9. 【题解】AHOI2009中国象棋

    还记得第一次看见这题的时候好像还是联赛前后的事了,那时感觉这题好强……其实现在看来蛮简单的,分类讨论一下即可.题意非常的简单:每一行,每一列都不能超过两个棋子.考虑我们的dp,如果一行一行转移的话行上 ...

  10. 【题解】ZJOI2008骑士

    树型打牌:洛谷P2607 这道题目一开始没有想到解法,只是想到没有上司的舞会,觉得十分的类似呀. 之后发现:n个点,n条边,只要删去一条边,就变成了和上题一模一样的做法. 那么考虑删去的这条边,实际上 ...