Linux内核中导出符号及其引用

Linux内核 专栏收录该内容
8 篇文章 0 订阅

导出符号可以被其他模块使用,只需使用前声明一下即可。

模块使用以下宏导出符号到内核符号表中:

EXPORT_SYMBOL(符号名);

EXPORT_SYMBOL_GPL(符号名);

EXPORT_SYMBOL_GPL只适合GPL许可的模块进行调用

示例:导出整数加、减运算函数符号的内核模块

calculate_lib.c

#include<linux/init.h>
#include<linux/module.h>
#include "calculate_lib.h"
int add_int(int a,int b)
{
    return a+b;
}
EXPORT_SYMBOL_GPL(add_int);
int sub_int(int a,int b)
{
    return a-b;
}
EXPORT_SYMBOL_GPL(sub_int);
MODULE_LICENSE("GPL v2");

calculate_lib.h

#ifndef _CALCULATE_LIB_H_
#define _CALCULATE_LIB_H_
extern int add_int(int a,int b);
extern int sub_int(int a,int b);
#endif

Makefile

KDIR :=/lib/modules/$(shell uname -r)/build
PWD=$(shell pwd)
obj-m = calculate_lib.o
all:
    $(MAKE) -C $(KDIR) M=$(PWD) 
    rm -rf *.o *.mod.c 
clean:
    rm  -rf *.ko

导出符号的引用

假设,模块B调用模块A的导出函数。

[1] 在模块A中.c源文件或者.h头文件中使用EXPORT_SYMBOL(xxxx) 导出函数.

[2] 在模块B中用 "extern" 申明函数(如, extern int xxxx)或包含模块A的头文件,申明以后就能够直接使用导出的函数了。

编译模块A,在模块A编译好后会生成符号表文件Module.symvers, 里面有函数地址和函数名对应关系,把这个文件拷贝到需要调用的模块B的源代码下,替换模块B的该文件。

然后重新编译B模块.这样就能够让模块B调用模块A的函数,以后加载模块顺序也必须先A后B,卸载相反。

加载导出函数以后,可以使用 cat  proc/kallsyms来查看所有的导出符号

 cat /proc/kallsyms  | grep add_int

模块间函数互相调用

com_lib.c

#include<linux/init.h>
#include<linux/module.h>
#include "com_lib.h"
void com_fun1(void)
{
    printk(" com_fun1\n");
}
EXPORT_SYMBOL_GPL(com_fun1);
void com_fun2(void)
{
        printk(" com_fun2\n");
}
EXPORT_SYMBOL_GPL(com_fun2);
int __init com_lib_init(void)
{
    printk("com_lib_init\n");
    return 0;
}
void __exit com_lib_exit(void)
{
   printk(" com_lib_exit\n");
}
module_init(com_lib_init);
module_exit(com_lib_exit);
MODULE_LICENSE("GPL v2");

calculate_lib.c

#include<linux/init.h>
#include<linux/module.h>
#include "calculate_lib.h"
#include "com_lib.h"
static int flag =5;
int add_int(int a,int b)
{
    printk("flag : %d \n",flag);
    com_fun1();
    com_fun2();
    printk("calculate_lib add_int\n");
    return a+b;
}
EXPORT_SYMBOL_GPL(add_int);
int sub_int(int a,int b)
{
    com_fun2();
    printk("calculate_lib add_int\n");
    return a-b;
}
EXPORT_SYMBOL_GPL(sub_int);

static int lib_init(void)
{
    flag=1;
    printk("calculate_lib lib_init\n");
    com_fun1();
    com_fun2();
    return 0;
}

static void lib_exit(void)
{
  printk("calculate_lib lib_ exit \n");
}

module_init(lib_init);
module_exit(lib_exit);
MODULE_LICENSE("GPL v2");

test_demo.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/device.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include "calculate_lib.h"
#include "com_lib.h"
static int test_init(void)
{
     int a=3,b=5,t;
     printk(">>test_init \n");
     t = add_int(a,b);
     printk("\n\n add_int %d+%d=%d\r\n",a,b,t);
     com_fun1();
     com_fun2();
     return 0;
}

static void test_exit(void)
{
     printk(">>test_exit\n");
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL v2");

多核模块间互相调用,可在同一个目录下编译

Makefile

obj-m +=calculate_lib.o
obj-m +=test_demo.o
obj-m += com_lib.o

KDIR :=/lib/modules/$(shell uname -r)/build
PWD=$(shell pwd)

modules:
	$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
	$(MAKE) -C $(KDIR) M=$(PWD) clean

make后,Module.symvers文件中的内容如下:

依次加载com_lib.ko、calculate_lib.ko、test_demo.ko

insmod com_lib.ko
insmod calculate_lib.ko
insmod test_demo.ko

dmesg中打印如下信息

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值