Linux内核EXPORT_SYMBOL宏解析

Linux内核EXPORT_SYMBOL宏解析


  本文针对ARM32处理器进行说明。使用内核4.0版本。

宏定义展开

  EXPORT_SYMBOL宏定义于include/linux/export.h

  众所周知,EXPORT_SYMBOL宏是导出符号给模块(ko)使用的,所以当内核配置不支持动态加载ko时,EXPORT_SYMBOL宏为空

#else /* !CONFIG_MODULES... */

#define EXPORT_SYMBOL(sym)
#define EXPORT_SYMBOL_GPL(sym)
#define EXPORT_SYMBOL_GPL_FUTURE(sym)
#define EXPORT_UNUSED_SYMBOL(sym)
#define EXPORT_UNUSED_SYMBOL_GPL(sym)

#endif /* CONFIG_MODULES */

  在内核配置支持ko加载后(MODULE),宏定义展开如下:

#define __CRC_SYMBOL(sym, sec)					\
	extern __visible void *__crc_##sym __attribute__((weak));		\
	static const unsigned long __kcrctab_##sym		\
	__used							\
	__attribute__((section("___kcrctab" sec "+" #sym), unused))	\
	= (unsigned long) &__crc_##sym;
#else
#define __CRC_SYMBOL(sym, sec)
#endif

/* For every exported symbol, place a struct in the __ksymtab section */
#define __EXPORT_SYMBOL(sym, sec)				\
	extern typeof(sym) sym;					\
	__CRC_SYMBOL(sym, sec)					\
	static const char __kstrtab_##sym[]			\											(1)
	__attribute__((section("__ksymtab_strings"), aligned(1))) \
	= VMLINUX_SYMBOL_STR(sym);				\
	extern const struct kernel_symbol __ksymtab_##sym;	\									(2)
	__visible const struct kernel_symbol __ksymtab_##sym	\
	__used							\
	__attribute__((section("___ksymtab" sec "+" #sym), unused))	\							(3)
	= { (unsigned long)&sym, __kstrtab_##sym }

#define EXPORT_SYMBOL(sym)					\
	__EXPORT_SYMBOL(sym, "")

#define EXPORT_SYMBOL_GPL(sym)					\
	__EXPORT_SYMBOL(sym, "_gpl")

#define EXPORT_SYMBOL_GPL_FUTURE(sym)				\
	__EXPORT_SYMBOL(sym, "_gpl_future")

  __EXPORT_SYMBOL宏展开。
1)以符号名定义字符串数组__kstrtab_##sym,链接到__ksymtab_strings section中。以1字节对齐(节省内存空间)。把函数名存放于字符串中。VMLINUX_SYMBOL_STR正常情况下返回原值。
2)定义struct kernel_symbol数据结构

struct kernel_symbol
{
	unsigned long value;
	const char *name;
};

  这个数据结构8个字节,两个成员,value指向函数指针,name指向上文中的strtab地址。insmod时,模块会寻找依赖的符号。就是从kstrtab_symbol表中遍历。从name指针获取函数名字符串,比对一致后,获取strtabvalue值(内核函数指针)。即模块需要的符号。
3)链接到___symtab section中。

链接脚本

  RO_DATA_SECTION宏定义于vmlinux.lds.h中。ksymtabkstrtab相关链接逻辑定义于其中

	/* Kernel symbol table: Normal symbols */			\
	__ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {		\
		VMLINUX_SYMBOL(__start___ksymtab) = .;			\
		*(SORT(___ksymtab+*))					\
		VMLINUX_SYMBOL(__stop___ksymtab) = .;			\
	}								\
									\
	/* Kernel symbol table: GPL-only symbols */			\
	__ksymtab_gpl     : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) {	\
		VMLINUX_SYMBOL(__start___ksymtab_gpl) = .;		\
		*(SORT(___ksymtab_gpl+*))				\
		VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .;		\
	}								\
									\
	/* Kernel symbol table: Normal unused symbols */		\
	__ksymtab_unused  : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) {	\
		VMLINUX_SYMBOL(__start___ksymtab_unused) = .;		\
		*(SORT(___ksymtab_unused+*))				\
		VMLINUX_SYMBOL(__stop___ksymtab_unused) = .;		\
	}								\
									\
	/* Kernel symbol table: GPL-only unused symbols */		\
	__ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \
		VMLINUX_SYMBOL(__start___ksymtab_unused_gpl) = .;	\
		*(SORT(___ksymtab_unused_gpl+*))			\
		VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .;	\
	}								\
									\
	/* Kernel symbol table: GPL-future-only symbols */		\
	__ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \
		VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .;	\
		*(SORT(___ksymtab_gpl_future+*))			\
		VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .;	\
	}								\
									\
	/* Kernel symbol table: Normal symbols */			\
	__kcrctab         : AT(ADDR(__kcrctab) - LOAD_OFFSET) {		\
		VMLINUX_SYMBOL(__start___kcrctab) = .;			\
		*(SORT(___kcrctab+*))					\
		VMLINUX_SYMBOL(__stop___kcrctab) = .;			\
	}								\
									\
	/* Kernel symbol table: GPL-only symbols */			\
	__kcrctab_gpl     : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) {	\
		VMLINUX_SYMBOL(__start___kcrctab_gpl) = .;		\
		*(SORT(___kcrctab_gpl+*))				\
		VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .;		\
	}								\
									\
	/* Kernel symbol table: Normal unused symbols */		\
	__kcrctab_unused  : AT(ADDR(__kcrctab_unused) - LOAD_OFFSET) {	\
		VMLINUX_SYMBOL(__start___kcrctab_unused) = .;		\
		*(SORT(___kcrctab_unused+*))				\
		VMLINUX_SYMBOL(__stop___kcrctab_unused) = .;		\
	}								\
									\
	/* Kernel symbol table: GPL-only unused symbols */		\
	__kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \
		VMLINUX_SYMBOL(__start___kcrctab_unused_gpl) = .;	\
		*(SORT(___kcrctab_unused_gpl+*))			\
		VMLINUX_SYMBOL(__stop___kcrctab_unused_gpl) = .;	\
	}								\
									\
	/* Kernel symbol table: GPL-future-only symbols */		\
	__kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \
		VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .;	\
		*(SORT(___kcrctab_gpl_future+*))			\
		VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .;	\
	}								\
									\
	/* Kernel symbol table: strings */				\
        __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) {	\
		*(__ksymtab_strings)					\
	}								\

