尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

modpost __ref (noinline、modpost)

发布时间:2026/9/28 18:37:13

资讯中心
01
ARTICLE

modpost __ref (noinline、modpost)

modpost __ref (noinline、modpost)
__ref是 Linux 内核中用于抑制模块构建modpost阶段“段不匹配Section Mismatch”警告的注解宏。核心作用抑制警告在内核构建过程中modpost工具会检查代码引用关系。如果一个标记为普通段如.text的函数引用了标记为__init初始化后会被释放的函数或数据modpost会发出“Section Mismatch”警告因为这种引用在初始化结束后可能导致崩溃。__ref的作用就是告诉modpost“我知道这个引用看起来有问题但这是安全的请忽略这个警告”。历史与定义__ref系列注解在 2008 年由 Sam Ravnborg 引入用于替代旧的__init_refok、__initdata_refok和__exit_refok宏使注解的语义更清晰。其定义在include/linux/init.h中通常为#define __ref __section(.ref.text) noinline #define __refdata __section(.ref.data) #define __refconst __section(.ref.rodata)被__ref标记的函数会被放入.ref.text段而非默认的.text段。链接脚本会将.ref.text与其他普通文本段合并但modpost在检查时会跳过从.ref.text段发出的引用检查。重要警示__ref仅仅抑制警告并不修复问题本身。它只是一个“承诺”开发者保证该引用在__init代码被释放后不会被实际调用。如果承诺有误系统仍可能崩溃。因此使用__ref时需要确保该函数在初始化完成后确实不会再调用被引用的__init函数或数据。通常需要添加注释说明为什么这个引用是安全的。__section(.ref.text)是 Linux 内核中用于将变量或函数放置到指定命名段section的底层宏它是__ref系列注解的实现基础。核心作用自定义段放置#define __section(s) __attribute__((__section__(s)))__section(.ref.text)展开后是 GCC 的__attribute__((__section__(.ref.text)))属性。它告诉编译器不要把这个函数或变量放到默认的.text或.data段而是放到名为.ref.text的自定义段中。为什么需要.ref.text段这个段的存在与内核构建时的modpost 段不匹配检查直接相关。Linux 内核将不同生命周期的代码和数据放入不同的段.init.text/.init.data初始化完成后会被释放的内存。.text/.data永久保留的常规代码和数据。modpost工具会检查跨段引用。如果一个普通.text段的函数引用了.init.text段的函数modpost会发出警告因为初始化结束后.init.text已被释放这个引用可能导致崩溃。__ref的解决方案是把这类有“可疑”引用的函数从.text移到.ref.text。modpost在检查时会跳过从.ref.text段发出的引用检查从而抑制警告。段名的特殊性段名以.ref开头并非随意选择。modpost的检查逻辑中只有以.ref开头的段才会被豁免。这也是为什么__ref、__refdata、__refconst分别对应.ref.text、.ref.data、.ref.rodata。使用约束使用__section(.ref.text)或__ref时开发者必须自行保证引用的安全性。这只是一种“承诺”而非修复。如果函数在初始化完成后仍然调用了已释放的__init代码系统依然会崩溃。因此内核文档建议在使用时添加注释说明为什么这个引用是安全的。noinline是 Linux 内核中一个禁止编译器将函数内联展开的注解宏。它的核心作用是强制函数保持独立的栈帧这在启动代码、异常处理和调试场景中至关重要。核心作用禁止内联#define noinline __attribute__((noinline))它展开为 GCC 的__attribute__((noinline))属性告诉编译器无论优化级别多高都不要把这个函数内联到它的调用者中。为什么需要noinline在内核启动和异常处理的早期阶段noinline有几个关键用途保持清晰的函数边界在启动代码中如果函数被内联它的代码会“混入”调用者导致栈回溯unwinder难以正确识别函数边界objtool等工具也无法准确分析。避免在敏感路径上引入额外代码在缺页异常、中断入口等场景中内联可能引入额外的栈操作或寄存器保存改变代码的时序和栈布局导致难以调试的问题。确保符号存在某些函数需要作为独立的符号被引用如call指令的目标、kprobe 的挂载点、ftrace 的回调目标。如果被内联这些符号就不复存在。与__ref的协同__ref定义中noinline是它的组成部分#define __ref __section(.ref.text) noinline这里noinline的作用是确保被标记的函数拥有独立的栈帧和符号这样modpost才能正确识别它位于.ref.text段从而跳过段不匹配检查。如果函数被内联到调用者中段放置就失去了意义。与always_inline的对比属性作用典型用途noinline禁止内联启动代码、异常处理、kprobe 目标、调试always_inline强制内联性能关键的短函数、头文件中的内联函数inline建议内联编译器可忽略常规的内联建议在缺页异常处理中你会看到page_fault_oops、kernelmode_fixup_or_oops等函数被标记为noinline正是为了确保在 Oops 发生时栈回溯能显示清晰的函数边界方便定位问题。modpost是 Linux 内核构建流程中的一个核心工具程序它的主要职责是在编译完成后对内核模块.ko文件和内核本身vmlinux进行符号解析、版本校验和段不匹配检查确保模块能正确链接到内核。核心职责modpost在内核构建的“阶段二”被调用处理以下关键任务解析模块依赖读取modules.order确定模块的构建顺序。检查符号引用确保模块使用的所有外部符号都在内核或其他模块中有定义。如果找不到定义它会发出警告通常用KBUILD_MODPOST_WARN可以避免直接报错。生成符号版本信息当启用CONFIG_MODVERSIONS时modpost会利用genksyms生成的校验和为每个导出符号创建Module.symvers文件确保模块加载时符号版本匹配。执行“段不匹配”Section Mismatch检查__ref、.ref.text等机制背后的“执法者”。它检查代码中是否存在从普通段如.text到初始化段如.init.text初始化后会被释放的非法引用并发出警告。段不匹配检查的工作方式当在编译内核时看到类似下面的警告就是modpost在“报警”WARNING: modpost: vmlinux.o(___ksymtab_gpltick_nohz_full_setup0x0): Section mismatch in reference from the variable __ksymtab_tick_nohz_full_setup to the function .init.text:tick_nohz_full_setup()这表示一个被导出的符号tick_nohz_full_setup被标记为__init放在了初始化后会被释放的.init.text段但同时又出现在导出符号表.ksymtab中模块加载时可能访问到已释放的内存导致内核崩溃。modpost通过读取编译生成的 ELF 目标文件中的重定位信息RELA或REL分析每个引用来自哪个段、指向哪个段并对照一份“允许的段引用规则”来判断是否存在风险。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。