由_OF_DECLARE引发对内核SECTION段解析的思考(基于kernel-4.9)

原创 2018年04月17日 15:08:36

这个宏定义是定义在of.h中的,主要目的就是为了方便解析dts文件的。

#ifdef CONFIG_OF
#define _OF_DECLARE(table, name, compat, fn, fn_type)           \
    static const struct of_device_id __of_table_##name      \
        __used __section(__##table##_of_table)          \
         = { .compatible = compat,              \
             .data = (fn == (fn_type)NULL) ? fn : fn  }
#else
#define _OF_DECLARE(table, name, compat, fn, fn_type)           \
    static const struct of_device_id __of_table_##name      \
        __attribute__((unused))                 \
         = { .compatible = compat,              \
             .data = (fn == (fn_type)NULL) ? fn : fn }
#endif

以上的定义来看,它使用了__section,其实展开以后可以看到,其实是传递给编译器的一个attribute:

/* Simple shorthand for a section definition */
#ifndef __section
# define __section(S) __attribute__ ((__section__(#S)))
#endif

关于attribute的使用,可以参考gcc相关的文档,简而言之,上面的一段宏定义实现的功能就是创建一个struct of_device_id结构的变量__of_table_XXX,并把对应变量链接到__XXX_of_table对应的section中。关于这个section的位置,我们可以通过查看vmlinux.lds文件来找到对应的定义,这个文件是 ld script,是给ld链接器使用的,用来链接生成最终的kernel image的。

编译内核完成后它也会被生成在obj/KERNEL_OBJ/arch/arm64/kernel/vmlinux.lds:

 .init.data : {
  *(.init.data) *(.meminit.data) *(.init.rodata) . = ALIGN(8); __start_ftrace_events = .; *(_ftrace_events) __stop_ftrace_events = .; __start_ftrace_enum_maps = .; *(_ftrace_enum_map) __stop_ftrace_enu
m_maps = .; *(.meminit.rodata) . = ALIGN(8);__clk_of_table= .; *(__clk_of_table) *(__clk_of_table_end) . = ALIGN(8);__reservedmem_of_table= .; *(__reservedmem_of_table) *(__reservedmem_of_table_end
) . = ALIGN(8); __clksrc_of_table = .; *(__clksrc_of_table) *(__clksrc_of_table_end) . = ALIGN(8); __iommu_of_table = .; *(__iommu_of_table) *(__iommu_of_table_end) . = ALIGN(8); __cpu_method_of_table 
= .; *(__cpu_method_of_table) *(__cpu_method_of_table_end) . = ALIGN(8); __cpuidle_method_of_table = .; *(__cpuidle_method_of_table) *(__cpuidle_method_of_table_end) . = ALIGN(32); __dtb_start = .; *(.
dtb.init.rodata) __dtb_end = .; . = ALIGN(8); __irqchip_of_table = .; *(__irqchip_of_table) *(__irqchip_of_table_end) . = ALIGN(8); __irqchip_acpi_probe_table = .; *(__irqchip_acpi_probe_table) __irqch
ip_acpi_probe_table_end = .; . = ALIGN(8); __clksrc_acpi_probe_table = .; *(__clksrc_acpi_probe_table) __clksrc_acpi_probe_table_end = .; . = ALIGN(32); __earlycon_table = .; *(__earlycon_table) __earl
ycon_table_end = .;
  . = ALIGN(16); __setup_start = .; *(.init.setup) __setup_end = .;
  __initcall_start = .; *(.initcallearly.init) __initcall0_start = .; *(.initcall0.init) *(.initcall0s.init) __initcall1_start = .; *(.initcall1.init) *(.initcall1s.init) __initcall2_start = .; *(.init
call2.init) *(.initcall2s.init) __initcall3_start = .; *(.initcall3.init) *(.initcall3s.init) __initcall4_start = .; *(.initcall4.init) *(.initcall4s.init) __initcall5_start = .; *(.initcall5.init) *(.
initcall5s.init) __initcallrootfs_start = .; *(.initcallrootfs.init) *(.initcallrootfss.init) __initcall6_start = .; *(.initcall6.init) *(.initcall6s.init) __initcall7_start = .; *(.initcall7.init) *(.
initcall7s.init) __initcall_end = .;
  __con_initcall_start = .; *(.con_initcall.init) __con_initcall_end = .;
  __security_initcall_start = .; *(.security_initcall.init) __security_initcall_end = .;
  . = ALIGN(4); __initramfs_start = .; *(.init.ramfs) . = ALIGN(8); *(.init.ramfs.info)
 }

从上面的文件中可以看到,lds中会有很多个__XXX__of_table section的定义,它们都是被放到.init.data section中的。

而针对这段of_table的解析在各个模块对应代码中由各自模块负责解析,我们接下来以__reservedmem_of_table为例作为说明。

首先它的定义在:

#define RESERVEDMEM_OF_DECLARE(name, compat, init)          \
    _OF_DECLARE(reservedmem, name, compat, init, reservedmem_of_init_fn)

只要调用RESERVEDMEM_OF_DECLARE声明过的一些函数和name都会生成一个对应的__of_table_name对应的一个struct of_device_id结构变量,并放置于SECTIONS(__reservedmem_of_table)中,比如CMA的定义:

RESERVEDMEM_OF_DECLARE(cma, "shared-dma-pool", rmem_cma_setup);

上面的语句展开后其实对应如下:

 static const struct of_device_id __of_table_cma     
     __used __attribute__ ((__section__(__reservedmem_of_table))) 
      = { .compatible = "shared-dma-pool",           
          .data = rmem_cma_setup  
       }

section(__reservedmem_of_table)对应的解析函数在of_reserved_mem.c中:

static const struct of_device_id __rmem_of_table_sentinel
    __used __section(__reservedmem_of_table_end);// 找到对应的 section end
/**
 * res_mem_init_node() - call region specific reserved memory init code
 */
static int __init __reserved_mem_init_node(struct reserved_mem *rmem)
{
    extern const struct of_device_id __reservedmem_of_table[];
    const struct of_device_id *i;
    for (i = __reservedmem_of_table; i < &__rmem_of_table_sentinel; i++) { //遍历__reservedmem_of_table section中的内容,
                                                                           //也就是struct of_device_id结构变量
        reservedmem_of_init_fn initfn = i->data;
        const char *compat = i->compatible;
        if (!of_flat_dt_is_compatible(rmem->fdt_node, compat))        //如果检测到dts中有compatible匹配就进一步执行对应的initfn
            continue;
        if (initfn(rmem) == 0) {
            pr_info("Reserved memory: initialized node %s, compatible id %s\n",
                rmem->name, compat);
            return 0;
        }
    }
    return -ENOENT;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/rikeyone/article/details/79975138

网络敏感程序的编制

网络敏感程序的编制 UNIX系统为程序员提供了许多子程序,这些子程序可存取各种安全属性.有 些是信息子程序,返回文件属性,实际的和有效的UID,GID等信息.有些子程序可 改变文件属性.UID,GID...
  • ghj1976
  • ghj1976
  • 2000-08-25 14:20:00
  • 1344

由一个面试题引发的思考

         最近找工作面试基本上都要做笔试题目,上周去了一家公司,具体名字就不说了,有一道算法题,从1+2-3+4-5+..N,要求给一个参数N,计算结果。当时看到这题的第一思路是这样的。循环遍...
  • shengyongwang
  • shengyongwang
  • 2011-03-06 17:22:00
  • 643

一件事情引发的思考

最近,遇到了一件事情,给了我一点点启发,觉得需要记下来。 好久不看书了,觉得写东西一点儿文化底蕴都没有,,没事儿的时候还是要多看些文学方面的东西啊 还记得,2013-07-08,我来到了公司报道,...
  • jolingogo
  • jolingogo
  • 2013-11-19 08:48:28
  • 1173

lintcode balanced binary tree 解题思路

给定一个二叉树,确定它是高度平衡的。 此题的解题思路在于从底向上进行高度的计算,采用递归的方法来实现这一目的。 public int maxDepth(TreeNode root){ ...
  • tianchuan900
  • tianchuan900
  • 2017-09-07 22:24:13
  • 42

Linux内核与驱动开发学习总结:内核初始化宏__init(十二)

reference:http://blog.chinaunix.net/uid-25871104-id-2854544.html                      http://www....
  • fenggui
  • fenggui
  • 2015-06-26 11:36:56
  • 1055

linux中的_init应用,含有__attribute__ 和section的意义和作用

在linux/init.h中定义如下: #define __init __section(.init.text) __cold notrace 有些版本的内核是这样定义的: #define __...
  • suen1987
  • suen1987
  • 2013-06-23 16:21:55
  • 1315

由sage2引发的思考,大屏展示中跨屏方案总结分析

一、前言半年前开始接触Alibaba情报中心内部大屏展示项目,中心由42块屏幕组成,每面墙由3x7共21块屏幕组成。每块大屏分别由不同人开发,最后合并作展示,其中有的大屏占据4块屏幕的大小,虽然可以用...
  • majieco
  • majieco
  • 2017-02-14 11:00:50
  • 869

SecureCRT学习之道:SecureCRT 常用技巧

快捷键: 1、 ctrl + a :  移动光标到行首 2、 ctrl + e :移动光标到行尾 3、 ctrl + d :删除光标之后的一个字符 4、 ctrl + w : ...
  • u011511429
  • u011511429
  • 2014-07-24 10:33:39
  • 1114

GNU/GCC/G++ 编译/链接生成的常见段(section)表

自建开发平台最令人头疼的莫过于处理链接器产生的大量错误。其中难免接触到段。本文列出了大多出可以碰到的标准段名及其定义,希望可以给你带来帮助。...
  • zvvzxzko2006
  • zvvzxzko2006
  • 2015-09-17 11:44:59
  • 1723

读"一个细节引发的思考“引发的思考

今天偶然看到了这篇" 一个细节引发的思考”,不仅解除了我平时的困惑之一,也引发了我的一点思考。知其然还要知其所以然,我觉得作为CS的学生,这是应该具备的基本态度。首先看一下GNU网站上对该问题给出的解...
  • lovekatherine
  • lovekatherine
  • 2007-11-09 16:53:00
  • 1470
收藏助手
不良信息举报
您举报文章:由_OF_DECLARE引发对内核SECTION段解析的思考(基于kernel-4.9)
举报原因:
原因补充:

(最多只允许输入30个字)