第一种方法
需要编译整个内核
参考文章:https://blukat.me/2017/12/cross-compile-arm-kernel-module/、
步骤如下:
下载arm交叉编译器:
linaro社区,老版本 :版本范围 4.9 ~ 7.5
arm官网,新版本 : 版本范围 8.2 ~10.3
下载对应版本的linux内核:https://mirrors.edge.kernel.org/pub/linux/kernel/
获取.config文件(optee场景下,编译一次后,在linux源码目录下有该文件)
编译linux内核
1 make ARCH=arm CROSS_COMPILE=<TOOLCHAIN_DIR>/bin /arm-linux-gnueabihf-
编译内核模块
第二种方法
使用原有的.config文件,无需编译整个内核
参考文章:https://huhaipeng.top/2019/02/01/linux内核模块的交叉编译和加载/
以 optee 3.15.0 qemu版本为例,它是arm架构的,ree侧运行linux kernel。我希望在本地x86 linux上编译一个ko,且该ko能在该qemu arm linux中insmod并运行。(optee搭建可以参考我的另一篇文章 - 基于qemu的optee模拟环境搭建 )
这涉及到交叉编译,步骤比较复杂,且暂未明白每一步骤的具体含义,因此详细记录一下我的操作过程。
环境准备
我的目标是编译一个arm版的linux内核模块,那么肯定离不开两个东西:
(1)linux内核源码
(2)交叉编译器
下载这两个文件(注意一定要跟目标系统的版本匹配哦):
1 2 3 4 5 cd /home/bling/Downloads/git clone -b optee-3.15.0 --depth=1 https://github.com/linaro-swg/linux.git wget https://developer.arm.com/-/media/Files/downloads/gnu-a/10.2-2020.11/binrel/gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf.tar.xz
重点来了,需要编译optee时linux目录下生成的.config文件,将其拷贝到当前linux目录下。然后再继续后面的步骤。
在源码目录下依次执行如下3条命令:
1 2 3 4 5 6 7 make ARCH=arm CROSS_COMPILE=/home/bling/Downloads/gcc-arm-aarch32/bin/arm-none-linux-gnueabihf- menuconfig make ARCH=arm CROSS_COMPILE=/home/bling/Downloads/gcc-arm-aarch32/bin/arm-none-linux-gnueabihf- prepare make ARCH=arm CROSS_COMPILE=/home/bling/Downloads/gcc-arm-aarch32/bin/arm-none-linux-gnueabihf- scripts
以上,便会生成我们编译ko时所依赖的各种文件。
所以接下来,我们编写ko源码及Makefile文件。
ko源码及Makefile
ko源码 - exp.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 struct smc_calls_result { unsigned long arg0; unsigned long arg1; unsigned long arg2; unsigned long arg3; }; static int __init init_function(void) { union{ struct arm_smccc_res smccc; struct smc_calls_result result; } res; printk("hello! a test ko!\\n" ); unsigned long a0 = 0xB2000016; unsigned long a1 = 0x0; unsigned long a2 = 0x1; unsigned long a3 = 0x2; arm_smccc_smc(a0, a1, a2, a3, 0, 0, 0, 0, &res.smccc); printk("hello! end\\n" ); return 0; } static void __exit exit_function(void) { printk("bye bye~\\n" ); } module_init(init_function); module_exit(exit_function); MODULE_LICENSE("GPL" ); MODULE_AUTHOR("bling" ); MODULE_DESCRIPTION("testdriver" );
Makefile:
KDIR指定linux源码目录
1 2 3 4 5 6 7 KDIR := /home/bling/Downloads/linux obj-m += exp.o all: make -C $(KDIR) M=$(shell pwd ) modules clean: make -C $(KDIR) M=$(shell pwd ) clean
编译命令:
1 make ARCH=arm CROSS_COMPILE=/home/bling/Downloads/gcc-arm-aarch32/bin/arm-none-linux-gnueabihf-
最后,将生成的exp.ko传到qemu内,可执行成功!
思考
换成其他交叉编译器呢?
比如linaro的:https://releases.linaro.org/components/toolchain/binaries/7.5-2019.12/arm-linux-gnueabihf/
实验证明,更换编译器后也能编译成功。所以重点在于源码版本
和.config文件
。
编译内核源码目录和编译ko使用不同的交叉编译器呢?
不行。实验证明会报如下错误:
1 2 3 4 5 6 7 8 9 10 11 12 $ make ARCH=arm CROSS_COMPILE=/home/bling/Downloads/gcc-arm-aarch32/bin/arm-none-linux-gnueabihf- make -C /home/bling/Downloads/linux M=/home/bling/optee_v7/kotest modules make[1]: Entering directory '/home/bling/Downloads/linux' CC [M] /home/bling/optee_v7/kotest/exp.o cc1: error: cannot load plugin ./scripts/gcc-plugins/arm_ssp_per_task_plugin.so: ./scripts/gcc-plugins/arm_ssp_per_task_plugin.so: undefined symbol: _Z14rtx_alloc_stat8rtx_code scripts/Makefile.build:271: recipe for target '/home/bling/optee_v7/kotest/exp.o' failed make[2]: *** [/home/bling/optee_v7/kotest/exp.o] Error 1 Makefile:1851: recipe for target '/home/bling/optee_v7/kotest' failed make[1]: *** [/home/bling/optee_v7/kotest] Error 2 make[1]: Leaving directory '/home/bling/Downloads/linux' Makefile:5: recipe for target 'all' failed make: *** [all] Error 2
所以,必须保证编译内核源码和编译ko时使用同一个版本交叉编译器。具体原因等以后学内核的时候再深究。
ref
如何为嵌入式开发建立交叉编译环境