linux 內核中EXPORT_SYMBOL()分析與實踐
linux內核版本 | 時間 | 備注 |
---|---|---|
4.1.15 | 2021/11/1 | 技術總結 |
一、EXPORT_SYMBOL()分析
EXPORT_SYMBOL實際是一個宏函數。用於將函數或者符號向全部內核代碼公開,不用修改內核代碼就可以在內核模塊中直接調用(注意是在內核模塊中),即:使用EXPORT_SYMBOL可以將一個函數以符號的方式導出給其他模塊使用。
定義如下://出自 linux dir/include/linux/export.h文件
#define __EXPORT_SYMBOL(sym, sec) \
extern typeof(sym) sym; \
__CRC_SYMBOL(sym, sec) \
static const char __kstrtab_##sym[] \
__attribute__((section("__ksymtab_strings"), aligned(1))) \
= VMLINUX_SYMBOL_STR(sym); \
extern const struct kernel_symbol __ksymtab_##sym; \
__visible const struct kernel_symbol __ksymtab_##sym \
__used \
__attribute__((section("___ksymtab" sec "+" #sym), unused)) \
= { (unsigned long)&sym, __kstrtab_##sym }
#define EXPORT_SYMBOL(sym) \
__EXPORT_SYMBOL(sym, "")
這里以EXPORT_SYMBOL(system_state)為例,經過宏替換后結果如下:
extern typeof (system_state) system_state;
extern __visible void *__crc_system_state __attribute__ ((weak));
static const unsigned long __kcrctab_system_state __used __attribute__ ((section("___kcrctab" sec "+" #sym), unused)) = (unsigned long) &__crc_system_state;
static const char __kstrtab_system_state[] __attribute__((section("__ksymtab_strings"), aligned(1))) = "system_state";
extern const struct kernel_symbol __ksymtab_system_state;
__visible const struct kernel_symbol __ksymtab_system_state __used __attribute__ ((section("___ksymtab" sec "+" #sym), unused)) = {(unsigned long)&system_state,__kstrtab_system_state};
以上代碼實則是:對於每個使用EXPORT_SYMBOL()導出的符號,都將在ksymtab節中放置一個與之關聯的結構體。
二、實踐過程記錄
創建一個module_first模塊和module_second模塊,再創建一個makefile文件。
//module_first.c
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
static int module_first_function(void)
{
printk("this is module_first_function\r\n");
return 0;
}
EXPORT_SYMBOL(module_first_function); /*導出module_first_function函數供module_second模塊使用 */
static int __init module_first_init(void)
{
printk("module_first_init\r\n");
return 0;
}
static int __exit module_first_exit(void)
{
printk("module_first_exit\r\n");
return 0;
}
// 指定驅動的入口函數和出口函數
module_init(module_first_init);
module_exit(module_first_exit);
MODULE_AUTHOR("iriczhao");
MODULE_LICENSE("GPL");
//module_second.c
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
extern int module_first_function(void);
static int module_second_function(void)
{
/* 此處調用module_first模塊中module_first_function函數 */
module_first_function();
printk("============================\r\n");
printk("this is module_second_function\r\n");
printk("============================\r\n");
return 0;
}
static int __init module_second_init(void)
{
printk("module_second_init\r\n");
module_second_function();
return 0;
}
static int __exit module_second_exit(void)
{
printk("module_second_exit\r\n");
return 0;
}
// 指定驅動的入口函數和出口函數
module_init(module_second_init);
module_exit(module_second_exit);
MODULE_AUTHOR("iriczhao");
MODULE_LICENSE("GPL");
makefile 文件
KERNELDIR := /home/iriczhao/linux/linux-imx-rel_imx_4.1.15_2.1.0_ga
CURRENT_PATH := $(shell pwd)
obj-m := module_first.o module_second.o
build: kernel_modules
kernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
編譯構建后,將生成的module_first.ko和module_second.ko兩個模塊文件拷貝到運行環境根文件系統中。加載模塊,運行結果如下:
可見,根據上圖紅框中內容顯示,在module_second模塊中成功調用了module_first模塊中使用EXPORT_SYMBOL聲明的module_first_function函數。
本文完!!!