• Linux设备驱动程序 之 内核符号表


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

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

    EXPORT_SYMBOL(name);

    EXPORT_SYMBOL_GPL(name);

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

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

     1 /* For every exported symbol, place a struct in the __ksymtab section */
     2 #define ___EXPORT_SYMBOL(sym, sec)                    
     3     extern typeof(sym) sym;                        
     4     __CRC_SYMBOL(sym, sec)                        
     5     static const char __kstrtab_##sym[]                
     6     __attribute__((section("__ksymtab_strings"), aligned(1)))    
     7     = VMLINUX_SYMBOL_STR(sym);                    
     8     static const struct kernel_symbol __ksymtab_##sym        
     9     __used                                
    10     __attribute__((section("___ksymtab" sec "+" #sym), used))    
    11     = { (unsigned long)&sym, __kstrtab_##sym }
    12 
    13 #if defined(__KSYM_DEPS__)
    14 
    15 /*
    16  * For fine grained build dependencies, we want to tell the build system
    17  * about each possible exported symbol even if they're not actually exported.
    18  * We use a string pattern that is unlikely to be valid code that the build
    19  * system filters out from the preprocessor output (see ksym_dep_filter
    20  * in scripts/Kbuild.include).
    21  */
    22 #define __EXPORT_SYMBOL(sym, sec)    === __KSYM_##sym ===
    23 
    24 #elif defined(CONFIG_TRIM_UNUSED_KSYMS)
    25 
    26 #include <generated/autoksyms.h>
    27 
    28 #define __EXPORT_SYMBOL(sym, sec)                
    29     __cond_export_sym(sym, sec, __is_defined(__KSYM_##sym))
    30 #define __cond_export_sym(sym, sec, conf)            
    31     ___cond_export_sym(sym, sec, conf)
    32 #define ___cond_export_sym(sym, sec, enabled)            
    33     __cond_export_sym_##enabled(sym, sec)
    34 #define __cond_export_sym_1(sym, sec) ___EXPORT_SYMBOL(sym, sec)
    35 #define __cond_export_sym_0(sym, sec) /* nothing */
    36 
    37 #else
    38 #define __EXPORT_SYMBOL ___EXPORT_SYMBOL
    39 #endif
    40 
    41 #define EXPORT_SYMBOL(sym)                    
    42     __EXPORT_SYMBOL(sym, "")
    43 
    44 #define EXPORT_SYMBOL_GPL(sym)                    
    45     __EXPORT_SYMBOL(sym, "_gpl")
    46 
    47 #define EXPORT_SYMBOL_GPL_FUTURE(sym)                
    48     __EXPORT_SYMBOL(sym, "_gpl_future")

    测试代码

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

    hello.c

     1 #include <linux/init.h>
     2 #include <linux/module.h>
     3 
     4 MODULE_LICENSE("GPL");
     5 
     6 void print_hello(void)
     7 {
     8         printk(KERN_INFO "Hello");
     9 }
    10 EXPORT_SYMBOL(print_hello);
    11 
    12 static int hello_init(void)
    13 {
    14         printk(KERN_INFO "hello init!
    ");
    15         return 0;
    16 }
    17 
    18 static void hello_exit(void)
    19 {
    20         printk(KERN_INFO "hello exit!
    ");
    21 }
    22 
    23 module_init(hello_init);
    24 module_exit(hello_exit);

    world.c

     1 #include <linux/init.h>
     2 #include <linux/module.h>
     3 
     4 MODULE_LICENSE("GPL");
     5 
     6 extern void print_hello(void);
     7 
     8 static void print_world(void)
     9 {
    10         printk(KERN_INFO "World!
    ");
    11 }
    12 
    13 static int world_init(void)
    14 {
    15         printk(KERN_INFO "world init!
    ");
    16 
    17         print_hello();
    18         print_world();
    19 
    20         return 0;
    21 }
    22 
    23 static void world_exit(void)
    24 {
    25         printk(KERN_INFO "world exit!
    ");
    26 }
    27 
    28 module_init(world_init);
    29 module_exit(world_exit);

    执行结果:

    1 [13912.081180] hello init!
    2 [13917.863471] world init!
    3 [13917.863477] Hello
    4 [13917.863479] World!
  • 相关阅读:
    问与答练习20210802
    jmeter向kafka中写入数据 在路上
    jmeter插件地址 在路上
    wav2vec遇到的坑:AttributeError: 'Namespace' object has no attribute 'activation'
    oracle11g+arcgis10.2.2新产品部署注意步骤
    Django OssMediaStorage 手动上传图片文件到阿里云 oss
    Django MySQL中存储表情字符
    Ubuntu conda: command not found
    Python 二进制图片数据, 转换成图片到本地
    k8s集群配置搭建skywalking
  • 原文地址:https://www.cnblogs.com/wanpengcoder/p/11759567.html
Copyright © 2020-2023  润新知