我們再用nm命令查看一下該目標文件的外部函數列表。nm hello.ko:00000000 r __mod_alias25 0000003c r __mod_author23 00000018 r __mod_description24 00000050 r __mod_license5 0000005c r __mod_srcversion23 0000008c r __mod_vermagic5 00000080 r __module_depends 00000000 D __this_module 00000000 T cleanup_module U hello_data 00000000 t hello_exit 0000002d t hello_init 0000002d T init_module U mcount U printkU代表未解決的引用,可見都為內核代碼中的導出函數,D表示符號位於數據段,T表示符號位於代碼段。內核提供了一個所有導出函數的列表。該列表給出了所有導出函數的內存地址和對應的函數名,可以通過proc文件系統訪問,即文件/proc/kallsyms。
/* Exported symbols */ /*syms為一個數組,共有num_syms項, 類型kernel_symbol負責將標識符(name欄位) 分配到內存地址(value欄位)*/ const struct kernel_symbol *syms; /*也是num_syms個項的數組,存放了到處富豪的校驗和 用於實現版本控制*/ const unsigned long *crcs; unsigned int num_syms;
/* Kernel parameters. */ struct kernel_param *kp; unsigned int num_kp;
/* GPL-only exported symbols. */ unsigned int num_gpl_syms; const struct kernel_symbol *gpl_syms; const unsigned long *gpl_crcs;
#ifdef CONFIG_UNUSED_SYMBOLS /* unused exported symbols. */ const struct kernel_symbol *unused_syms; const unsigned long *unused_crcs; unsigned int num_unused_syms;
/* GPL-only, unused exported symbols. */ unsigned int num_unused_gpl_syms; const struct kernel_symbol *unused_gpl_syms; const unsigned long *unused_gpl_crcs; #endif
/* symbols that will be GPL-only in the near future. */ const struct kernel_symbol *gpl_future_syms; const unsigned long *gpl_future_crcs; unsigned int num_gpl_future_syms;
/* Exception table */ unsigned int num_exentries; struct exception_table_entry *extable;
/* Startup function. */ int (*init)(void);
/* If this is non-NULL, vfree after init() returns */ /*模塊二進位數據分為兩個部分:初始化部分和核心部分 前者包含的東西在裝載結束后都可以丟棄 後者包含了正常運行期間需要的所有數據 初始化部分的起始地址保存在module_init*/ void *module_init;
/* Here is the actual code + data, vfree'd on unload. */ void *module_core;
/* Here are the sizes of the init and core sections */ unsigned int init_size, core_size;
/* The size of the executable code in each section. */ unsigned int init_text_size, core_text_size;
unsigned int taints; /* same bits as kernel:tainted */
#ifdef CONFIG_GENERIC_BUG /* Support for BUG */ unsigned num_bugs; struct list_head bug_list; struct bug_entry *bug_table; #endif
#ifdef CONFIG_KALLSYMS /* * We keep the symbol and string tables for kallsyms. * The core_* fields below are temporary, loader-only (they * could really be discarded after module init). */ Elf_Sym *symtab, *core_symtab; unsigned int num_symtab, core_num_syms; char *strtab, *core_strtab;
/* The command line arguments (may be mangled). People like keeping pointers to this stuff */ char *args; #ifdef CONFIG_TRACEPOINTS struct tracepoint *tracepoints; unsigned int num_tracepoints; #endif
#ifdef CONFIG_TRACING const char **trace_bprintk_fmt_start; unsigned int num_trace_bprintk_fmt; #endif #ifdef CONFIG_EVENT_TRACING struct ftrace_event_call *trace_events; unsigned int num_trace_events; #endif #ifdef CONFIG_FTRACE_MCOUNT_RECORD unsigned long *ftrace_callsites; unsigned int num_ftrace_callsites; #endif
#ifdef CONFIG_MODULE_UNLOAD /* What modules depend on me? */ /*將依賴本模塊的模塊用module_use數據結構鏈接 起來*/ struct list_head modules_which_use_me;
/* Who is waiting for us to be unloaded */ struct task_struct *waiter;
/* Exported symbols */ /*syms為一個數組,共有num_syms項, 類型kernel_symbol負責將標識符(name欄位) 分配到內存地址(value欄位)*/ const struct kernel_symbol *syms; /*也是num_syms個項的數組,存放了到處富豪的校驗和 用於實現版本控制*/ const unsigned long *crcs; unsigned int num_syms;
/* Kernel parameters. */ struct kernel_param *kp; unsigned int num_kp;
/* GPL-only exported symbols. */ unsigned int num_gpl_syms; const struct kernel_symbol *gpl_syms; const unsigned long *gpl_crcs;
#ifdef CONFIG_UNUSED_SYMBOLS /* unused exported symbols. */ const struct kernel_symbol *unused_syms; const unsigned long *unused_crcs; unsigned int num_unused_syms;
/* GPL-only, unused exported symbols. */ unsigned int num_unused_gpl_syms; const struct kernel_symbol *unused_gpl_syms; const unsigned long *unused_gpl_crcs; #endif
/* symbols that will be GPL-only in the near future. */ const struct kernel_symbol *gpl_future_syms; const unsigned long *gpl_future_crcs; unsigned int num_gpl_future_syms;
/* Exception table */ unsigned int num_exentries; struct exception_table_entry *extable;
/* Startup function. */ int (*init)(void);
/* If this is non-NULL, vfree after init() returns */ /*模塊二進位數據分為兩個部分:初始化部分和核心部分 前者包含的東西在裝載結束后都可以丟棄 後者包含了正常運行期間需要的所有數據 初始化部分的起始地址保存在module_init*/ void *module_init;
/* Here is the actual code + data, vfree'd on unload. */ void *module_core;
/* Here are the sizes of the init and core sections */ unsigned int init_size, core_size;
/* The size of the executable code in each section. */ unsigned int init_text_size, core_text_size;
unsigned int taints; /* same bits as kernel:tainted */
#ifdef CONFIG_GENERIC_BUG /* Support for BUG */ unsigned num_bugs; struct list_head bug_list; struct bug_entry *bug_table; #endif
#ifdef CONFIG_KALLSYMS /* * We keep the symbol and string tables for kallsyms. * The core_* fields below are temporary, loader-only (they * could really be discarded after module init). */ Elf_Sym *symtab, *core_symtab; unsigned int num_symtab, core_num_syms; char *strtab, *core_strtab;
/* The command line arguments (may be mangled). People like keeping pointers to this stuff */ char *args; #ifdef CONFIG_TRACEPOINTS struct tracepoint *tracepoints; unsigned int num_tracepoints; #endif
#ifdef CONFIG_TRACING const char **trace_bprintk_fmt_start; unsigned int num_trace_bprintk_fmt; #endif #ifdef CONFIG_EVENT_TRACING struct ftrace_event_call *trace_events; unsigned int num_trace_events; #endif #ifdef CONFIG_FTRACE_MCOUNT_RECORD unsigned long *ftrace_callsites; unsigned int num_ftrace_callsites; #endif
#ifdef CONFIG_MODULE_UNLOAD /* What modules depend on me? */ /*將依賴本模塊的模塊用module_use數據結構鏈接 起來*/ struct list_head modules_which_use_me;
/* Who is waiting for us to be unloaded */ struct task_struct *waiter;