美文网首页
CONFIG_X86_X32 enabled but no bi

CONFIG_X86_X32 enabled but no bi

作者: yestyle | 来源:发表于2018-11-09 20:36 被阅读233次

    问题现象

    最近在交叉编译 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)
            endif
    endif
    

    此段代码即是根据 try-run 的运行结果确定工具链是否支持 elf32_x86_64,如果支持则定义 CONFIG_X86_X32_ABI,否则输出前述编译警告。

    try-runscripts/Kbuild.include 中定义:

    # output directory for tests below
    TMPOUT := $(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 -V
    GNU 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 可查看两个命令支持的目标格式。

    以上。

    相关文章

      网友评论

          本文标题:CONFIG_X86_X32 enabled but no bi

          本文链接:https://www.haomeiwen.com/subject/vkqaxqtx.html