android - 为Android编译外部模块

标签 android linux

我正在尝试将驱动程序编译为可加载模块,但每当我将 adb shell 放入手机并执行 insmod test.ko 时,我都会收到错误消息 insmod: 无法加载/data/local/tmp/test.ko: 执行格式错误。 Grep'ing dmesg 我找到以下日志:test: no symbol version for module_layout

我用谷歌搜索了很多 [Ref] [Ref] [Ref] [Ref] [Ref]并阅读 linux kbuild 文档 txt 文件 [Ref] [Ref]无济于事,所以如果有人知道答案,那就太好了 :)(我只引用了我找到的最有用的链接)。

到目前为止我所做的是:

我有一个 Qualcomm Aurora checkout 并在内核目录中键入以下内容

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 文件。

我不明白的是消息错误:内核配置无效。它所讨论的文件存在,所以我知道它们是在我的内核构建中创建的。

无论如何,尝试将它insmod 到手机上会给出我之前提到的消息。如果我 cat 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 构建过程 envsetup.sh ,正在运行 lunch然后构建内核:

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

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

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

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

make all输出仍将位于您的模块目录中(而不是 Android 输出目录)。

这与所有与纯 Linux 构建相关的示例基本相同。我需要提供的唯一额外信息是 Android 构建系统输出其构建文件的位置,即 O=$(MY_ANDROID_ROOT_DIR)/out/target/product/<your-product>/obj/KERNEL_OBJ .

O= define 告诉 Make 在哪里可以找到内核构建的输出。

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

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

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

PS 如果你的模块包含多个文件定义obj-m += my_driver.o然后 my_driver-m:= <extra objects> .

关于android - 为Android编译外部模块,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44385550/

相关文章:

android - 你的 CPU 不支持 VT-x

android - 机器人安装

java - Java、Android 中的 Skype API 或 Google Talk/语音

linux - ioctl()如何调用驱动程序代码

python - 如何启动一个进程并将其置于 python 后台?

mysql - .mysql_history 没有被自动保存

android - 暂停后 MediaPlayer 完成

Android Studio - 在模拟器上运行签名的 apk

linux - Shell:如何为一个正在执行的命令设置工作目录而不影响一行中的其他命令

java - putty中通过java执行jar文件