在阅读源代码的过程中,发现一个头文件有引用:
/** 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. VIN码识别:助力汽车后市场转型升级

    随着中国汽车市场的成熟,汽车后市场发展迅速,呈“井喷”式增长.据最新数据统计,2015年,中国汽车后市场产值突破8000亿规模,到2018年有望突破万亿. 所谓汽车后市场是指汽车销售以后,围绕汽车使用 ...

  2. 用jsp实现省市区三级联动下拉

    jsp+jquery实现省市区三级联动下拉 不少系统都需要实现省市区三级联动下拉,像人口信息管理.电子商务网站.会员管理等,都需要填写地址相关信息.而用ajax实现的无刷新省市区三级联动下拉则可以改善 ...

  3. Java进阶知识点1:白捡的扩展性 - 枚举值也是对象

    一.背景 枚举经常被大家用来储存一组有限个数的候选常量.比如下面定义了一组常见数据库类型: public enum DatabaseType { MYSQL, ORACLE, SQLSERVER } ...

  4. 最大流——EK算法

    一.算法理论 [基本思想] 反复寻找源点s到汇点t之间的增广路径,若有,找出增广路径上每一段[容量-流量]的最小值delta,若无,则结束.在寻找增广路径时,可以用BFS来找,并且更新残留网络的值(涉 ...

  5. Understand:高效代码静态分析神器详解(一) | 墨香博客 http://www.codemx.cn/2016/04/30/Understand01/

    Understand:高效代码静态分析神器详解(一) | 墨香博客 http://www.codemx.cn/2016/04/30/Understand01/ ===== 之前用Windows系统,一 ...

  6. SSH答疑解惑系列(一)——spring容器是如何启动的

    SSH框架十分受欢迎,其中有一个原因就是spring可以和Struts2框架无缝整合.在使用spring时,无需手动创建web容器,而是通过配置文件声明式创建spring容器. 在web应用中,创建s ...

  7. 如何使用 window.open() 处理ajax请求返回的url: 在本页面打开并防止浏览器拦截

    ajax请求中用window.open()打开请求返回url(例如实现下载功能时),可能会因为跨域问题导致浏览器拦截 解决办法是:在请求前,打开一个窗口,请求成功后将返回的url直接赋值给该窗口的hr ...

  8. reactor工作模型

  9. [剑指Offer] 25.复杂链表的复制

    /* struct RandomListNode { int label; struct RandomListNode *next, *random; RandomListNode(int x) : ...

  10. 莫比乌斯反演题表II

    bzoj3994:[SDOI2015]约数个数和 **很好推+有个小结论bzoj3309:DZY Loves Math ***很好推+线筛某函数/卡常bzoj4816:[Sdoi2017]数字表格 * ...