2011-12-19 107 views
28

当编译一个内核模块时,我得到了一个WARNING和一个注释来添加一个编译选项,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. 

我不能准确地找到内核部分不匹配是什么,更不用说如何去修复它。

回答

35

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

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

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

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


对于这些部分和注释的列表,请参阅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中的完整列表)
这导致代码/数据被放置在特定节中。
的部分错配分析是一个完整的
内核编译后一直在做,但启用这个选项将除了
做到以下几点:

  • -fno内联函数称为一次添加的选项GCC
    当在非初始化函数内嵌入函数注释__init时,我们将失去区域信息,因此分析不会捕获非法引用。
    这个选项告诉gcc内联更少,但也会导致更大的内核产生
  • 运行部分错配分析为每个模块/内置in.o
    当我们在vmlinux.o运行部分错配分析,我们
    输在哪里不匹配是
    介绍valueble信息。
    运行每个模块/内置.o文件的分析
    会告诉哪里的不匹配发生得更接近
    源。缺点是我们会报告相同的
    不匹配至少两次。
  • 启用来自modpost的详细报告以帮助解决
    报告的部分不匹配。