linux 內核中EXPORT_SYMBOL()分析與實踐


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函數。
image


本文完!!!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM