跟踪EXPORT_SYMBOL

本文详细解释了EXPORT_SYMBOL宏在内核模块中的使用方式及其生成的代码片段,包括__ksymtab_strings和___ksymtab的链接过程。通过ld链接器的linkerscript,理解了内核模块如何组织和链接符号信息。

1. EXPORT_SYMBOL的定义

/* 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[]			\
	__attribute__((section("__ksymtab_strings"), aligned(1))) \
	= MODULE_SYMBOL_PREFIX #sym;                    	\
	static 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, "")

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

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

So, 当你EXPORT_SYMBOL(fuck)的时候,生成了如下的代码:

<pre name="code" class="cpp">static const char__kstrtab_fuck = "fuck"; //按照__attribute__((section("__ksymtab_strings"), aligned(1)))的限制, __kstrtab_fuck放在<pre name="code" class="cpp"><pre name="code" class="cpp">//__ksymtab_strings section中


<pre name="code" class="cpp">static const struct kernel_symbol__ksymtab_fuck = {&fuck, __kstrtab_fuck};
//按照__attribute__((section("___ksymtab" sec "+" #sym),unused))的限制,应该放在___ksymtab+fuck section中



2. *.ko是个ELF的文件, 使用readelf 查看编译出来的结果, __ksymtab_strings是存在的,可是说好的fuck section呢?肯定是被放在__ksytab中,怎么link进去的呢?

  [ 8] __ksymtab         PROGBITS        00000024 00385c 000010 00   A  0   0  4
  [ 9] .rel__ksymtab     REL             00000000 04bd70 000020 08     42   8  4
  [10] __ksymtab_gpl     PROGBITS        00000034 00386c 000098 00   A  0   0  4
  [11] .rel__ksymtab_gpl REL             00000000 04bd90 000130 08     42  10  4
  [12] .rodata           PROGBITS        00000000 003904 000462 00   A  0   0  4
  [13] .rel.rodata       REL             00000000 04bec0 0000d0 08     42  12  4
  [14] .modinfo          PROGBITS        00000000 003d66 0000e9 00   A  0   0  1
  [15] .rodata.str1.1    PROGBITS        00000000 003e4f 000c37 01 AMS  0   0  1
  [16] __ksymtab_strings PROGBITS        00000000 004a86 000230 00   A  0   0  1

3. 原来是ld根据linker script来工作的,我的项目的script: kernel/linux-3.0.35/dist/scripts/module-common.lds

/*
 * Common module linker script, always used when linking a module.
 * Archs are free to supply their own linker scripts.  ld will
 * combine them automatically.
 */
SECTIONS {
	/DISCARD/ : { *(.discard) }

	__ksymtab		: { *(SORT(___ksymtab+*)) }
	__ksymtab_gpl		: { *(SORT(___ksymtab_gpl+*)) }
	__ksymtab_unused	: { *(SORT(___ksymtab_unused+*)) }
	__ksymtab_unused_gpl	: { *(SORT(___ksymtab_unused_gpl+*)) }
	__ksymtab_gpl_future	: { *(SORT(___ksymtab_gpl_future+*)) }
	__kcrctab		: { *(SORT(___kcrctab+*)) }
	__kcrctab_gpl		: { *(SORT(___kcrctab_gpl+*)) }
	__kcrctab_unused	: { *(SORT(___kcrctab_unused+*)) }
	__kcrctab_unused_gpl	: { *(SORT(___kcrctab_unused_gpl+*)) }
	__kcrctab_gpl_future	: { *(SORT(___kcrctab_gpl_future+*)) }

4. 在insmod的时候,find_module_sections就可以查找到__ksymtab

5. 为什么要

__attribute__((section("___ksymtab" sec "+" #sym), unused))
而不是直接

__attribute__((section("___ksymtab"), unused))

搜索了下,是为了提高ld的执行效率

#include <linux/types.h> #include <linux/seq_file.h> #include <net/netfilter/nf_conntrack.h> #include <net/netfilter/nf_conntrack_expect.h> #include <linux/bcm_nf_conntrack.h> #include <linux/bcm_nf_expect.h> int ct_show_bcm_ext(struct seq_file *s, const struct nf_conn *ct) { #if IS_ENABLED(CONFIG_BCM_INGQOS) seq_printf(s, "iqprio=%u ", ct->bcm_ext.iq_prio); #endif #if defined(CONFIG_BCM_KF_NF_REGARDLESS_DROP) seq_printf(s, "swaccel=%u ", ct->bcm_ext.sw_accel_flows); seq_printf(s, "hwaccel=%u ", ct->bcm_ext.hw_accel_flows); #endif return seq_has_overflowed(s); } EXPORT_SYMBOL(ct_show_bcm_ext); #if defined(CONFIG_BLOG) bool bcm_nf_blog_ct_is_expired(const struct nf_conn *ct) { BlogCtTime_t ct_time; /*query the timeout status from blog */ memset(&ct_time, 0, sizeof(ct_time)); blog_lock(); if (ct->bcm_ext.blog_key[BLOG_PARAM1_DIR_ORIG] != BLOG_KEY_FC_INVALID || ct->bcm_ext.blog_key[BLOG_PARAM1_DIR_REPLY] != BLOG_KEY_FC_INVALID) { blog_query(QUERY_FLOWTRACK, (void *)ct, ct->bcm_ext.blog_key[BLOG_PARAM1_DIR_ORIG], ct->bcm_ext.blog_key[BLOG_PARAM1_DIR_REPLY], (unsigned long) &ct_time); } blog_unlock(); if (ct_time.flags.valid) { signed long newtimeout; newtimeout = ct->bcm_ext.extra_jiffies - (ct_time.idle * HZ); if (newtimeout > 0) { ((struct nf_conn *)ct)->timeout = newtimeout + nfct_time_stamp; return false; } } /* ct is expired */ return true; } EXPORT_SYMBOL(bcm_nf_blog_ct_is_expired); #endif /*CONFIG_BLOG */ #if defined(CONFIG_BCM_NF_DERIVED_CONN) DEFINE_SPINLOCK(bcm_derived_conn_lock); EXPORT_SYMBOL(bcm_derived_conn_lock); #endif #if IS_ENABLED(CONFIG_BCM_HW_FIREWALL) bcm_hwf_ct_event_t __rcu bcm_hwf_ct_event_fn = NULL; EXPORT_SYMBOL(bcm_hwf_ct_event_fn); extern bcm_hwf_expect_event_t __rcu bcm_hwf_expect_event_fn = NULL; EXPORT_SYMBOL(bcm_hwf_expect_event_fn); #endif结合分析local in加速
11-18
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值