Linux设备驱动程序 之 内核符号表
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设备驱动程序 之 内核符号表的更多相关文章
- Linux设备驱动程序 之 内核定时器
综述 如果需要在将来的某个时间点调度执行某个动作,同时在该时间点到达之前不会阻塞当前进程,则可以使用内核定时器: 内核定时器是一个数据结构,它告诉内核在用户定义的时间点使用用户定义的参数来执行一个用户 ...
- linux内核符号表
我们已经看到 insmod 如何对应共用的内核符号来解决未定义的符号. 表中包含了全局内 核项的地址 -- 函数和变量 -- 需要来完成模块化的驱动. 当加载一个模块, 如何由模块 输出的符号成为内核 ...
- 嵌入式Linux设备驱动程序:编写内核设备驱动程序
嵌入式Linux设备驱动程序:编写内核设备驱动程序 Embedded Linux device drivers: Writing a kernel device driver 编写内核设备驱动程序 最 ...
- linux设备驱动程序该添加哪些头文件以及驱动常用头文件介绍(转)
原文链接:http://blog.chinaunix.net/uid-22609852-id-3506475.html 驱动常用头文件介绍 #include <linux/***.h> 是 ...
- LINUX设备驱动程序的注意事项(两)建设和执行模块
<一>:设置測试系统 首先准备好一个内核源代码树,构造一个新内核,然后安装到自己的系统中. <二>:HelloWorld模块 #inclu ...
- Linux设备驱动程序 第三版 读书笔记(一)
Linux设备驱动程序 第三版 读书笔记(一) Bob Zhang 2017.08.25 编写基本的Hello World模块 #include <linux/init.h> #inclu ...
- 【Linux设备驱动程序】Chapter 2 - 构造和运行模块
Hello World 模块 #include <linux/init.h> #include <linux/module.h> MODULE_LICENSE("Du ...
- Linux设备驱动程序学习----3.模块的编译和装载
模块的编译和装载 更多内容请参考Linux设备驱动程序学习----目录 1. 设置测试系统 第1步,要先从kernel.org的镜像网站上获取一个主线内核,并安装到自己的系统中,因为学习驱动程序的编写 ...
- Linux设备驱动程序学习----目录
目录 设备驱动程序简介 1.设备驱动程序简介 构造和运行模块 2.内核模块和应用程序的对比 3.模块编译和装载 4.模块的内核符号表 5.模块初始化和关闭 6.模块参数 7.用户空间编写驱动程序 ...
随机推荐
- c++11 原生字符串字面值
c++11 原生字符串字面值 #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #in ...
- Spring切面编程Aspect之@Before和@Around用法
查看dao层使用的sql import java.util.Arrays; import org.apache.commons.lang.ArrayUtils; import org.aspectj. ...
- 【php设计模式】装饰器模式
装饰器模式,顾名思义,就是对已经存在的某些类进行装饰,以此来扩展一些功能.其结构图如下: Component为统一接口,也是装饰类和被装饰类的基本类型. ConcreteComponent为具体实现类 ...
- JS-上下文练习
/** * 因为JS没有块级作用域,if里面的foo又是以var形式声明的,所以会被提升上去, * 被赋值为undefined,之后undefined代表false,所以会进入if语句块, * foo ...
- impala 建表时报错,不支持中文
1.错误信息 (1366, "Incorrect string value: '\\xE6\\x8E\\x88\\xE6\\x9D\\x83...' for column 'search' ...
- java 日期。时间
友情链接: https://www.cnblogs.com/wanson/articles/10818955.html
- linux-2.6.38poll机制简析(以tiny6410按键中断程序为基础)
一.应用程序 /* struct pollfd { int fd; //文件描述符 short events; //表示请求检测的事件 short revents; //表示检测之后返回的事件 }; ...
- Unicode(统一码、万国码、单一码)
Unicode(统一码.万国码.单一码)是一种在计算机上使用的字符编码.它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言.跨平台进行文本转换.处理的要求.1990年开始研发,199 ...
- [SHOI2013]阶乘字符串
题目描述 给定一个由前\(n\)个小写字母组成的串\(S\). 串\(S\)是阶乘字符串当且仅当前\(n\)个小写字母的全排列(共\(n!\)种)都作为\(S\)的子序列(可以不连续)出现. 由这个定 ...
- 学习elasticsearch(一)linux环境搭建(1)
首先安装了Oracle Virtual Box 然后安装了最小版的CentOS.由于vbox自带的操作面板不太好用,于是用了xshell,XShell连接最小版的centOS时遇到的问题记录下. 1. ...