什么是内核段不匹配?

30

在编译内核模块时,我收到了一个警告,提示我添加一个编译选项CONFIG_DEBUG_SECTION_MISMATCH=y。它提供了有关问题更详细的信息:


当编译一个内核模块时,我收到了一个警告,并提示我需要添加一个编译选项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.

我无法确切地找到什么是内核段不匹配,更不用说如何解决它了。

1个回答

40
这意味着一个函数位于具有特定生存期的部分中,引用了位于具有不同生存期的另一个部分中的内容。
当内核二进制文件链接时,代码和数据的不同部分被拆分为不同的部分。其中一些部分始终保持加载状态,但其他某些部分在不再需要时被删除(例如,只在启动期间需要的东西可以在启动完成后释放 - 这样可以节省内存)。
如果一个位于长时间存在的部分中的函数引用了可丢弃部分中的数据,则存在问题 - 当已经释放该数据时,它可能尝试访问该数据,从而导致各种运行时问题。
除非您编写了该代码或非常熟悉它,否则您无法修复此警告。可以通过正确注释函数(或其引用的数据)以使其进入正确的部分来解决此问题。正确的修复只能通过详细了解内核的该部分来确定。
要查看这些部分和注释的列表,请参阅内核源树中的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, e.g.:
 *
 * static int init_variable __initdata = 0;
 * static const char linux_logo[] __initconst = { 0x32, 0x36, ... };
 *
 * Don't forget to initialize data not at file scope, i.e. 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在链接或运行时将删除一些部分,
以前在这些部分中使用的代码/数据将很可能导致oops。
在代码函数和变量中注释了__init、__devinit等(请参见include/linux/init.h中的完整列表),
这会导致代码/数据被放置在特定的部分中。
段匹配分析总是在完整内核构建之后完成,但启用此选项还将执行以下操作:

  • 向gcc添加选项-fno-inline-functions-called-once
    当内联非init函数中注释为__init的函数时,我们将失去部分信息,
    因此分析将无法捕获非法引用。
    此选项告诉gcc要减少内联,但也会
    导致内核变得更大。
  • 对每个模块/built-in.o运行段不匹配分析
    当我们在vmlinux.o上运行段不匹配分析时,
    我们会丢失有关不匹配发生位置的有价值信息。
    对每个模块/built-in.o文件运行分析
    将更接近源代码地告知不匹配发生的位置。缺点是我们将至少报告相同的不匹配两次。
  • 启用modpost的详细报告以帮助解决
    报告的段不匹配问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接