内核镜像链接脚本调用关系为:

#define RO_DATA(align) RO_DATA_SECTION(align)

arch/arm/kernel/vmlinux.lds.S

#ifdef CONFIG_DEBUG_RODATA
	. = ALIGN(1<<SECTION_SHIFT);
#endif
	RO_DATA(PAGE_SIZE)

	. = ALIGN(4);
	__ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {
		__start___ex_table = .;

最终在系统编译完成链接阶段,会将内核符号链接到对应section中。可以通过查看System.map文件看到对应内容,示例:

ksymtab

……
c05bcfb0 R __start___ksymtab
c05bcfb0 R __start_builtin_fw
c05bcfb0 R __start_pci_fixups_early
c05bcfb0 R __start_pci_fixups_enable
c05bcfb0 R __start_pci_fixups_final
c05bcfb0 R __start_pci_fixups_header
c05bcfb0 R __start_pci_fixups_resume
c05bcfb0 R __start_pci_fixups_resume_early
c05bcfb0 R __start_pci_fixups_suspend
c05bcfb0 R __start_pci_fixups_suspend_late
c05bcfb0 R __stop___bug_table
c05bcfb8 R __ksymtab_PDE_DATA
c05bcfc0 R __ksymtab____pskb_trim
c05bcfc8 R __ksymtab____ratelimit
c05bcfd0 R __ksymtab___aeabi_idiv
c05bcfd8 R __ksymtab___aeabi_idivmod
c05bcfe0 R __ksymtab___aeabi_lasr
c05bcfe8 R __ksymtab___aeabi_llsl
c05bcff0 R __ksymtab___aeabi_llsr
c05bcff8 R __ksymtab___aeabi_lmul
c05bd000 R __ksymtab___aeabi_uidiv
c05bd008 R __ksymtab___aeabi_uidivmod
c05bd010 R __ksymtab___aeabi_ulcmp
……

kstrtab

……
c05c8ee0 r __kstrtab_reset_devices
c05c8eee r __kstrtab_static_key_initialized
c05c8f05 r __kstrtab_system_state
c05c8f12 r __kstrtab_init_uts_ns
c05c8f1e r __kstrtab_init_task
c05c8f28 r __kstrtab_arm_elf_read_implies_exec
c05c8f42 r __kstrtab_elf_set_personality
c05c8f56 r __kstrtab_elf_check_arch
c05c8f65 r __kstrtab_set_irq_flags
c05c8f73 r __kstrtab_arm_check_condition
c05c8f87 r __kstrtab_dump_fpu
c05c8f90 r __kstrtab_thread_notify_head
c05c8fa3 r __kstrtab_pm_power_off
……
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值