添加自定义的section

2023-05-16

一、基本知识点

编译出来的程序(o so exe ko等等)都是以elf格式进行排列保存的

elf文件分析情况:https://blog.csdn.net/edonlii/article/details/8779075

二、系统连接器会自带许多section,当然也可以添加自定义的section

2.1、以下命令可以查看连接器默认的section名

ld --verbose > section.lds

2.2、如何实现自定义的section

2.2.1、使用__section__函数实现自定义

__attribute__((used, __section__("xxxx")))

自定义一个结构体

#define SECTION_START(_type,_name)			\
static const struct mydyh_desc __mydyh_desc_##_type	\
	__attribute__((used, __section__(".dyh.info.init"))) = {	\
		.nr		= MY_DYH_##_type,		\
		.name	= _name,
		
#define SECTION_END						\
};

2.2.2、在链接脚本中添加section名和起始结束位置

 2.2.3、怎样才能获取到section里面的数据?

通过nm命令查看可执行程序的符号表,发现存在__dyh_info_begin,__dyh_info_end符号

nm exe_name | grep __dyh_info

因此,可以通过extern方式,获取符号地址

extern struct mydyh_desc __dyh_info_begin[], __dyh_info_end[];

2.3、编译代码

gcc section.c -T section.lds -o section

demo程序:https://github.com/dyh-git/section_custom

三、有什么用途?

假如在main函数中需要实现许多初始化功能,每当添加一个初始化功能,就需要把初始化函数添加到main函数中,然后重新编译。往往初始化函数的入参和返回值都一致。

如果使用自定义section模式,不需要把初始化函数添加到main函数中,遍历__dyh_info_begin到 __dyh_info_end地址就可以实现,详见demo程序。内核在module_init加载驱动时就是采用的这种方式。

四、module_init函数分析

4.1、module_init调用流程

#define module_init(x)	__initcall(x);

#define __initcall(fn) __define_initcall("1", fn)

#define __define_initcall(level,fn) \
        static initcall_t __initcall_##fn __used \
        __attribute__((__section__(".initcall" level ".init"))) = fn

可以看到,最终会调用__section__函数创建.initcall的section

4.2、查看linux链接脚本vmlinux.lds可以找到上面定义的section

 4.3、执行流程,do_initcall_level遍历的数组initcall_levels对应的就是section的起始位置

static initcall_t *initcall_levels[] __initdata = {
        __initcall0_start,
        __initcall1_start,
        __initcall2_start,
        __initcall3_start,
        __initcall4_start,
        __initcall5_start,
        __initcall6_start,
        __initcall7_start,
        __initcall_end,
};

int __init_or_module do_one_initcall(initcall_t fn)
{
        int ret;

        if (initcall_debug)
                ret = do_one_initcall_debug(fn);
        else
                ret = fn();

        return ret;
}

static void __init do_initcall_level(int level)
{
        initcall_t *fn;

        for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
                do_one_initcall(*fn);
}

static void __init do_initcalls(void)
{
        int level;

        for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
                do_initcall_level(level);
}

参考书籍:《程序员的自我修养—链接、装载与库》

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

添加自定义的section 的相关文章

随机推荐