为Android编译外部模块

时间:2017-06-06 08:54:07

标签: android linux

我正在尝试将驱动程序编译为可加载模块,但每当我adb shell进入我的手机并执行insmod test.ko时,我都会收到错误消息insmod: failed to load /data/local/tmp/test.ko: Exec format error。 Grep&#d; dmesg我找到以下日志:test: no symbol version for module_layout

我已经完成了相当多的谷歌搜索[Ref] [Ref] [Ref] [Ref] [Ref]并阅读了linux kbuild文档txt文件{{3 }} [Ref]无济于事,所以如果有人知道答案,那就是制作:)(我只引用了我发现的最有用的链接)。

到目前为止,我所做的是:

我有一个Qualcomm Aurora结账,在内核目录中输入以下内容

cp arch/arm64/configs/gemini_user_defconfig .config [B]# Has CONFIG_MODVERSIONS enabled and MODULE_SIG*=n[/B]
yes "" | make oldconfig ARCH=arm64 CROSS_COMPILE=aarch64-linux-android- V=1
make prepare ARCH=arm64 CROSS_COMPILE=aarch64-linux-android- V=1
make scripts ARCH=arm64 CROSS_COMPILE=aarch64-linux-android- V=1
make modules ARCH=arm64 CROSS_COMPILE=aarch64-linux-android- V=1

我将PATH设置为指向/MyAOSBDir/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin,因此我选择了正确的工具链。

此时似乎很好。在我的内核目录中,我有Module.symvers,所以我似乎已经设置了。

现在到我在这个构建树之外设置的目录中进行虚拟测试...... Makefile看起来像这样:

KERNEL_DIR:=/solomon-build/MiNote2AOSB/kernel/
obj-m += test.o
PWD := $(shell pwd)

.PHONY: all
all:
        $(MAKE) M=$(PWD) ARCH=arm64 CROSS_COMPILE=aarch64-linux-android- -C $(KERNEL_DIR) modules V=1
clean:
        $(MAKE) M=$(PWD) -C $(KERNEL_DIR) clean

司机只是一个假人:

#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);

我在评论专栏做make all并获得此输出:

make M=/solomon-build/build_mxt_kmod ARCH=arm64 CROSS_COMPILE=aarch64-linux-android- -C /solomon-build/MiNote2AOSB/kernel/ modules V=1
make[1]: Entering directory `/solomon-build/MiNote2AOSB/kernel'
test -e include/generated/autoconf.h -a -e include/config/auto.conf || (                \
        echo >&2;                                                       \
        echo >&2 "  ERROR: Kernel configuration is invalid.";           \
        echo >&2 "         include/generated/autoconf.h or include/config/auto.conf are missing.";\
        echo >&2 "         Run 'make oldconfig && make prepare' on kernel src to fix it.";      \
        echo >&2 ;                                                      \
        /bin/false)
mkdir -p /solomon-build/build_mxt_kmod/.tmp_versions ; rm -f /solomon-build/build_mxt_kmod/.tmp_versions/*
make -f ./scripts/Makefile.build obj=/solomon-build/build_mxt_kmod
  ./scripts/gcc-wrapper.py aarch64-linux-android-gcc -Wp,-MD,/solomon-build/build_mxt_kmod/.test.o.d  -nostdinc -isystem /solomon-build/MiNote2AOSB/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/../lib/gcc/aarch64-linux-android/4.9.x-google/include -I./arch/arm64/include -Iarch/arm64/include/generated  -Iinclude -I./arch/arm64/include/uapi -Iarch/arm64/include/generated/uapi -I./include/uapi -Iinclude/generated/uapi -include ./include/linux/kconfig.h -D__KERNEL__ -mlittle-endian -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Werror-implicit-function-declaration -Wno-format-security -std=gnu89 -mgeneral-regs-only -fno-pic -fno-delete-null-pointer-checks -Os -Wno-maybe-uninitialized --param=allow-store-data-races=0 -Wframe-larger-than=2048 -fstack-protector -Wno-unused-but-set-variable -fno-omit-frame-pointer -fno-optimize-sibling-calls -fno-var-tracking-assignments -g -Wdeclaration-after-statement -Wno-pointer-sign -fno-strict-overflow -fconserve-stack -Werror=implicit-int -Werror=strict-prototypes -Werror=date-time  -DMODULE  -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(test)"  -D"KBUILD_MODNAME=KBUILD_STR(test)" -c -o /solomon-build/build_mxt_kmod/.tmp_test.o /solomon-build/build_mxt_kmod/test.c
(cat /dev/null;   echo kernel//solomon-build/build_mxt_kmod/test.ko;) > /solomon-build/build_mxt_kmod/modules.order
make -f ./scripts/Makefile.modpost
  find /solomon-build/build_mxt_kmod/.tmp_versions -name '*.mod' | xargs -r grep -h '\.ko$' | sort -u | sed 's/\.ko$/.o/' | scripts/mod/modpost -m  -i ./Module.symvers -I /solomon-build/build_mxt_kmod/Module.symvers  -o /solomon-build/build_mxt_kmod/Module.symvers -S -E -w  -s -T -
  ./scripts/gcc-wrapper.py aarch64-linux-android-gcc -Wp,-MD,/solomon-build/build_mxt_kmod/.test.mod.o.d  -nostdinc -isystem /solomon-build/MiNote2AOSB/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/../lib/gcc/aarch64-linux-android/4.9.x-google/include -I./arch/arm64/include -Iarch/arm64/include/generated  -Iinclude -I./arch/arm64/include/uapi -Iarch/arm64/include/generated/uapi -I./include/uapi -Iinclude/generated/uapi -include ./include/linux/kconfig.h -D__KERNEL__ -mlittle-endian -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Werror-implicit-function-declaration -Wno-format-security -std=gnu89 -mgeneral-regs-only -fno-pic -fno-delete-null-pointer-checks -Os -Wno-maybe-uninitialized --param=allow-store-data-races=0 -Wframe-larger-than=2048 -fstack-protector -Wno-unused-but-set-variable -fno-omit-frame-pointer -fno-optimize-sibling-calls -fno-var-tracking-assignments -g -Wdeclaration-after-statement -Wno-pointer-sign -fno-strict-overflow -fconserve-stack -Werror=implicit-int -Werror=strict-prototypes -Werror=date-time  -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(test.mod)"  -D"KBUILD_MODNAME=KBUILD_STR(test)" -DMODULE  -c -o /solomon-build/build_mxt_kmod/test.mod.o /solomon-build/build_mxt_kmod/test.mod.c
  aarch64-linux-android-ld -EL -r  -T ./scripts/module-common.lds --build-id   --fix-cortex-a53-843419 -o /solomon-build/build_mxt_kmod/test.ko /solomon-build/build_mxt_kmod/test.o /solomon-build/build_mxt_kmod/test.mod.o
make[1]: Leaving directory `/solomon-build/MiNote2AOSB/kernel'

