linux编译.o文件,使用-O0编译Linux内核

文章目录

1. 编译内核

1.1. 修改gcc优化等级

1.2. 防止`modpost: Section mismatches detected.`错误

1.3. 根据需要编译内核

1.4. 修改子目录Makefile

1.5. 重新执行编译

2. 参考资料

1. 编译内核

进入kernel 源码目录

1.1. 修改gcc优化等级

diff --git a/Makefile b/Makefile

index d4d36c619..1047c83c6 100644

--- a/Makefile

+++ b/Makefile

@@ -701,11 +701,11 @@ KBUILD_CFLAGS += $(call cc-disable-warning, format-overflow)

KBUILD_CFLAGS += $(call cc-disable-warning, address-of-packed-member)

ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE

-KBUILD_CFLAGS += -O2

+KBUILD_CFLAGS += -O0

else ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3

-KBUILD_CFLAGS += -O3

+KBUILD_CFLAGS += -O0

else ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE

-KBUILD_CFLAGS += -Os

+KBUILD_CFLAGS += -O0

endif

ifdef CONFIG_CC_DISABLE_WARN_MAYBE_UNINITIALIZED

1.2. 防止modpost: Section mismatches detected.错误

如果此时直接执行make进行编译,会出现modpost: Section mismatches detected.错误。

解决方法是修改scripts/mod/modpost.c。

diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c

index d2a30a7b3..58e2237c2 100644

--- a/scripts/mod/modpost.c

+++ b/scripts/mod/modpost.c

@@ -2670,7 +2670,7 @@ int main(int argc, char **argv)

if (dump_write)

write_dump(dump_write);

- if (sec_mismatch_count && sec_mismatch_fatal)

+ if (0 && sec_mismatch_count && sec_mismatch_fatal)

fatal("modpost: Section mismatches detected.\n"

"Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n");

for (n = 0; n < SYMBOL_HASH_SIZE; n++) {

1.3. 根据需要编译内核

make tinyconfig ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- 2>&1 | tee -a build.log

make vmlinux -j4 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- 2>&1 | tee -a build_error.log

此时编译失败,原因是部分函数未定义,具体原因可以参考宋宝华: 关于Linux编译优化几个必须掌握的姿势

MODINFO modules.builtin.modinfo

LD vmlinux

mm/page-writeback.o: In function `page_index':

page-writeback.c:(.text+0x21a4): undefined reference to `__page_file_index'

page-writeback.c:(.text+0x21a4): relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol `__page_file_index'

mm/truncate.o: In function `truncate_exceptional_pvec_entries':

truncate.c:(.text+0x199c): undefined reference to `dax_delete_mapping_entry'

truncate.c:(.text+0x199c): relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol `dax_delete_mapping_entry'

......

mm/rmap.o: In function `linear_page_index':

rmap.c:(.text+0x3110): undefined reference to `linear_hugepage_index'

Makefile:1077: recipe for target 'vmlinux' failed

make: *** [vmlinux] Error 1

1.4. 修改子目录Makefile

修改方法就是单独为提示存在未定义符号的文件修改gcc优化等级。方法是在Makefile中添加CFLAGS_file.o += -O。

拷贝如下内容新建脚本enbale_O0.sh,使用enabel_O0.sh和上述编译失败的build_error.log文件,执行./enable_O0.sh build_error.log。

#!/bin/bash

# make clean -j16

# make all -j4 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- 2>&1 |tee -a build_error.log

MAKE_LOG=""

BUILD_PATH="$(pwd -P)"

if [ $# -ge 1 ]; then

MAKE_LOG=$1

else

echo "Usage: $(basename $0) build_error.log [build_path]"

exit -1

fi

if [ $# -ge 2 ]; then

if [ -d $2 ]; then

BUILD_PATH=$2

BUILD_PATH=${BUILD_PATH%*/}

else

echo "$2 No such directory"

exit -1

fi

fi

if [ ! -f ${MAKE_LOG} ]; then

echo "${MAKE_LOG}: No such file"

exit -1

fi

add_cflag()

{

make_file=$1

obj_file=$2

if [ -e ${make_file} ]; then

line_no=$(grep -snv '^#' ${make_file}\

| cut -d : -f 1 | head -1)

str_cflags="CFLAGS_${obj_file}"

if [[ "" == "$(grep ${str_cflags}.*O ${make_file})" ]]; then

cmd="${line_no}i\\${str_cflags} += -O"

sed -i "${cmd}" ${make_file}

echo "${make_file}: add ${str_cflags}"

fi

fi

}

vmlinux_add_cflag()

{

log_file=$1

filelist=$(grep -shw -B1 'undefined reference' ${log_file}\

| grep 'In function' | cut -d : -f 1 | sort -u)

for f in ${filelist}

do

path=$(dirname ${f})

obj_file=$(basename ${f})

make_file=${path}/Makefile

add_cflag ${make_file} ${obj_file}

done

}

process_one()

{

# ERROR: "alloc_test_extent_buffer" [fs/btrfs/btrfs.ko] undefined!

str=$1

symbol=$(echo ${str} | awk '{print $2}')

symbol=${symbol:1:0-1}# 删除 ""

ko=$(echo ${str} | awk '{print $3}')

ko=${ko:1:0-1}# 删除 []

path=$(dirname ${ko})

filelist=$(grep -rl ${symbol} ${BUILD_PATH}/${path}/*.o)

echo $filelist

make_file=${path}/Makefile

for f in ${filelist}

do

f=${f#${BUILD_PATH}/}# 从左边删除 "${BUILD_PATH}/"

obj=$(basename ${f})

add_cflag ${make_file} ${obj}

done

}

module_add_cflag()

{

log_file=$1

IFS=$'\n'# 按行遍历

str_list=$(grep -sh "^ERROR:.*undefined!" ${log_file} | sort -u)

for str in ${str_list}

do

process_one ${str}

done

}

vmlinux_add_cflag ${MAKE_LOG}

module_add_cflag ${MAKE_LOG}

执行结束后,子目录Makefile改动如下:

diff --git a/mm/Makefile b/mm/Makefile

index d99684669..52a1962ea 100644

--- a/mm/Makefile

+++ b/mm/Makefile

@@ -2,6 +2,14 @@

#

# Makefile for the linux memory manager.

#

+CFLAGS_truncate.o += -O

+CFLAGS_rmap.o += -O

+CFLAGS_page-writeback.o += -O

+CFLAGS_mremap.o += -O

+CFLAGS_mprotect.o += -O

+CFLAGS_mincore.o += -O

+CFLAGS_memory.o += -O

+CFLAGS_gup.o += -O

KASAN_SANITIZE_slab_common.o := n

KASAN_SANITIZE_slab.o := n

1.5. 重新执行编译

make clean

make vmlinux -j4 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- 2>&1 | tee -a build_ok.log

此时可正常编译通过。

MODINFO modules.builtin.modinfo

LD vmlinux

SORTEX vmlinux

SYSMAP System.map

2. 参考资料

宋宝华: 关于Linux编译优化几个必须掌握的姿势

runninglinuxkernel_4