半两温柔� 2024-04-27 00:00 采纳率: 0%
浏览 12

linux内核驱动开发

在学习linux内核驱动开发时,需要导出模块符号并被另一个模块调用,报错显示符号导出被外部调用,但是在另一个模块中并没有找到对应的符号,报错如下:

tcy@tcy-virtual-machine:~/workSpace/3$ make
make -C /lib/modules/6.5.0-28-generic/build M=/home/tcy/workSpace/3  modules
make[1]: 进入目录“/usr/src/linux-headers-6.5.0-28-generic”
warning: the compiler differs from the one used to build the kernel
  The kernel was built by: x86_64-linux-gnu-gcc-12 (Ubuntu 12.3.0-1ubuntu1~22.04) 12.3.0
  You are using:           gcc-12 (Ubuntu 12.3.0-1ubuntu1~22.04) 12.3.0
  CC [M]  /home/tcy/workSpace/3/hello.o
  CC [M]  /home/tcy/workSpace/3/printp.o
  MODPOST /home/tcy/workSpace/3/Module.symvers
ERROR: modpost: /home/tcy/workSpace/3/hello: local symbol 'hi' was exported
ERROR: modpost: /home/tcy/workSpace/3/hello: local symbol 'prt' was exported
ERROR: modpost: "hi" [/home/tcy/workSpace/3/printp.ko] undefined!
ERROR: modpost: "prt" [/home/tcy/workSpace/3/printp.ko] undefined!
make[3]: *** [scripts/Makefile.modpost:144:/home/tcy/workSpace/3/Module.symvers] 错误 1
make[2]: *** [/usr/src/linux-headers-6.5.0-28-generic/Makefile:1991:modpost] 错误 2
make[1]: *** [Makefile:234:__sub-make] 错误 2
make[1]: 离开目录“/usr/src/linux-headers-6.5.0-28-generic”
make: *** [Makefile:7:all] 错误 2

两个模块代码分别如下:
模块一:

#include <linux/module.h>

#define CNT 1

static int cnt = CNT;
static char *hi = "Hi,Linux\n";
static int arr[] = {1, 2, 3, 4, 5, 6};
static int nums = sizeof(arr)/sizeof(int);

module_param(cnt, int, S_IRUGO);    //传参函数,表示循环三次
module_param(hi, charp, S_IRUGO);     //charp类型
module_param_array(arr, int, &nums, S_IRUGO);   //整型数组

static void prt(void){
    printk(KERN_INFO "this is hello module\n");
}

static int __init hello_init(void){
    int i;
    printk(KERN_INFO "HELLO LINUX MODULE\n");
    for (i=0;i<cnt;i++){
        printk(KERN_INFO "%d:%s", i, hi);
    }
    for (i = 0; i < 6; i++){
        printk(KERN_INFO "%d ", arr[i]);
    }
    printk(KERN_INFO "nums:%d\n", nums);
    return 0;
}

static void __exit hello_exit(void){
    printk(KERN_INFO "GOODBYE LINUX\n");
}

module_init(hello_init);
module_exit(hello_exit);

EXPORT_SYMBOL_GPL(hi);
EXPORT_SYMBOL_GPL(prt);

MODULE_LICENSE("Dual BSD/BPL");
MODULE_AUTHOR("KGZ");
MODULE_VERSION("V1.0");

模块二:

#include <linux/module.h>

extern char *hi;
extern void prt(void);

static int __init printp_init(void){
    printk(KERN_INFO "printp:%s", hi);
    prt();
    return 0;
}

static void __exit printp_exit(void){
}

module_init(printp_init);
module_exit(printp_exit);

MODULE_LICENSE("DUal BSD/GPL");
MODULE_AUTHOR("KGZ");
MODULE_VERSION("V1.0");
  • 写回答

