kallsyms是 Linux 内核内置的符号地址映射机制核心是在编译时生成压缩符号表并链接进内核运行时提供地址↔符号名双向查询支撑调试、栈回溯、模块依赖解析等场景。本质内核镜像里的只读符号表替代传统System.map运行时可直接访问。核心能力地址 → 符号名如0xffffffff81050000→schedule符号名 → 地址如schedule→0xffffffff81050000支持内核与加载模块的符号查询典型用途内核 Oops 栈回溯、printk符号打印、perf/ftrace/kprobe性能分析、内核模块符号解析。编译阶段符号表生成与压缩scripts/kallsyms.c1. 符号提取内核编译最后阶段主机工具scripts/kallsyms扫描vmlinux提取地址、类型、名称三类信息。符号按地址升序排序确保运行时可二分查找。2. 数据结构构建核心数组内核将符号信息编码为以下只读数组链接到__kallsyms段数组名类型作用kallsyms_num_symsunsigned long总符号数kallsyms_addressesunsigned long[]符号地址已排序kallsyms_offsetsunsigned long[]地址差分编码压缩kallsyms_namesu8[]压缩符号名字符串kallsyms_token_tableu8[]Token 字典高频子串kallsyms_token_indexu16[]Token 索引表kallsyms_markersunsigned long[]查找加速标记3. 关键压缩算法空间优化地址差分编码只存相邻地址差值大幅减少kallsyms_addresses体积。Token 替换字典压缩统计高频子串如sys_、__init、irq映射为单字节 Token0–255。符号名存储格式[长度][类型][Token/原字符...]。示例sys_schedule→ 用 Token 替换sys_仅存[长度][T][Token][schedule]。运行阶段符号查询与解析kernel/kallsyms.c1. 地址 → 符号名核心kallsyms_lookup二分查找定位在排序的kallsyms_addresses中二分找到目标地址所属符号的索引。地址还原用kallsyms_offsets差分解码得到符号实际地址。符号名解压从kallsyms_names读取对应偏移的压缩串。调用kallsyms_expand_symbol遍历 Token 字典还原完整符号名与类型T/t/V/v 等。返回结果输出符号名、所属模块、地址偏移。2. 符号名 → 地址核心kallsyms_lookup_name遍历所有符号解压每个符号名并匹配目标名。匹配成功则返回对应地址内核符号未找到时继续查询模块符号表。3. /proc/kallsyms 虚拟文件内核通过seq_file接口遍历并解压所有符号实时生成文本输出。格式地址 类型 符号名如ffffffff8123f8e0 T do_softirq_own_stack。关键内核接口kallsyms_lookup(addr, ...)地址查符号名、模块、偏移。kallsyms_lookup_name(name)符号名查地址。kallsyms_on_each_symbol(fn)遍历所有内核符号并回调。module_kallsyms_lookup_name(name)查询模块符号。配置与安全内核配置CONFIG_KALLSYMSy启用基础符号表。CONFIG_KALLSYMS_ALLy包含静态函数 / 变量调试用生产建议关闭。安全生产环境可通过kptr_restrict限制非 root 读取/proc/kallsyms防止地址泄露。kallsyms 符号提取一定会被提取的符号默认必进这些符号不管是否 EXPORT 都会被 kallsyms 收录有序列表内核所有全局函数如schedule、sys_open、do_exit、copy_process内核所有全局变量如jiffies、init_task、current_task所有可加载内核模块的全局符号模块里的global function/var都会进/proc/kallsyms汇编代码里的全局符号如中断入口、异常处理、系统调用入口只要是全局global且非弱别名的内核符号默认必进 kallsyms。默认不提取但开启配置后会提取静态函数 / 静态变量默认不进kallsyms。开启后全部进入CONFIG_KALLSYMS_ALLy开启后static functionstatic variable全部会被提取用于调试、栈回溯、kprobe 跟踪静态函数。绝对不会被 kallsyms 提取的符号编译器自动生成的局部符号.L 开头弱别名符号如系统调用包装函数编译阶段被优化掉的符号内核启动后被释放的段中的符号如.init段函数执行完释放用户态程序符号kallsyms 只管内核符号类型字母你可以直接用这个判断符号类型类型含义是否进 kallsymsT/tTEXT 段函数代码是t 只有 KALLSYMS_ALL 才会显示R/r只读数据是D/d已初始化数据是B/b未初始化数据是A绝对地址很少U未定义符号不进大写 全局小写 静态System.mapSystem.map编译时生成的静态文本文件内核运行时用不到只是给人看 / 工具用。kallsyms编译时打进内核镜像里的压缩数据结构内核运行时自己要用并暴露/proc/kallsyms。内置数据结构运行时核心依赖支持动态模块与随机地址。内核编译完成后自动生成是一个符号地址对照表格式ffffffff81000000 T startup_64 ffffffff81000040 T early_idt_handler内核运行时根本不读取它作用给调试工具gdb、objdump做地址对照核心区别特性System.mapkallsyms存在形式磁盘上的文本文件内核镜像里的压缩数据运行时是否可用❌ 完全不用✅ 内核必须用如何查看cat System.mapcat /proc/kallsyms是否动态更新❌ 固定不变✅ 加载模块会自动新增地址是否真实✅ 固定物理 / 链接地址✅ 显示运行时真实地址占用空间几 MB 文本几百 KB 压缩数据主要用途调试、对照、离线分析内核栈回溯、oops、kprobe、perf缺点不支持动态模块不支持随机地址KASLR运行时不可用EXPORT_SYMBOL作用将内核函数 / 变量标记为可被内核模块调用的全局符号解决模块加载时的符号重定位问题。常用宏EXPORT_SYMBOL(sym)导出符号对所有模块开放。EXPORT_SYMBOL_GPL(sym)仅对 GPL 协议模块开放。EXPORT_SYMBOL_NS(sym, NS)导出到指定命名空间。底层把符号信息存入内核特殊段__ksymtab/__ksymtab_gpl供模块加载器查找。EXPORT_SYMBOL决定哪些符号进入内核导出表可被模块合法调用。kallsyms是全量符号数据库含导出 未导出用于调试与运行时查找。/proc/kallsyms默认只显示EXPORT_SYMBOL导出的符号大写T/t等。EXPORT_SYMBOL只决定模块能否调用不影响是否进入 kallsyms即使不导出的全局函数也会出现在/proc/kallsyms特性EXPORT_SYMBOLkallsyms可见性仅导出符号全量符号含静态用途模块间合法调用调试、Oops、动态查找权限需内核源码修改运行时查表无需重编内核风险稳定 ABI未导出符号无 ABI 保障原理总结编译时提取符号 → 排序 → 差分压缩地址 Token 压缩名称 → 生成只读数组并链接进内核。运行时通过二分查找快速定位地址解压 Token 还原符号名提供双向查询与/proc/kallsyms接口。价值以极小内存开销实现内核符号的运行时可访问是内核调试与性能分析的基础设施。所有全局内核 / 模块符号 开启 KALLSYMS_ALL 后的所有静态符号。