Export driven by Linux kernel_ SYMBOL

preface

  • I'm sorry, fans. The blogger hasn't updated the original article for a long time. From today on, he will resume the time of writing articles. Some time ago, all kinds of things were not going well. At that time, I was in a low mood. Now it's back.

brief introduction

  • This article mainly talks about export in Linux kernel driver_ Symbol () the usage of the macro definition.
  • When reading the Linux kernel driver source code, we will find that many functions have EXPORT_SYMBOL() macro definition.
  • From the definition of this macro, it is understood as the output symbol. So what role does he play.

EXPORT_SYMBOL() macro definition function

  • EXPORT_SYMBOL the functions or symbols defined by the macro definition will be exposed to the kernel code, and can be directly called in other kernel modules without modifying the kernel code, that is, export_ You can export a symbol to another module.

usage method

  1. After the module function definition, use "export_symbol" to export.
static int rice_func(void)
{
    return 0;
}
EXPORT_SYMBOL(rice_func);
copy
  1. Use extern to declare it in another module that calls the function.
extern int rice_func(void);
copy
  1. First load the module that defines the function, and then load the module that calls the function. Pay attention to the order.

experiment

Write code

  • Write two modules: rice_export.ko and rice_import.ko, where:
    • rice_export.ko: export defined functions
    • rice_import.ko: call the exported function
Export code of function module (rice_export.c)
  • Export function: rice_drv_export, function meaning: input a string externally, and then print it out
#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");
copy
Code of electrophoresis function module (rice_import.c)
  • Calling function declaration: extern int rice_drv_export(char *name);, Meaning: declare external functions
#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");
copy

Compile and run

  • After compiling the two modules, push them to the board, and load the export module rice first_ export. Ko, and then load the calling module -- rice_import.ko
  • Operation results:

Posted by Nicholas on Tue, 10 May 2022 17:08:56 +0300