• 【转】编程之:EXPORT_SYMBOL使用


    EXPORT_SYMBOL只出现在2.6内核中,在2.4内核默认的非static 函数和变量都会自动导入到kernel 空间的, 都不用EXPORT_SYMBOL() 做标记的。
    2.6就必须用EXPORT_SYMBOL() 来导出来(因为2.6默认不到处所有的符号)。 

    1、EXPORT_SYMBOL的作用
    EXPORT_SYMBOL标签内定义的函数或者符号对全部内核代码公开,不用修改内核代码就可以在您的内核模块中直接调用,即使用EXPORT_SYMBOL可以将一个函数以符号的方式导出给其他模块使用。

    这里要和System.map做一下对比:
    System.map 中的是连接时的函数地址。连接完成以后,在2.6内核运行过程中,是不知道哪个符号在哪个地址的。
    EXPORT_SYMBOL 的符号, 是把这些符号和对应的地址保存起来,在内核运行的过程中,可以找到这些符号对应的地址。

    而模块在加载过程中,其本质就是能动态连接到内核,如果在模块中引用了内核或其它模块的符号,就要EXPORT_SYMBOL这些符号,这样才能找到对应的地址连接。

    使用方法:

       第一、在模块函数定义之后使用EXPORT_SYMBOL(函数名)
       第二、在掉用该函数的模块中使用extern对之声明
       第三、首先加载定义该函数的模块,再加载调用该函数的模块

    另外,在编译调用某导出函数的模块时,往往会有WARNING: "****" [**********] undefined!
    使用dmesg命令后会看到相同的信息。开始我以为只要有这个错误就不能加载模块,后来上网查了一下,发现这主要是因为在编译连接的时候还没有和内核打交道,当然找不到symbol了,但是由于你生成的是一个内核模块,所以LD不提示error,而是给出一个warning,寄希望于在insmod的时候,内核能够把这个symbol连接上。

    一个模块mod1中定义一个函数func1;在另外一个模块mod2中定义一个函数func2,func2调用func1。
    在模块mod1中,EXPORT_SYMBOL(func1);
    在模块mod2中,extern int func1();
    就可以在mod2中调用func1了

    EXPORT_SYMBOL示范

    比如有两个驱动模块:Module A和Module B,其中Module B使用了Module A中的export的函数,因此在Module B的Makefile文件中必须添加:

    KBUILD_EXTRA_SYMBOLS += /path/to/ModuleA/Module.symvers

    export KBUILD_EXTRA_SYMBOLS

    这样在编译Module B时,才不会出现Warning,提示说func1这个符号找不到,而导致编译得到的ko加载时也会出错。

    复制代码
    // Module A (mod_a.c)  
    #include<linux/init.h>  
    #include<linux/module.h>  
    #include<linux/kernel.h>  
      
    static int func1(void)  
    {  
           printk("In Func: %s...
    ",__func__);  
           return 0;  
    }  
      
    // Export symbol func1  
    EXPORT_SYMBOL(func1);  
      
    static int __init hello_init(void)  
    {  
           printk("Module 1,say hello world!
    ");  
           return 0;  
    }  
      
    static void __exit hello_exit(void)  
    {  
           printk("Module 1,Exit!
    ");  
    }  
      
    module_init(hello_init);  
    module_exit(hello_exit);  
    复制代码
    复制代码
    // Module B (mod_b.c)  
    #include<linux/init.h>  
    #include<linux/kernel.h>  
    #include<linux/module.h>  
    extern int functl(void);  
    static int func2(void)  
    {  
           func1();  
           printk("In Func: %s...
    ",__func__);  
           return 0;  
    }  
      
    static int __init hello_init(void)  
    {  
           printk("Module 2,is used Module 1 function!
    ");  
           func2();  
           return 0;  
    }  
      
    static void __exit hello_exit(void)  
    {  
           printk("Module 2,Exit!
    ");  
    }  
      
    module_init(hello_init);  
    module_exit(hello_exit);  
    复制代码
    在驱动加载的时候,一定要先加载定义function1的Module A模块,然后再加载调用function1的Module B的驱动模块。
    如下操作:
    insmod Module_A.ko  
    insmod Module_B.ko  


    转自:https://www.cnblogs.com/Caden-liu8888/p/7725293.html
  • 相关阅读:
    Linux性能监控
    程序员技术练级攻略
    使用 GDB 调试多进程程序
    nginx下面部署fast-cgi和C++【原】
    ROS Learning-024 (提高篇-002) rviz的安装和使用
    ROS Learning-023 (提高篇-001) 准备工作 --- 安装一些必要的软件包
    STM32 C++编程 005 I2c(Soft)类
    Python 网络爬虫 005 (编程) 如何编写一个可以 下载(或叫:爬取)一个网页 的网络爬虫
    设置 PyCharm 软件中 Terminal 窗口 中启动的 python 交互命令的版本
    在PyCharm 软件中设置你的项目 使用的Python版本
  • 原文地址:https://www.cnblogs.com/coreLeo/p/11759383.html
Copyright © 2020-2023  润新知