linux驱动之符号导出

一、什么是符号引入,为啥要导入?

在linux内核中,有分为内核程序与模块程序,内核是主题,而模块可以动态从内核地添加与卸载。

如果模块程序中需要使用内核模块中定义的函数或者变量,那么内核模块就需要将它们导出(引入的反向操作)。

同理,如果不同模块之间也需要相互使用对方定义的东西,那么都要导出它们。

不导出的危害

如果不导出,但是又有别的模块需要使用它们,虽然该模块在编译时正常,(产生未解决的引用问题)但是当加入到内核中却没有解决这个未解决的引用问题(也就是没有找到该符号的地址)那么就会报错。

如何导出?
EXPORT_SYMBOL//允许被所有模块以及内核使用
EXPORT_SYMBOL_GPL//不支持给不支持GPL的模块使用
EXPORT_SYMBOL_GPL_FUTURE//支持给所有模块使用,但是不支持GPL会报警

二、如何导入?

在此之前我们先了解一下有关内核模块加载的知识


内核模块

在编译好之后使用file命令可以发现其实就是ELF格式的文件(Linux下的可执行文件格式),它允许重定位。

我们先了解一下它的结构。!](https://img-blog.csdnimg.cn/3d4ec9d98ee64e9fa70ef4663a606a3a.png)

在这里插入图片描述

其中ELF header描绘的是Section header entry的基本信息(地址等),而Section header entry描绘的是它对应的Section对应的基本信息(地址等),Section就是ELF文件的主题部分了。

insmod之后,模块是如何被加载到内核中的?

1.insmod触发read系统调用,调用到了相应文件系统的APL,将模块的ELF加载到某块用户空间中

2.sys_init_module系统调用,完成剩下的模块加载任务

sys_init_module

在详细了解如何加载模块到内核之前我们先了解一个结构体,它是内核模块在内核中的抽象

struct module {
	enum module_state state;//模块的状态,在模块导入过程中有不同的状态

	/* Member of list of modules */
	struct list_head list;//内核模块被内核用链表管理起来

	/* Unique handle for this module */
	char name[MODULE_NAME_LEN];//模块名称

	/* Exported symbols */
	const struct kernel_symbol *syms;//这个就是导出的符号,里面包含符号名称与地址

	/* Kernel parameters. */
	struct kernel_param *kp;//模块参数

	/* Startup function. */
	int (*init)(void);//模块初始化指针
    
    //用于管理相互依赖的模块
   	/* What modules depend on me? */
	struct list_head source_list;
	/* What modules do I depend on? */
	struct list_head target_list;
	......
    ......
   	......
};
1.调用load_module

1.vmalloc在内核中分配一大块内存

2.利用copy_from_user将前面用户空间的ELF文件拷贝到内核空间(叫做HDR,但是HDR也不是最终的地址)

2.两次改写
第一次:

1.将ELF从用户空间拷贝到内核空间后,我们需要改写Section header entry中的地址(但是Section的内容没有改动,注意

2.利用.gnu.linkonce.this_module Section初始化mod对象(struct moudle结构体)

第二次:

1.将最终搬移好的ELF中的Section分为CORE与INIT两种,(其中.gnu.linkonce.this_module Section在CORE中)

2.搬移好之后再次改写Section header entry中的地址,并且Mod中的地址也要改变。

3.将INIT Section删除


模块的导入是如何实现的?

那就要从EXPORT_SYMBOL的宏说起了,简言之,这些宏的作用就是生成了kernel_sysmbol结构体对象(包含了符号名与符号地址)

重要的是:

这个对象在编译之后是被放入_ksymtab Section中的,而这个Section也会被搬移到CORE Section中。

(_ksymtab Section是由kernel_sysmbol数组构成的)

别的模块如何查找到它的地址?

前面我们知道了模块在内核中有一个抽象struct module通过这个模块与模块以及内核就会产生联系,借用simplify_symbols函数以及find_symbol就能找到对应的地址,如果找不到就报错。

这样真的可以了吗?

我们知道在两次搬移HDR过程中,都没有改写Section中的内容,而_ksymtab Section中包含kernel_sysmbol,它里面又包含符号的地址,所以这样会造成错误。

重定位:

其实在ELF文件中还有一个与_ksymtab Section对应的 .rel_ksymtab Section,利用这个Section以及其它的一些Section在第二次搬移之后将_ksymtab Section中的地址修改为正确地址。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值