6条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-04-27 00:00
    关注

    引自免费微信小程序:皆我百晓生

    从错误信息来看,模块hello在尝试导出本地变量hi和函数prt,但是这些符号在模块printp中并未找到。这通常是因为在模块hello中使用了EXPORT_SYMBOL_GPL()来导出这两个符号,但在模块printp中没有正确地包含它们。

    解决这个问题的方法是确保在模块printp.c中正确声明并导出符号。你需要将导出符号的代码移动到一个头文件中,然后让两个模块都包含这个头文件。创建一个新的头文件(例如 hello_api.h),并将要共享的符号放入其中:

    #ifndef HELLO_API_H
    #define HELLO_API_H
    
    void prt(void);
    const char *get_hi(void);
    
    #endif /* HELLO_API_H */
    

    接下来,在模块hello.c中修改导出函数和字符串为只读,并更新hello.c

    #include <linux/module.h>
    #include <linux/kernel.h> // 添加这一行,因为我们需要 printk 函数
    
    #define CNT 1
    
    static int cnt = CNT;
    static const char hi[] = "Hi,Linux\n"; // 将 char* 更改为 const char*,并添加 []
    static int arr[] = {1, 2, 3, 4, 5, 6};
    static int nums = sizeof(arr)/sizeof(int);
    
    module_param(cnt, int, S_IRUGO);    //传参函数,表示循环三次
    module_param_array(arr, int, &nums, S_IRUGO);   //整型数组
    
    static void prt(void){
        printk(KERN_INFO "this is hello module\n");
    }
    
    static int __init hello_init(void){
        int i;
        printk(KERN_INFO "HELLO LINUX MODULE\n");
        for (i=0;i<cnt;i++){
            printk(KERN_INFO "%d:%s", i, hi);
        }
        for (i = 0; i < 6; i++){
            printk(KERN_INFO "%d ", arr[i]);
        }
        printk(KERN_INFO "nums:%d\n", nums);
        return 0;
    }
    
    static void __exit hello_exit(void){
        printk(KERN_INFO "GOODBYE LINUX\n");
    }
    
    module_init(hello_init);
    module_exit(hello_exit);
    
    EXPORT_SYMBOL_GPL(hi);
    EXPORT_SYMBOL_GPL(prt);
    
    MODULE_LICENSE("Dual BSD/BPL");
    MODULE_AUTHOR("KGZ");
    MODULE_VERSION("V1.0");
    
    // 在这里提供函数指针
    const char *get_hi(void) {
        return hi;
    }
    

    然后,在模块printp.c中,删除对hiprt的外部声明,并包含新创建的头文件:

    #include <linux/module.h>
    #include "hello_api.h"
    
    static int __init printp_init(void){
        printk(KERN_INFO "printp:%s", get_hi());
        prt();
        return 0;
    }
    
    static void __exit printp_exit(void){
    }
    
    module_init(printp_init);
    module_exit(printp_exit);
    
    MODULE_LICENSE("DUal BSD/GPL");
    MODULE_AUTHOR("KGZ");
    MODULE_VERSION("V1.0");
    

    这样,模块printp就可以通过包含hello_api.h来访问hello模块中的hiprt了。记得重新编译两个模块,然后加载模块:

    sudo make clean
    sudo make
    sudo insmod hello.ko
    sudo insmod printp.ko
    

    如果你仍然遇到问题,可以检查是否有其他编译选项或配置不正确。如果有任何进一步的问题,请随时告诉我。

    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 4月27日

悬赏问题

  • ¥15 联想笔记本开机出现系统更新界面
  • ¥15 各位帮帮我 我不想重做系统
  • ¥30 微信小程序蓝牙数据透传
  • ¥15 加氢站氢负荷数据集来源
  • ¥15 umi接入sentry遇到问题
  • ¥15 HBuilderX打包H5网页,扫码模块无法使用
  • ¥15 Javascript跳转页面后,无法执行后面代码,如何解决?
  • ¥15 echarts绘制图表
  • ¥15 请教两个关于高德地图定位不准的技术问题
  • ¥15 根据企业名称 对照两个文件 样本筛选/匹配