insmod使用公共内核符号表来解析模块中未定义的符号。功能内核符号表中包含了所有全局内核项(函数和变量)的地址,这是实现模块化驱动程序所必须的。当模块装载到内核后,它所导出的任何符号都会变成内核符号表的一部分。通常情况下,模块只需要实现自己的功能,无需导出任何符号,但是如果其他模块想要使用该模块的某函数或变量,就需要导出符号;通过导出符号,在可以在其他模块上层叠新的模块。通过模块层叠可将模块划分为多个层,简化每个层可缩短开发时间。

Linux提供了一个方法来管理符号对模块以外部分的可见性,从而减少了可能造成的名字空间污染,并且适当的隐藏信息。如果一个模块需要导出符号,则应该使用下面的宏:

EXPORT_SYMBOL(name);

EXPORT_SYMBOL_GPL(name);

这两个宏均用于给定的符号导出到模块外部。_GPL版本导出的符号只能被GPL许可证下的模块使用。符号必须在模块文件的全局部分导出,不能在函数中导出,这是因为上面两个宏将被扩展为一个特殊变量的声明,而该变量必须是全局的。该变量将在模块可执行文件的特殊部分(一个”ELF段”)中保存,在装载时,内核通过这个段来寻找模块导出的变量;

上面两个宏定义在include/linux/export.h中

 /* For every exported symbol, place a struct in the __ksymtab section */
