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-run
在 scripts/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
注意:objcopy
和 ld
引數值的不同(elf32-86-64
和 elf32_86_64
)。
解決方法
假如檢視到的工具鏈不支援需要的目標,只需升級工具鏈再重新編譯核心即可。
小結
64 位處理器執行原生 32 位程式,需要開啟核心
CONFIG_X86_X32
選項。CONFIG_X86_X32
選項需要工具鏈支援編譯elf32_x86_64
目標。objcopy --help
和ld -V
可檢視兩個命令支援的目標格式。
以上。