• 链接加载文件gcc __attribute__ section


    在阅读源代码的过程中,发现一个头文件有引用:
    /** 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段后面加上自己的函数?
     
  • 相关阅读:
    手误【删库】 == 跑路,不存在的 Linux回收站
    大规模集群全网数据备份解决方案
    宝塔Nginx配置防盗链
    Markdown语法
    QFtp编程模型(二)
    Ubuntu驱动程序开发6-Linux内核启动与程序烧写
    Ubuntu下TFTP、NFS和SSH服务搭建
    ubuntu环境变量的三种设置方式
    QByteArray详解
    mysql的索引下推理解和实践
  • 原文地址:https://www.cnblogs.com/likeyiyy/p/3866005.html
Copyright © 2020-2023  润新知