#define ___EXPORT_SYMBOL(sym, sec) \
extern typeof(sym) sym; \
__CRC_SYMBOL(sym, sec) \
static const char __kstrtab_##sym[] \
__attribute__((section("__ksymtab_strings"), aligned())) \
= VMLINUX_SYMBOL_STR(sym); \
static const struct kernel_symbol __ksymtab_##sym \
__used \
__attribute__((section("___ksymtab" sec "+" #sym), used)) \
= { (unsigned long)&sym, __kstrtab_##sym } #if defined(__KSYM_DEPS__) /*
* For fine grained build dependencies, we want to tell the build system
* about each possible exported symbol even if they're not actually exported.
* We use a string pattern that is unlikely to be valid code that the build
* system filters out from the preprocessor output (see ksym_dep_filter
* in scripts/Kbuild.include).
*/
#define __EXPORT_SYMBOL(sym, sec) === __KSYM_##sym === #elif defined(CONFIG_TRIM_UNUSED_KSYMS) #include <generated/autoksyms.h> #define __EXPORT_SYMBOL(sym, sec) \
__cond_export_sym(sym, sec, __is_defined(__KSYM_##sym))
#define __cond_export_sym(sym, sec, conf) \
___cond_export_sym(sym, sec, conf)
#define ___cond_export_sym(sym, sec, enabled) \
__cond_export_sym_##enabled(sym, sec)
#define __cond_export_sym_1(sym, sec) ___EXPORT_SYMBOL(sym, sec)
#define __cond_export_sym_0(sym, sec) /* nothing */ #else
#define __EXPORT_SYMBOL ___EXPORT_SYMBOL
#endif #define EXPORT_SYMBOL(sym) \
__EXPORT_SYMBOL(sym, "") #define EXPORT_SYMBOL_GPL(sym) \
__EXPORT_SYMBOL(sym, "_gpl") #define EXPORT_SYMBOL_GPL_FUTURE(sym) \
__EXPORT_SYMBOL(sym, "_gpl_future")

测试代码

两个测试模块分别为hello.ko和world.ko,hello模块导出函数,world模块使用该函数;

hello.c

 #include <linux/init.h>
#include <linux/module.h> MODULE_LICENSE("GPL"); void print_hello(void)
{
printk(KERN_INFO "Hello");
}
EXPORT_SYMBOL(print_hello); static int hello_init(void)
{
printk(KERN_INFO "hello init!\n");
return ;
} static void hello_exit(void)
{
printk(KERN_INFO "hello exit!\n");
} module_init(hello_init);
module_exit(hello_exit);

world.c

 #include <linux/init.h>
#include <linux/module.h> MODULE_LICENSE("GPL"); extern void print_hello(void); static void print_world(void)
{
printk(KERN_INFO "World!\n");
} static int world_init(void)
{
printk(KERN_INFO "world init!\n"); print_hello();
print_world(); return ;
} static void world_exit(void)
{
printk(KERN_INFO "world exit!\n");
} module_init(world_init);
module_exit(world_exit);

执行结果:

 [13912.081180] hello init!
[13917.863471] world init!
[13917.863477] Hello
[13917.863479] World!

Linux设备驱动程序 之 内核符号表的更多相关文章

  1. Linux设备驱动程序 之 内核定时器

    综述 如果需要在将来的某个时间点调度执行某个动作,同时在该时间点到达之前不会阻塞当前进程,则可以使用内核定时器: 内核定时器是一个数据结构,它告诉内核在用户定义的时间点使用用户定义的参数来执行一个用户 ...

  2. linux内核符号表

    我们已经看到 insmod 如何对应共用的内核符号来解决未定义的符号. 表中包含了全局内 核项的地址 -- 函数和变量 -- 需要来完成模块化的驱动. 当加载一个模块, 如何由模块 输出的符号成为内核 ...

  3. 嵌入式Linux设备驱动程序:编写内核设备驱动程序

    嵌入式Linux设备驱动程序:编写内核设备驱动程序 Embedded Linux device drivers: Writing a kernel device driver 编写内核设备驱动程序 最 ...

  4. linux设备驱动程序该添加哪些头文件以及驱动常用头文件介绍(转)

    原文链接:http://blog.chinaunix.net/uid-22609852-id-3506475.html 驱动常用头文件介绍 #include <linux/***.h> 是 ...

  5. LINUX设备驱动程序的注意事项(两)建设和执行模块

             <一>:设置測试系统 首先准备好一个内核源代码树,构造一个新内核,然后安装到自己的系统中.           <二>:HelloWorld模块 #inclu ...

  6. Linux设备驱动程序 第三版 读书笔记(一)

    Linux设备驱动程序 第三版 读书笔记(一) Bob Zhang 2017.08.25 编写基本的Hello World模块 #include <linux/init.h> #inclu ...

  7. 【Linux设备驱动程序】Chapter 2 - 构造和运行模块

    Hello World 模块 #include <linux/init.h> #include <linux/module.h> MODULE_LICENSE("Du ...

  8. Linux设备驱动程序学习----3.模块的编译和装载

    模块的编译和装载 更多内容请参考Linux设备驱动程序学习----目录 1. 设置测试系统 第1步,要先从kernel.org的镜像网站上获取一个主线内核,并安装到自己的系统中,因为学习驱动程序的编写 ...

  9. Linux设备驱动程序学习----目录

    目录 设备驱动程序简介 1.设备驱动程序简介 构造和运行模块 2.内核模块和应用程序的对比 3.模块编译和装载 4.模块的内核符号表  5.模块初始化和关闭  6.模块参数  7.用户空间编写驱动程序 ...

随机推荐

  1. VBA学习资料分享-3

    VBA创建/发送OUTLOOK邮件时怎么加上默认签名呢?用过OUTLOOK写邮件的人都知道,如果你设置了默认签名,那么在创建空白邮件的时候就会自动加上你设置的签名.根据这一特性,我们可以在用VBA创建 ...

  2. 09 redis中布隆过滤器的使用

    我们在使用新闻客户端看新闻时,它会给我们不停地推荐新的内容,它每次推荐时要去重,去掉那些已经看过的内容.问题来了,新闻客户端推荐系统如何实现推送去重的? 会想到服务器记录了用户看过的所有历史记录,当推 ...

  3. 【小知识点】input输入框在安卓以及IOS手机中光标及字体不居中解决方法

    问题根本:不要使用line-height垂直居中. 解决方法:可直接定义height,然后高度由上下padding值撑开. input { height: 1rem; padding: 1rem 0; ...

  4. poi的基本导入

    一.获取列的值 private String getCell(Cell cell){ if(null == cell){ return ""; } try{ cell.setCel ...

  5. 忘记root密码,修改方法

    Linux的root密码修改不像Windows的密码修改找回,Windows的登录密码忘记需要介入工具进行解决.CentOS6和CentOS7的密码方法也是不一样的,具体如下: 首先是CentOS 6 ...

  6. vscode go开发主要插件

    • Colorization 代码着彩色 • Completion Lists 代码自动完成(使用gocode) • Snippets 代码片段 • Quick Info 快速提示信息(使用godef ...

  7. Image Processing and Computer Vision_Review:A survey of recent advances in visual feature detection—2014.08

    翻译 一项关于视觉特征检测的最新进展概述——http://tongtianta.site/paper/56761 摘要 -特征检测是计算机视觉和图像处理中的基础和重要问题.这是一个低级处理步骤,它是基 ...

  8. Linux小试牛刀

    1.统计出/etc/passwd文件中其默认shell为非/sbin/nologin的用户个数,并将用户都显示出来 [root@centos7data]#getent passwd | grep -v ...

  9. 低级键盘钩子,在WIN7以上版本的问题

    最近在项目用到低级键盘钩子.发现一个很奇怪的事情,在开发环境和测试环境下都正常运行的键盘钩子, 到了现场环境,总是偶发性出现 键盘钩子不能用了,而且退出时产生1404 错误. 后经过阅读MSDN 的R ...

  10. 如何定义搜索面板的过滤器?DevExpress WPF超easy

    DevExpress广泛应用于ECM企业内容管理. 成本管控.进程监督.生产调度,在企业/政务信息化管理中占据一席重要之地.通过DevExpress WPF Controls,您能创建有着强大互动功能 ...