/proc/version
. If, like me, you are assembling a module for an Android device, try Android kernels from Code Aurora, Cyanogen or Android, the ones closest to your device. In my case, it was the core of msm-3.0. Note that you do not need to search for exactly the same source version as the version of your kernel image. Minor version differences are most likely not to be a hindrance. I used the kernel source 3.0.21, while the version of the existing kernel image was 3.0.8. Do not try, however, to use the source code for the 3.1 kernel if you have a 3.0.x kernel image./proc/config.gz
file, you can start with this, otherwise, you can try to start with the default configuration, but in this case you need to be extremely careful ( although I will not go into the details of using the default configuration, as I was lucky not to resort to this, then there will be some details as to why the correct configuration is so important).arm-eabi-gcc
is accessible through one of the paths in the PATH environment variable, and that the terminal is open in the folder with the kernel source files, you can start the kernel configuration and the installation of header files and scripts: $ mkdir build $ gunzip config.gz > build/.config # , , .config $ make silentoldconfig prepare headers_install scripts ARCH=arm CROSS_COMPILE=arm-eabi- O=build KERNELRELEASE=`adb shell uname -r`
silentoldconfig
is most likely to ask if you want to enable certain options. You can choose defaults, but this may well not work.KERNELRELEASE
, however, this must match exactly the version of the kernel from which you plan to load the module.Makefile
. hello.c
following code in the file hello.c
, in a separate directory: #include <linux/module.h> /* Needed by all modules */ #include <linux/kernel.h> /* Needed for KERN_INFO */ #include <linux/init.h> /* Needed for the macros */ static int __init hello_start(void) { printk(KERN_INFO "Hello world\n"); return 0; } static void __exit hello_end(void) { printk(KERN_INFO "Goodbye world\n"); } module_init(hello_start); module_exit(hello_end);
Makefile
in the same directory: obj-m = hello.o
hello.mod.c
, the contents of which can create various problems: MODULE_INFO(vermagic, VERMAGIC_STRING);
VERMAGIC_STRING
determined by the VERMAGIC_STRING
macro, which is located in the include/generated/utsrelease.h
generated by the kernel build system. By default, this value is determined by the kernel version and git repository status. This is what KERNELRELEASE
when configuring the kernel. If VERMAGIC_STRING
does not match the kernel version, loading the module will result in a message of this kind in the dmesg
: hello: version magic '3.0.21-perf-ge728813-00399-gd5fa0c9' should be '3.0.8-perf'
struct module __this_module __attribute__((section(".gnu.linkonce.this_module"))) = { .name = KBUILD_MODNAME, .init = init_module, #ifdef CONFIG_MODULE_UNLOAD .exit = cleanup_module, #endif .arch = MODULE_ARCH_INIT, };
struct module
structure defined in include/linux/module.h
carries an unpleasant surprise: struct module { (...) #ifdef CONFIG_UNUSED_SYMBOLS (...) #endif (...) /* Startup function. */ int (*init)(void); (...) #ifdef CONFIG_GENERIC_BUG (...) #endif #ifdef CONFIG_KALLSYMS (...) #endif (...) (... plenty more ifdefs ...) #ifdef CONFIG_MODULE_UNLOAD (...) /* Destruction function. */ void (*exit)(void); (...) #endif (...) }
init
pointer to be in the right place, CONFIG_UNUSED_SYMBOLS
must be defined in accordance with what our kernel image uses. So what about the exit pointer, is CONFIG_GENERIC_BUG
, CONFIG_KALLSYMS
, CONFIG_SMP
, CONFIG_TRACEPOINTS
, CONFIG_JUMP_LABEL
, CONFIG_TRACING
, CONFIG_EVENT_TRACING
, CONFIG_FTRACE_MCOUNT_RECORD
, CONFIG_TRACEPOINTS
, CONFIG_JUMP_LABEL
, CONFIG_TRACING
, CONFIG_EVENT_TRACING
, CONFIG_FTRACE_MCOUNT_RECORD
static const struct modversion_info ____versions[] __used __attribute__((section("__versions"))) = { { 0xsomehex, "module_layout" }, { 0xsomehex, "__aeabi_unwind_cpp_pr0" }, { 0xsomehex, "printk" }, };
Module.symvers
file, which is generated in accordance with the header files.module_layout
, depends on what the struct module
looks like, that is, it depends on which configuration options mentioned earlier are enabled. The second, __aeabi_unwind_cpp_pr0
, is a function specific to ABI ARM, and the last is for our calls to the printk
function.printk
function, even in a compatible way, the modules that were built initially will not boot with the new kernel. hello: disagrees about version of symbol symbol_name
Module.symvers
file, which we don’t have. bool each_symbol_section(bool (*fn)(const struct symsearch *arr, struct module *owner, void *data), void *data) { struct module *mod; static const struct symsearch arr[] = { { __start___ksymtab, __stop___ksymtab, __start___kcrctab, NOT_GPL_ONLY, false }, { __start___ksymtab_gpl, __stop___ksymtab_gpl, __start___kcrctab_gpl, GPL_ONLY, false }, { __start___ksymtab_gpl_future, __stop___ksymtab_gpl_future, __start___kcrctab_gpl_future, WILL_BE_GPL_ONLY, false }, #ifdef CONFIG_UNUSED_SYMBOLS { __start___ksymtab_unused, __stop___ksymtab_unused, __start___kcrctab_unused, NOT_GPL_ONLY, true }, { __start___ksymtab_unused_gpl, __stop___ksymtab_unused_gpl, __start___kcrctab_unused_gpl, GPL_ONLY, true }, #endif }; if (each_symbol_in_section(arr, ARRAY_SIZE(arr), NULL, fn, data)) return true; (...)
struct symsearch { const struct kernel_symbol *start, *stop; const unsigned long *crcs; enum { NOT_GPL_ONLY, GPL_ONLY, WILL_BE_GPL_ONLY, } licence; bool unused; };
each_symbol_section
function is three (or five, when the CONFIG_UNUSED_SYMBOLS
config CONFIG_UNUSED_SYMBOLS
enabled) fields, each of which contains the beginning of the symbol table, its end, and two flags.integer
values from the definitions in each_symbol_section
, we can determine the location of the symbol tables and signatures, and recreate the Module.symvers file from the kernel binary.zImage
), so a simple search for a compressed image is impossible. A compressed core actually represents a small binary, followed by a compressed stream. You can scan the zImage
file in order to find the compressed stream and get an unpacked image from it.dmesg
: $ adb shell dmesg | grep "\.init" <5>[01-01 00:00:00.000] [0: swapper] .init : 0xc0008000 - 0xc0037000 ( 188 kB)
0xc0008000
. $ python extract-symvers.py -B 0xc0008000 kernel-filename > Module.symvers
Module.symvers
file for the kernel from which we want to load the module, we can finally assemble the module (again, assuming arm-eabi-gcc
accessible from the PATH
, and that the terminal is open in the source directory): $ cp /path/to/Module.symvers build/ $ make M=/path/to/module/source ARCH=arm CROSS_COMPILE=arm-eabi- O=build modules
$ adb shell # insmod hello.ko # dmesg | grep insmod <6>[mm-dd hh:mm:ss.xxx] [id: insmod]Hello world # lsmod hello 586 0 - Live 0xbf008000 (P) # rmmod hello # dmesg | grep rmmod <6>[mm-dd hh:mm:ss.xxx] [id: rmmod]Goodbye world
Source: https://habr.com/ru/post/331202/
All Articles