使用-O0編譯Linux內核

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. 參考資料

  1. 宋寶華: 關於Linux編譯優化幾個必須掌握的姿勢
  2. runninglinuxkernel_4
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章