CONFIG_X86_X32 enabled but no binutils support

問題現象

最近在交叉編譯 X86-64 平臺的 Linux 內核時,出現如下編譯警告:

CONFIG_X86_X32 enabled but no binutils support

查看 .config 文件確實打開了 CONFIG_X86_X32:

CONFIG_X86_X32=y

arch/x86/Kconfig 中找到對 CONFIG_X86_X32 的說明:

config X86_X32
    bool "x32 ABI for 64-bit mode"
    depends on X86_64
    ---help---
      Include code to run binaries for the x32 native 32-bit ABI      for 64-bit processors.  An x32 process gets access to the
      full 64-bit register file and wide data path while leaving
      pointers at 32 bits for smaller memory footprint.

      You will need a recent binutils (2.22 or later) with
      elf32_x86_64 support enabled to compile a kernel with this
      option set.

由上述說明可知,CONFIG_X86_X32 選項用於在 64 位處理器上運行原生 32 位程序,需要 binutils 2.22 或更高版本(帶 elf32_x86_64 支持)。

源碼分析

在內核源碼中搜索上述警告,定位到 arch/x86/Makefile

ifdef CONFIG_X86_X32
    x32_ld_ok := $(call try-run,\
            /bin/echo -e '1: .quad 1b' | \            $(CC) $(KBUILD_AFLAGS) -c -x assembler -o "$$TMP" - && \            $(OBJCOPY) -O elf32-x86-64 "$$TMP" "$$TMPO" && \            $(LD) -m elf32_x86_64 "$$TMPO" -o "$$TMP",y,n)
        ifeq ($(x32_ld_ok),y)
                CONFIG_X86_X32_ABI := y
                KBUILD_AFLAGS += -DCONFIG_X86_X32_ABI
                KBUILD_CFLAGS += -DCONFIG_X86_X32_ABI        else
                $(warning CONFIG_X86_X32 enabled but no binutils support)
        endifendif

此段代碼即是根據 try-run 的運行結果確定工具鏈是否支持 elf32_x86_64,如果支持則定義 CONFIG_X86_X32_ABI,否則輸出前述編譯警告。

try-runscripts/Kbuild.include 中定義:

# output directory for tests belowTMPOUT := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/)# try-run# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)# Exit code chooses option. "$$TMP" serves as a temporary file and is# automatically cleaned up.try-run = $(shell set -e;       \
    TMP="$(TMPOUT).$$$$.tmp";   \
    TMPO="$(TMPOUT).$$$$.o";    \    if ($(1)) >/dev/null 2>&1;  \
    then echo "$(2)";       \    else echo "$(3)";       \
    fi;             \
    rm -f "$$TMP" "$$TMPO")

其作用是執行第一個入參指定的命令,如果成功則輸出第二個入參,失敗則輸出第三個入參,最後刪除臨時目錄下的兩個臨時文件。

結合 arch/x86/Makefile 的使用情況,完成如下三個操作:

  • 將一行彙編語句使用 gcc 編譯成 .$$$$.tmp

  • 使用 objcopy.$$$$.tmp 轉換爲 elf32-x86-64 格式的 .$$$$.o

  • 最後使用 ld.$$$$.o 鏈接爲 elf32_x86_64 目標的 .$$$$.tmp(複用此文件名)。

假如三個操作都沒有錯誤發生,表明目標工具鏈支持 x32 ABI 對應的選項,則 x32_ld_ok 變量賦值爲 y,否則賦值爲 n

其中要編譯的彙編語句僅有一行,作用是定義一個值爲 1 的 64 比特數值,僅用於後續的選項測試,沒有實際功能:

1: .quad 1b

查看工具鏈支持的編譯目標

objcopy --help 的最後可查看其支持的目標,其中包括 elf32-86-64,各個目標可作爲 -O 參數傳入:

objcopy: supported targets: elf64-x86-64 elf32-i386 elf32-iamcu elf32-x86-64 pei-i386 pei-x86-64 elf64-l1om elf64-k1om elf64-little elf64-big elf32-little elf32-big pe-x86-64 pe-bigobj-x86-64 pe-i386 plugin srec symbolsrec verilog tekhex binary ihex

ld -V 可查看其支持的目標,其中包括 elf32_86_64,各個目標可作爲 -m 參數傳入:

# ld -VGNU ld (GNU Binutils for Ubuntu) 2.31.1
  Supported emulations:
   elf_x86_64
   elf32_x86_64
   elf_i386
   elf_iamcu
   elf_l1om
   elf_k1om
   i386pep
   i386pe

注意:objcopyld 參數值的不同(elf32-86-64elf32_86_64)。

解決方法

假如查看到的工具鏈不支持需要的目標,只需升級工具鏈再重新編譯內核即可。

小結

  • 64 位處理器運行原生 32 位程序,需要打開內核 CONFIG_X86_X32 選項。

  • CONFIG_X86_X32 選項需要工具鏈支持編譯 elf32_x86_64 目標。

  • objcopy --helpld -V 可查看兩個命令支持的目標格式。

以上。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章