使用-O0編譯Linux內核


轉載:https://blog.csdn.net/wuu1010/article/details/103285396

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
————————————————
版權聲明:本文為CSDN博主「wuu1010」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/wuu1010/java/article/details/103285396


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM