Rice我叫加饭? · 2021年12月22日

Linux内核驱动开发的EXPORT_SYMBOL

简介

  • 本文主要来讲讲Linux内核驱动中,EXPORT_SYMBOL()宏定义的用法。
  • 在阅读的Linux内核驱动源码的时候,我们会发现很多的函数带有EXPORT_SYMBOL()宏定义。
    image.png
  • 从这个宏定义的理解为输出符号。那么他究竟有什么作用。

EXPORT_SYMBOL()宏定义作用

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

使用方法

  1. 在模块函数定义之后使用"EXPORT_SYMBOL(函数名)"来导出。

    static int rice_func(void)
    {
    return 0;
    }
    EXPORT_SYMBOL(rice_func);
  2. 在调用该函数的另外一个模块中使用extern对之声明。

    extern int rice_func(void);
  3. 先加载定义该函数的模块,然后再加载调用该函数的模块,先后顺序必须注意。

实验

编写代码

  • 编写两个模块:rice_export.ko 和 rice_import.ko,其中:
  • rice_export.ko:导出定义的函数
  • rice_import.ko:调用导出的函数

导出函数模块的代码(rice_export.c)

  • 导出函数为:rice_drv_export,函数含义:外部输入一个字符串,然后打印出来
#include "rice_export.h"

#define CLASS_NAME  "rice_export"
#define DEVICE_NAME "rice_export"

typedef struct {
    int major_number;
    struct device *device;
    struct class *class;
} Rice_Driver;

Rice_Driver rice_drv;

static int rice_drv_export(char *name) {
    
    printk(KERN_ALERT "Rice Export: %s\n", name);
    return 0;
}
EXPORT_SYMBOL(rice_drv_export);

static int __init rice_export_init(void) {
    rice_drv.major_number = register_chrdev(0, DEVICE_NAME, NULL);

    if (rice_drv.major_number < 0) {
        printk(KERN_ALERT "Register fail!!\n");
        return rice_drv.major_number;
    }

    printk(KERN_ALERT "Registe success, major number is %d\n", rice_drv.major_number);

    rice_drv.class = class_create(THIS_MODULE, CLASS_NAME);

    if (IS_ERR(rice_drv.class)) {
        unregister_chrdev(rice_drv.major_number, DEVICE_NAME);
        return PTR_ERR(rice_drv.class);
    }

    rice_drv.device = device_create(rice_drv.class, NULL, MKDEV(rice_drv.major_number, 0), NULL, DEVICE_NAME);

    if (IS_ERR(rice_drv.device)) {
        class_destroy(rice_drv.class);
        unregister_chrdev(rice_drv.major_number, DEVICE_NAME);
        return PTR_ERR(rice_drv.device);
    }

    printk(KERN_ALERT "rice export ko init!!\n");

    return 0;
}

static void __exit rice_export_exit(void) {
    device_destroy(rice_drv.class, MKDEV(rice_drv.major_number, 0));
    class_unregister(rice_drv.class);
    class_destroy(rice_drv.class);
    unregister_chrdev(rice_drv.major_number, DEVICE_NAME);

    printk(KERN_ALERT "rice export ko exit!!\n");
}

module_init(rice_export_init);
module_exit(rice_export_exit);
MODULE_AUTHOR("RieChen");
MODULE_LICENSE("GPL");

电泳函数模块的代码(rice_import.c)

  • 调用函数声明:extern int rice_drv_export(char * name);,含义:声明外部函数

    #include "rice_import.h"
    
    #define CLASS_NAME  "rice_import"
    #define DEVICE_NAME "rice_import"
    
    typedef struct {
     int major_number;
     struct device *device;
     struct class *class;
    } Rice_Driver;
    
    Rice_Driver rice_drv;
    
    
    extern int rice_drv_export(char *name);
    
    
    static int __init rice_import_init(void) {
     rice_drv.major_number = register_chrdev(0, DEVICE_NAME, NULL);
    
     if (rice_drv.major_number < 0) {
         printk(KERN_ALERT "Register fail!!\n");
         return rice_drv.major_number;
     }
    
     printk(KERN_ALERT "Registe success, major number is %d\n", rice_drv.major_number);
    
     rice_drv.class = class_create(THIS_MODULE, CLASS_NAME);
    
     if (IS_ERR(rice_drv.class)) {
         unregister_chrdev(rice_drv.major_number, DEVICE_NAME);
         return PTR_ERR(rice_drv.class);
     }
    
     rice_drv.device = device_create(rice_drv.class, NULL, MKDEV(rice_drv.major_number, 0), NULL, DEVICE_NAME);
    
     if (IS_ERR(rice_drv.device)) {
         class_destroy(rice_drv.class);
         unregister_chrdev(rice_drv.major_number, DEVICE_NAME);
         return PTR_ERR(rice_drv.device);
     }
    
     printk(KERN_ALERT "rice import ko init!!\n");
    
     rice_drv_export("RiceChen");
    
     return 0;
    }
    
    static void __exit rice_import_exit(void) {
     device_destroy(rice_drv.class, MKDEV(rice_drv.major_number, 0));
     class_unregister(rice_drv.class);
     class_destroy(rice_drv.class);
     unregister_chrdev(rice_drv.major_number, DEVICE_NAME);
    
     printk(KERN_ALERT "rice import ko exit!!\n");
    }
    
    module_init(rice_import_init);
    module_exit(rice_import_exit);
    MODULE_AUTHOR("RieChen");
    MODULE_LICENSE("GPL");

    编译运行

  • 将两个模块编译完,push到板子,先加载导出模块--rice_export.ko,然后再加载调用模块--rice_import.ko
  • 运行结果:
    image.png
首发:Rice 嵌入式开发技术分享
作者:RiceDIY

推荐阅读

更多嵌入式技术干货请关注Rice 嵌入式开发技术分享
推荐阅读
关注数
1756
内容数
51
一个周末很无聊的嵌入式软件工程师,写写经验,写写总结。
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息