8

I have this embedded Linux devices. I would like to add kernel-level functionality to it, but would highly prefer not to compile my own kernel to do so. (If the kernel doesn't load and get to user space the device is bricked; I can't access the bootloader to recover it. The current kernel doesn't have kexec support so I couldn't use that to test a kernel image of my own.)

The device's kernel has support for modules, but I do not have a copy of the corresponding Module.symvers file.

My question: if I do not have the Module.symvers file for a Linux kernel but do have the kernel image and a module compiled for it, can I compile more modules that can be inserted into that kernel, maybe by generating the missing Module.symvers file?

The device is running Linux kernel version 3.10.
Kernel image (in its uImage container): https://www.olio.watch/olio-firmware-1.10.220/olio-firmware/uImage
Configuration (extracted from above image thanks to CONFIG_IKCONFIG): https://www.olio.watch/3.10.0-g2ae2f33-config
The one kernel module I have that matches that kernel: https://www.olio.watch/olio-firmware-1.10.220/olio-firmware/drv2605.ko

Billy
  • 665
  • I think this depends on the kernel configuration for the kernel on the embedded device. Can you force load modules with modprobe --force? – Alexander Oct 15 '18 at 08:49
  • 1
    @Goro I can only find one .ko file that matches the kernel: http://www.olio.watch/olio-firmware-1.10.220/olio-firmware/drv2605.ko – Billy Oct 16 '18 at 00:29
  • @Alexander The BusyBox modprobe on the system doesn't have --force (they stripped it in every way they could), I'll look into syscalls kmod uses and try to write my own simple program. In the meantime, here's the configuration if you'd like to take a look: http://www.olio.watch/3.10.0-g2ae2f33-config – Billy Oct 16 '18 at 00:33
  • @Goro Doesn't look like it does. It's small, only 20 kilobytes, and it doesn't contain the string 'Module.symvers' (or anything like that) anywhere. – Billy Oct 16 '18 at 00:48
  • 1
    @Goro Thanks for your help, looking forward to your answer! In the meantime, I'll try looking for anything useful in the actual kernel image. – Billy Oct 16 '18 at 00:55
  • In other words, without Module.symvers, an external build module could still be compiled and functional properly? The drawback is that it would let build system complaining about undefined symbols? – Louis Go Oct 26 '20 at 07:46

1 Answers1

7

First, in order to answer your question "can I compile Linux kernel module without Module.symvers", we need to understand what is the purpose of Module.symvers:

Module.symvers serves two main purposes:

1) It lists all exported symbols from vmlinux and all modules.

2) It lists the CRC if CONFIG_MODVERSIONS is enabled. Without CONFIG_MODVERSIONS enabled, the CRC would read 0x00000000.

Module.symvers will be generated during a kernel build, it contains all exported symbols from the kernel and compiled modules. For each symbol, the corresponding CRC value is also stored. The syntax of the Module.symvers file is:

    <CRC>       <Symbol>           <module>

For example:

    0x2d036834  scsi_remove_host   drivers/scsi/scsi_mod

Having said that, if we have Module.symvers then we can build any module because it contain all the necessary symbols.

If Module.symvers is not available, we still able to build an external module either by building this file or by borrowing it from another module.

Usually, when building an external module, the build system needs access to the symbols from the kernel to check if all external symbols are defined. This is done in a build step called MODPOST. This step obtains the symbols by reading Module.symvers from the kernel source tree.

If a Module.symvers file is present in the directory where the external module is being built, this file will be read too. During the MODPOST step, a new Module.symvers file will be written containing all exported symbols that were not defined in the kernel.

if Module.symvers file is not present, then an external module might be using an exported symbols from another external module, kbuild needs to have full knowledge of all symbols to avoid spitting out warnings about undefined symbols.

For this situation, there are three solutions:

1) Use a top-level kbuild file: If you have two modules, foo.ko and bar.ko, where foo.ko needs symbols from bar.ko, you can use a common top-level kbuild file so both modules are compiled in the same build. Consider the following directory layout:

    ./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.

2) Use an extra Module.symvers file: When an external module is built, a Module.symvers file is generated containing all exported symbols which are not defined in the kernel. To get access to symbols from bar.ko, copy the Module.symvers file from the compilation of bar.ko to the directory where foo.ko is built. During the module build, kbuild will read the Module.symvers file in the directory of the external module, and when the build is finished, a new Module.symvers file is created containing the sum of all symbols defined and not part of the kernel.

3) Use "make" variable KBUILD_EXTRA_SYMBOLS: If it is impractical to copy Module.symvers from another module, you can assign a space separated list of files to KBUILD_EXTRA_SYMBOLS in your build file. These files will be loaded by modpost during the initialization of its symbol tables.

More details 1