不使用 Module.symvers 编译 Linux 内核模块

Bil*_*lly 8 kernel-modules

我有这个嵌入式 Linux 设备。我想向它添加内核级功能,但非常不想编译我自己的内核来这样做。(如果内核未加载并进入用户空间,则设备变砖;我无法访问引导加载程序来恢复它。当前内核没有 kexec 支持,因此我无法使用它来测试内核映像我自己的。)

设备的内核支持模块,但我没有相应 Module.symvers 文件的副本。

我的问题:如果我没有 Linux 内核的 Module.symvers 文件,但有内核映像和为其编译的模块,我是否可以编译更多可以插入该内核的模块,也许是通过生成缺少的模块。 symvers 文件?

该设备正在运行 Linux 内核版本 3.10。
内核图像(在其的uImage容器):https://www.olio.watch/olio-firmware-1.10.220/olio-firmware/uImage
:配置(从上方图像由于CONFIG_IKCONFIG中提取)的https://www.olio .watch/3.10.0-g2ae2f33-config
我拥有的一个与该内核匹配的内核模块:https : //www.olio.watch/olio-firmware-1.10.220/olio-firmware/drv2605.ko

小智 5

首先,为了回答你的问题“我可以在没有 Module.symvers 的情况下编译 Linux 内核模块吗”,我们需要了解 什么是目的Module.symvers

Module.symvers 有两个主要目的:

1) 它列出了从 vmlinux 和所有模块导出的所有符号。

2) 如果CONFIG_MODVERSIONS启用,它会列出 CRC 。如果未CONFIG_MODVERSIONS启用,CRC 将读取 0x00000000。

Module.symvers将在内核构建期间生成,它包含从内核和编译模块中导出的所有符号。对于每个符号,还存储了相应的 CRC 值。Module.symvers 文件的语法是:

    <CRC>       <Symbol>           <module>
Run Code Online (Sandbox Code Playgroud)

例如:

    0x2d036834  scsi_remove_host   drivers/scsi/scsi_mod
Run Code Online (Sandbox Code Playgroud)

话虽如此,如果我们有Module.symvers那么我们可以构建任何模块,因为它包含所有必要的符号。

如果Module.symvers 不可用,我们仍然可以通过构建此文件或从另一个模块借用它来构建外部模块。

通常,在构建外部模块时,构建系统需要访问内核中的符号以检查是否定义了所有外部符号。这是在名为 的构建步骤中完成的MODPOST。这一步通过Module.symvers从内核源代码树中读取来获取符号。

如果Module.symvers正在构建外部模块的目录中存在文件,则该文件也将被读取。在此MODPOST步骤中,Module.symvers将写入一个包含所有未在内核中定义的导出符号的新文件。

如果 Module.symvers文件不存在,则外部模块可能正在使用从另一个外部模块导出的符号,kbuild需要充分了解所有符号以避免发出有关未定义符号的警告。

针对这种情况,有以下三种解决方案:

1)使用顶层kbuild文件:如果你有两个模块,foo.ko并且bar.ko,其中foo.ko从需求的符号bar.ko,你可以使用一个共同的顶层kbuild文件,因此两个模块在同一个构建编译。考虑以下目录布局:

    ./foo/ <= contains foo.ko
    ./bar/ <= contains bar.ko

    The top-level kbuild file would then look like:

    #./Kbuild (or ./Makefile):
        obj-y := foo/ bar/

    And executing

        $ make -C $KDIR M=$PWD

    will then do the expected and compile both modules with
    full knowledge of symbols from either module.
Run Code Online (Sandbox Code Playgroud)

2) 使用额外Module.symvers文件:构建外部模块时,Module.symvers会生成一个文件,其中包含所有未在内核中定义的导出符号。要访问 中的符号bar.ko,请将编译后的 bar.ko 中的 Module.symvers 文件复制到构建 foo.ko 的目录中。在模块构建期间,kbuild将读取Module.symvers外部模块目录中的文件,当构建完成时,Module.symvers会创建一个新文件,其中包含定义的所有符号的总和,而不是内核的一部分。

3)使用“make”变量KBUILD_EXTRA_SYMBOLS:如果Module.symvers从另一个模块复制不切实际,您可以KBUILD_EXTRA_SYMBOLS在构建文件中分配一个空格分隔的文件列表。这些文件将modpost在其符号表的初始化期间加载。

更多详情1