由于工作需要更新Linux kernel版本到5.16以后,查了一下当前Ubuntu 18.04只支持到5.4,自己下kernel代码来编译的话可能会有些现有驱动不兼容。
为了图方便,决定直接把Ubuntu升级到22.04.2,这样Linux kernel版本就直接到5.19了;
具体Ubuntu各个发行版本对应的Linux kernel支持情况,详见官网介绍或者Livepatch文档
但是,在将基础编译环境配置好后,同样的代码在22.04上遇到了几个报错,并且全网搜索结果不太好找到好的解决办法,遂整理如下:
报错信息:
flex-2.5.39: loadlocale.c:130: _nl_intern_locale_data: Assertion `cnt < (sizeof (_nl_value_type_LC_TIME) / sizeof (_nl_value_type_LC_TIME[0]))' failed.
Aborted (core dumped)
解决方法:
使用源码重新编译一个flex替换掉:
# 进入flex目录
cd prebuilts/misc/linux-x86/flex/
# 解压源码,注意这里一定要建一个目录,否则解压出来的目录名会覆盖掉flex-2.5.39这个二进制文件(同名),不利于后面做替换
mkdir flex-2.5.39_src
tar xzvf flex-2.5.39.tar.gz -C ./flex-2.5.39_src
cd flex-2.5.39_src/flex-2.5.39/
# 默认配置方式编译
./configure && make
# 替换掉源码中的二进制
mv flex ../../flex-2.5.39
# 返回flex目录,清理解压出来的目录,同时清除编译中间文件
cd ../../
git clean -fd -- ./
# 回到Android编译根目录
cd ../../../../
报错信息:
patchoatd E 06-21 15:22:26 844380 844380 image_space.cc:1761] Could not create image space with image file 'out/target/product/blueline/dex_bootjars/system/framework/boot.art'. Attempting to fall back to imageless running. Error was: Failed to mmap at expected address, mapped at 0x7fe5d0000000 instead of 0x705db000
patchoatd E 06-21 15:22:26 844380 844380 image_space.cc:1761] Attempted image: out/target/product/blueline/dex_bootjars/system/framework/boot-framework.art
patchoatd E 06-21 15:22:26 844380 844380 runtime.cc:1290] Dex file fallback disabled, cannot continue without image.
patchoatd E 06-21 15:22:26 844380 844380 patchoat.cc:485] Unable to initialize runtime
ninja: build stopped: subcommand failed.
问题原因:
报错指出,mmap系统调用返回的内存起始地址与传下去的建议地址值不一致。
实际上,这个建议值在Linux kernel 5.18(Host端,即PC或工作站端)及其以后,基本是被无视掉了,导致每次创建的内存地址值,跟建议值都不一样,从而报错,而在Linux kernel 5.17及其以前的版本,建议值通常都会被接受,并按照该地址申请内存;
解决方式:
mmap系统调用时,flag添加MAP_FIXED_NOREPLACE
标志位;
代码片段:
//art/runtime/mem_map.cc
MemMap* MemMap::MapFileAtAddress(uint8_t* expected_ptr,
size_t byte_count,
int prot,
int flags,
int fd,
off_t start,
bool low_4gb,
bool reuse,
const char* filename,
std::string* error_msg) {
...
if (reuse) {
// reuse means it is okay that it overlaps an existing page mapping.
// Only use this if you actually made the page reservation yourself.
CHECK(expected_ptr != nullptr);
DCHECK(error_msg != nullptr);
DCHECK(ContainedWithinExistingMap(expected_ptr, byte_count, error_msg))
<< ((error_msg != nullptr) ? *error_msg : std::string());
flags |= MAP_FIXED;
//Add begin @{
#if !defined(ART_TARGET)
} else if (expected_ptr) {
#define MAP_FIXED_NOREPLACE 0x100000
flags |= MAP_FIXED_NOREPLACE;
#endif
//@}
} else {
...
}
...
}
参考资料:这里的问题讨论和这里的修改方法
报错信息:
/usr/bin/ld: scripts/dtc/dtc-parser.tab.o:(.bss+0x10): multiple definition of `yylloc'; scripts/dtc/dtc-lexer.lex.o:(.bss+0x0): first defined here
这个应该是编译环境版本变化导致的,从日志可以知道,编译scripts/dtc/dtc-parser.tab.o
时,发现yylloc
已经在scripts/dtc/dtc-lexer.lex.o
中定义过了,因此报了重复定义的错误;
解决思路应该就是在scripts/dtc/dtc-parser.tab.o
去掉yylloc
的定义;
代码片段:
//${kernel_src_top}/scripts/dtc/dtc-parser.tab.c_shipped
/* The semantic value of the lookahead symbol. */
YYSTYPE yylval;
/* Location data for the lookahead symbol. */
//Removed begin @{
//YYLTYPE yylloc
//@}
# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
= { 1, 1, 1, 1 }
# endif
在解决完了上面yylloc
重复定义的问题后,再次编译kernel,会出现如下报错:
报错信息:
Building kernel
make: Entering directory '/home/ryan/projects/zsui-aosp-p-dev/out/target/product/blueline/obj/KERNEL_OBJ'
...
VDSOC32 arch/arm64/kernel/vdso32/vgettimeofday.o
VDSOA32 arch/arm64/kernel/vdso32/sigreturn.o
/..//bin/as: unrecognized option '-mfloat-abi=soft'
clang-5.0: error: assembler command failed with exit code 1 (use -v to see invocation)
make[3]: *** [/home/ryan/projects/zsui-aosp-p-dev/kernel/private/msm-google/arch/arm64/kernel/vdso32/Makefile:144: arch/arm64/kernel/vdso32/sigreturn.o] Error 1
make[3]: *** Waiting for unfinished jobs....
/..//bin/as: unrecognized option '-mfloat-abi=soft'
clang-5.0: error: assembler command failed with exit code 1 (use -v to see invocation)
make[3]: *** [/home/ryan/projects/zsui-aosp-p-dev/kernel/private/msm-google/arch/arm64/kernel/vdso32/Makefile:142: arch/arm64/kernel/vdso32/vgettimeofday.o] Error 1
make[2]: *** [arch/arm64/Makefile:242: vdso_prepare] Error 2
make[1]: *** [Makefile:152: sub-make] Error 2
make: *** [Makefile:24: __sub-make] Error 2
make: Leaving directory '/home/ryan/projects/zsui-aosp-p-dev/out/target/product/blueline/obj/KERNEL_OBJ'
ninja: build stopped: subcommand failed.
问题原因:
vdso32
这个目标需要使用gcc
交叉编译,并且是使用32位的编译工具链,但是当前Android kernel编译规则并未指定工具链的路径,导致在Ubuntu 22.04上无法找到正确的as二进制执行文件进行汇编;
解决方法:
gcc编译32位目标时,添加–prefix与–gcc-toolchain两个参数指定,这样会找到正确的as二进制执行文件进行汇编;
代码片段:总共需要修改两个文件
//${kernel_src_top}/arch/arm64/Makefile
...
else ifeq ($(cc-name),clang)
export CLANG_TRIPLE_ARM32 ?= $(CROSS_COMPILE_ARM32)
export CLANG_TARGET_ARM32 := --target=$(notdir $(CLANG_TRIPLE_ARM32:%-=%))
# Added @{
export GCC_TOOLCHAIN32_DIR := $(dir $(shell which $(CROSS_COMPILE_ARM32)ld))
export GCC_TOOLCHAIN32 := $(realpath $(GCC_TOOLCHAIN32_DIR)/..)
export CLANG_PREFIX32 := --prefix=$(GCC_TOOLCHAIN32_DIR)
export CLANG_GCC32_TC := --gcc-toolchain=$(GCC_TOOLCHAIN32)
# @}
export CONFIG_VDSO32 := y
vdso32 := -DCONFIG_VDSO32=1
else ifeq ($(shell which $(CROSS_COMPILE_ARM32)$(cc-name) 2> /dev/null),)
...
//${kernel_src_top}/arch/arm64/kernel/vdso32/Makefile
...
ifeq ($(cc-name),clang)
# Modified @{
# Original code:
# CC_ARM32 := $(CC) $(CLANG_TARGET_ARM32) -no-integrated-as
CC_ARM32 := $(CC) $(CLANG_TARGET_ARM32) -no-integrated-as $(CLANG_GCC32_TC) $(CLANG_PREFIX32)
# @}
else
CC_ARM32 := $(CROSS_COMPILE_ARM32)$(cc-name)
endif
...
参考资料:参考这笔提交