1.EXPORT_SYMBOL
EXPORT_SYMBOL( my_pub_func);
在预编译阶段会解析为:
extern void *__crc_my_pub_func __attribute__((weak));
static const unsigned long __kcrctab_my_pub_func __attribute__((__used__)) __attribute__((section("__kcrctab" ""), unused)) = (unsigned long) &__crc_my_pub_func;
static const char __kstrtab_my_pub_func[] __attribute__((section("__ksymtab_strings"))) = "" "my_pub_func";
static const struct kernel_symbol __ksymtab_my_pub_func __attribute__((__used__)) __attribute__((section("__ksymtab" ""), unused)) = { (unsigned long)&my_pub_func, __kstrtab_my_pub_func };
很显然__ksymtab_my_pub_func存储了my_pub_func的地址和符号信息,该符号对应的地址
只有insmod后才会确定;
__ksymtab_my_pub_func会链接到__ksymtab section,__ksymtab section中的所有内容就构成了
内核"导出"的符号表,这个表在insmod 时候会用到.
2./proc/kallsyms
cat /proc/kallsyms会打印出内核当前的符号表,例如:
...
d8834a24 t snd_free_sgbuf_pages [snd_page_alloc]
c0180d7a U create_proc_entry [snd_page_alloc]
d88341d8 T snd_dma_free_pages [snd_page_alloc]
c013d858 U __get_free_pages [snd_page_alloc]
d8834ab5 t snd_malloc_sgbuf_pages [snd_page_alloc]
c014f906 U kmem_cache_alloc [snd_page_alloc]
c0106dcd U dma_alloc_coherent [snd_page_alloc]
...
其中第一列是该符号在内核地址空间中的地址;第二列是符号属性,小写表示
局部符号,大写表示全局符号,具体含义参考man nm; 第三列表示符号字符串.
这里只显示EXPORT_SYMBOL,EXPROT_SYMBOL_GPL处理过的符号。
3.System.map内核符号文件
通过more /boot/System.map 可以查看内核符号列表。
可以显示编译好内核后所有在内核中的符号,模块中的要另行查看。
4.通过nm vmlinux也可以查看内核符号列表
可以显示编译好内核后所有在内核中的符号,模块中的要另行查看。
5.通过nm module_name可以查看模块的符号列表
但是得到是相对地址,只有加载后才会分配绝对地址。比如:e1000模块,如果e1000中的符号经过EXPORT_SYMBOL处理,等加载后,我们可以通过more /boot/System.map和nm vmlinux命令查看到,但是没有EXPORT_SYMBOL的,我目前不知道怎么查看。
另个试验:
1.验证EXPORT_SYMBOL
模块hello.c代码如下:
1 #include <linux/module.h>
2 #include <linux/kernel.h>
3
4 static int __init a_init_module(void)
5 {
6 unsigned long *__kcrctab_per_cpu__hrtimer_bases = 0xc02678b4;
7 unsigned char *__kstrtab_per_cpu__hrtimer_bases = 0xc026926b;
8 struct kernel_symbol *__ksymtab_per_cpu__hrtimer_bases = 0xc0265018;
9
10 printk("__kcrctab_per_cpu__hrtimer_bases = %08x\n", *__kcrctab_per_cpu__hrtimer_bases);
11 printk("__kstrtab_per_cpu__hrtimer_bases = %s\n", __kstrtab_per_cpu__hrtimer_bases);
12 printk("__ksymtab_per_cpu__hrtimer_bases value = %08x, name = %s\n", __ksymtab_per_cpu__hrtimer_bases->value,\
13 __ksymtab_per_cpu__hrtimer_bases->name);
14
15 return 0;
16 }
17
18 static void __exit a_cleanup_module(void)
19 {
20 printk("Bye, Bye\n");
21 }
22 module_init(a_init_module);
23 module_exit(a_cleanup_module);
Makefile配置文件如下:
1 #
2 # Makefile for hello.c file
3 #
4 KDIR:=/lib/modules/$(shell uname -r)/build
5
6 obj-m:=hello.o
7
8 default:
9 $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
10 clean:
11 $(RM) .*.cmd *.mod.c *.o *.ko -r .tmp*
make; insmod hello.ko之后通过dmesg的运行结果:
__kcrctab_per_cpu__hrtimer_bases = 1ac19564
__kstrtab_per_cpu__hrtimer_bases = per_cpu__hrtimer_bases
__ksymtab_per_cpu__hrtimer_bases value = c0279ea0, name = per_cpu__hrtimer_bases
通过nm vmlinux | grep per_cpu__hrtimer_bases我们可以看到如下的对应关系:
1ac19564 A __crc_per_cpu__hrtimer_bases
c02678b4 r __kcrctab_per_cpu__hrtimer_bases
c026926b r __kstrtab_per_cpu__hrtimer_bases
c0265018 r __ksymtab_per_cpu__hrtimer_bases
c0279ea0 d per_cpu__hrtimer_bases
对比如上两列数据。
本实验只是为了验证一下EXPROT_SYMBOL.
2.1.EXPORT_SYMBOL和EXPORT_SYMBOL_GPL的区别
模块1:hello.c
1 #include <linux/module.h>
2 #include <linux/kernel.h>
3
4 void function1(void)
5 {
6 printk("hello wold\n");
7 }
8 EXPORT_SYMBOL(function1);
9
10 void function2(void)
11 {
12 printk("hello wold again\n");
13 }
14 EXPORT_SYMBOL_GPL(function2);
15
16
17 static int __init a_init_module(void)
18 {
19 return 0;
20 }
21
22 static void __exit a_cleanup_module(void)
23 {
24 printk("<1>Bye, Bye\n");
25
26 }
27
28 module_init(a_init_module);
29 module_exit(a_cleanup_module);
模块2:hello2.c
1 #include <linux/module.h>
2 #include <linux/kernel.h>
3
4 //MODULE_LICENSE("GPL");
5
6 static int __init a_init_module(void)
7 {
8 function1();
9 // function2();
10 return 0;
11 }
12
13 static void __exit a_cleanup_module(void)
14 {
15 printk("<1>Bye, Bye\n");
16
17 }
18
19 module_init(a_init_module);
20 module_exit(a_cleanup_module);
首先编译后两个模块:hello.ko, hello2.ko
A.在hello2.c中注释掉MODULE_LICENSE("GPL")和function2()两行,先insmod hello.ko然后insmod hello2.ko,一切正常。
B.先insmod hello2.ko然后insmod hello.ko,会有出错信息,通过dmesg查看显示如下:hello2: Unknown symbol function1
C.在hello2.c中打开function2(),先insmod hello.ko然后insmod hello2.ko,模块hello2.ko无法加载,显示如下信息:insmod: error inserting 'hello2.ko': -1 File exists,通过dmesg查看显示如下:hello2: Unknown symbol function2。在hello2.c中打开MODULE_LICENSE("GPL")或者用MODULE_LICENSE("Dual BSD/GPL"),先insmod hello.ko然后insmod hello2.ko,一切正常。
所以说EXPORT_SYMBOL_GPL的符号必须要用MODULE_LICENSE("GPL")或者用MODULE_LICENSE("Dual BSD/GPL")之后才能在模块中引用。而且MODULE_LICENSE("char")中的char不可以是任意字符,否则错误和没有MODULE_LICENSE效果一样。
D.没有看MODULE_LICENSE内核代码,下一步去研读代码。
分享到:
相关推荐
只有在内核中使用EXPORT_SYMBOL或EXPORT_SYMBOL_GPL导出的符号才能在内核模块中直接使用。然而,内核并没有导出所有的符号。例如,在3.8.0的内核中,do_page_fault没有被导出。 而我的内核模块中需要使用do_page...
这个头文件包含了`EXPORT_SYMBOL`宏定义和其他与模块相关的函数声明,确保编译器知道如何处理这个指令。 ```c #include ``` 2. **定义函数**:然后,你需要定义你想导出的函数。这个函数应该按照正常的C语言函数...
- **EXPORT_SYMBOL_GPL**: 与EXPORT_SYMBOL类似,但仅允许GPL许可证下的模块调用导出的符号。这种方式适用于希望限制使用范围的情况。 示例: ```c EXPORT_SYMBOL_GPL(my_function_gpl); ``` 为了确保符号正确...
白金搜寻者 一个类似于ack和the_silver_searcher(ag)代码搜索工具。 它支持多种平台和多种编码。 特征 它比ack快3到5倍地搜索代码。 它搜索代码的速度与the_silver_searcher(ag)一样快。...ag EXPORT_SYMBOL_GPL 1
使用`EXPORT_SYMBOL`或`EXPORT_SYMBOL_GPL`宏来标记要导出的符号,以便其他模块可以使用。 二、模块编写实例 一个简单的内核模块示例可能如下: ```c #include #include MODULE_LICENSE("GPL"); MODULE_AUTHOR...
- **`EXPORT_SYMBOL_GPL()`**:此宏与前者相似,但限制了导出仅对GPL许可证下的模块可用。 ##### **5. 模块信息** ```c MODULE_AUTHOR(author); MODULE_DESCRIPTION(description); MODULE_VERSION(version_string)...
EXPORT_SYMBOL(symbol_name); ``` **模块的编译和装载** 编译内核模块需要内核头文件,并使用如`make`命令构建。装载模块使用`insmod`,卸载使用`rmmod`,查看模块信息用`modinfo`,搜索模块用`modprobe`。 **设备...
像往常一样使用 EXPORT_GPL_SYMBOL 或 EXPORT_SYMBOL 导出您的符号。 正常构建您的提供程序模块 - 并查看 Module.symvers 文件,因为我们将取决于它导出的内容 - Makefile 包含神奇的部分。 你的依赖模块现在需要...
- 解决问题:为使模块能访问`my_variable`,需要在内核源码中使用`EXPORT_SYMBOL(my_variable)`导出该变量。 5. **模块调试**: - 错误处理:当模块加载失败时,系统会给出错误信息,如"Unknown symbol in module...
2. `EXPORT_SYMBOL`和`EXPORT_SYMBOL_GPL`:这两个宏用于导出内核符号,使得其他模块可以使用。 3. `device`和`driver`结构:用于设备驱动编程,表示硬件设备和与其关联的驱动程序。 4. `request_module`和`try_...
通过`EXPORT_SYMBOL`或`EXPORT_SYMBOL_GPL`宏,可以将符号添加到内核符号表,增强模块间的协作能力。使用计数机制则保证了模块的稳定性和资源的安全回收。 #### 编译与装载 模块的编译通常需要特定的工具链和内核...
- **EXPORT_SYMBOL_GPL()**:`#include <linux/module.h>`,与EXPORT_SYMBOL()相似,但限制只能由GPL许可的模块使用。 #### 10. 常规和约定 - **双链表操作(Double-linked lists)**:`#include <linux/list.h>`,...
- **导出符号**:为了使其他模块能够访问特定函数,可以使用`EXPORT_SYMBOL()`宏进行声明。例如,下面的代码展示了如何导出`my_fun`函数供其他模块使用: ```c int my_fun(wlandevice_t *wlandev) { // 函数体......
6. **符号导出**:2.6内核默认不导出所有符号,需要显式使用`EXPORT_SYMBOL`,而2.4内核默认导出所有符号,除非使用`EXPORT_NO_SYMBOLS`。 7. **内核版本检查**:在2.6内核中,多个文件包含`<linux/module.h>`时...
2.6内核中,模块的许可证声明方式为MODULE_LICENSE("DualBSD/GPL"),与2.4内核中的MODULE_LICENSE("GPL")有所不同。 3. 模块参数的定义方式。模块参数在2.6内核中使用module_param宏声明,同时提供了module_param_...
`EXPORT_SYMBOL`和`EXPORT_SYMBOL_GPL`宏用于将内核模块的函数或变量导出到内核的符号表。前者可以被任何其他模块或内核代码使用,而后者则限制为只允许遵循GPL许可证的代码访问。这样做的目的是保护代码的使用权限...