什么是内核部分不匹配?

当编译一个内核模块时,我得到了一个警告和一个注释来添加一个编译选项CONFIG_DEBUG_SECTION_MISMATCH = y 。 它给了我更多有关问题的详细信息:

WARNING: \**\*path to module\***(.text+0x8d2): Section mismatch in reference from the function Pch_Spi_Enable_Bios_Wr() to the variable .devinit.data:ich9_pci_tbl.22939 The function Pch_Spi_Enable_Bios_Wr() references the variable __devinitdata ich9_pci_tbl.22939. This is often because Pch_Spi_Enable_Bios_Wr lacks a __devinitdata annotation or the annotation of ich9_pci_tbl.22939 is wrong. 

我找不到什么内核部分不匹配 ,更不用说如何去解决它。

这意味着具有给定生命周期的部分中的函数引用了具有不同生命周期的部分中的某个东西。

当内核二进制链接时,代码和数据的不同部分被分成不同的部分。 其中一些部分一直保持加载,但其他部分在不再需要时会被删除(例如启动过程中只需要启动的部分就可以在启动完成后释放 – 这样可以节省内存)。

如果一个持久部分中的函数引用了其中一个可丢弃部分中的数据,则存在一个问题 – 它可能试图在数据已经被释放时访问该数据,从而导致各种运行时问题。

这不是一个警告,除非你写了那个代码,或者对它非常熟悉。 它通过正确的注释函数(或者它所引用的数据)被修正,以便它进入正确的部分。 正确的修复只能通过对内核部分的详细了解来确定。


有关这些部分和注释的列表,请参阅内核源代码树中的include/linux/init.h头文件:

 /* These macros are used to mark some functions or * initialized data (doesn't apply to uninitialized data) * as `initialization' functions. The kernel can take this * as hint that the function is used only during the initialization * phase and free up used memory resources after * * Usage: * For functions: * * You should add __init immediately before the function name, like: * * static void __init initme(int x, int y) * { * extern int z; z = x * y; * } * * If the function has a prototype somewhere, you can also add * __init between closing brace of the prototype and semicolon: * * extern int initialize_foobar_device(int, int, int) __init; * * For initialized data: * You should insert __initdata between the variable name and equal * sign followed by value, eg: * * static int init_variable __initdata = 0; * static const char linux_logo[] __initconst = { 0x32, 0x36, ... }; * * Don't forget to initialize data not at file scope, ie within a function, * as gcc otherwise puts the data into the bss section and not into the init * section. * * Also note, that this data cannot be "const". */ /* These are for everybody (although not all archs will actually discard it in modules) */ #define __init __section(.init.text) __cold notrace #define __initdata __section(.init.data) #define __initconst __section(.init.rodata) #define __exitdata __section(.exit.data) #define __exit_call __used __section(.exitcall.exit) 

其他人跟随,更多评论和解释。

另请参阅CONFIG_DEBUG_SECTION_MISMATCH Kconfig符号的帮助文本:

部分不匹配分析检查是否有非法
从一个部分引用到另一个部分。
Linux将在链接或运行时删除一些部分
以及这些部分中以前对代码/数据的任何使用
最有可能导致哎呀。
在代码中,函数和变量都用注释
__init,__devinit等(请参阅include / linux / init.h中的完整列表)
这导致代码/数据被放置在特定的部分中。
部分不匹配分析总是在完成之后完成
内核版本,但启用此选项将另外
请执行下列操作:

  • 将选项-fno-inline-functions-called-once添加到gcc
    在非init初始化一个注释了__init的函数时
    功能,我们将失去部分信息,从而
    这个分析不会抓到非法的参考。
    这个选项告诉gcc内联少,但也将
    导致更大的内核。
  • 对每个模块/ built-in.o运行部分不匹配分析
    当我们在vmlinux.o上运行部分不匹配分析时,
    失去有价值的信息关于错配的地方
    介绍。
    运行每个模块/内置.o文件的分析
    将告诉哪里的失配发生在更接近的地方
    资源。 缺点是我们会报告相同的
    不匹配至少两次。
  • 从modpost启用详细的报告来帮助解决
    报告的部分不匹配。