所以,没有消息说缺少Module.symvers,所以这很好,我确实得到了一个内置的.ko文件。

我不明白的是消息ERROR: Kernel configuration is invalid。它所讨论的文件存在,所以我知道它们是在我的内核版本中创建的。

无论如何,尝试将insmod这个放到手机上会给出我之前提到的消息。如果我猫Module.symvers我看到了:

0xff924338      backlight_force_update  drivers/video/backlight/backlight       EXPORT_SYMBOL
0x30254daf      test_iosched_register   block/test-iosched      EXPORT_SYMBOL
<snip>
0xdd502540      backlight_device_unregister     drivers/video/backlight/backlight       EXPORT_SYMBOL
0x9939eba0      backlight_unregister_notifier   drivers/video/backlight/backlight       EXPORT_SYMBOL

因此文件中没有符号module_layout,因此没有CRC,我认为这是创建错误消息的?

非常感谢任何线索,谢谢。

哦,我还应该提一下模块和内核vermagic匹配:

# modinfo /data/local/tmp/test.ko
filename:       /data/local/tmp/test.ko
depends:
vermagic:       3.18.20-mytestkernel-perf-g671c431-dirty SMP preempt mod_unload modversions aarch64

# uname -a
Linux localhost 3.18.20-mytestkernel-perf-g671c431-dirty #1 SMP PREEMPT Mon Jun 5 15:46:13 BST 2017 aarch64

*编辑 - 找到解决方案 - 新问题* : 自发布以来,我进一步发展了很多。我意识到的是,使用Android构建系统的内核编译产生了与我上面的方法完全不同的Module.symvers一个(出于某种原因,它花了一些时间让便士丢弃并让我检查Andoird构建输出 - 呃!)。事实上,我已经意识到我总是拥有Module.symvers文件,它只是位于../out/target/product/msm8996/obj/KERNEL_OBJ/Module.symvers相对于内核目录的位置。将此文件复制到内核并重新运行我的模块构建现在会生成一个正确加载的模块:)

所以,我想问题就变成了,为什么两个文件不同?什么是Android做的不同?我假设它正在设置一些更详细的配置,但是如何/为什么/为什么?

1 个答案:

答案 0 :(得分:0)

所以,答案最终相对简单......

我只是使用正常的Android构建流程来源DesiredCapabilities desiredCapabilities = new DesiredCapabilities(); desiredCapabilities.setAcceptInsecureCerts(true); WebDriver driver = new FirefoxDriver(desiredCapabilities); ,运行envsetup.sh然后构建内核:

lunch

(请记住在.config文件中确保设置CONFIG_MODULES = y并将所有内核驱动程序设置为= m,如果您希望它们作为模块)。

在单独的目录中,不在Android构建树中,我现在有了我的新模块和下面的Makefile,现在看起来像这样:

. build/envsetup.sh
lunch msm8996-userdebug
make kernel -j16

MY_ANDROID_ROOT_DIR :=/path/to/my/android/checkout KERNEL_DIR:=$(MY_ANDROID_ROOT_DIR)/kernel obj-m += my_driver.o PWD := $(shell pwd) .PHONY: all all: $(MAKE) \ M=$(PWD) \ ARCH=arm64 \ CROSS_COMPILE=aarch64-linux-android- \ -C $(KERNEL_DIR) \ modules \ V=1 \ O=$(MY_ANDROID_ROOT_DIR)/out/target/product/msm8996/obj/KERNEL_OBJ clean: $(MAKE) M=$(PWD) -C $(KERNEL_DIR) clean 输出仍然在您的模块目录中(不是Android输出目录)。

这与所有与纯Linux版本相关的示例基本相同。我需要提供的唯一额外信息是Android构建系统输出其构建文件的位置,即 make all

O=$(MY_ANDROID_ROOT_DIR)/out/target/product/<your-product>/obj/KERNEL_OBJ定义告诉Make在哪里找到内核构建的输出。

'V = 1`定义告诉Make输出详细的构建信息。

O=是一个内核目标,它将构建Makefile变量modules中定义的模块。此变量“指定构建为可加载内核模块的目标文件”。

现在我的模块构建正常,我不需要担心独立编译内核或类似的东西来修复丢失的文件消息(虽然它仍然会输出autoconf.h,我不明白,因为它存在在我的树上,似乎并没有阻止我的模块工作)。

PS如果您的模块包含多个文件,请定义obj-m,然后obj-m += my_driver.o