DeepSeek辅助在64位Linux中编译运行32位的asm-xml-1.4程序

发布于:2025-09-07 ⋅ 阅读:(34) ⋅ 点赞:(0)

在网上搜快速xml解析器时找到一个2012年的asm-xml-1.4程序说是比expat快几倍,有点不信,想编译看看。

下载了源代码, 解压缩到/par,其中obj目录下有预编译好的.o文件。
然后运行如下命令编译示例,出错了

cd /par/asm-xml-1.4/examples
make -f unix.mak
gcc -O2 -fomit-frame-pointer -I ../include -c c/simple/simple.c -o simple.o
gcc -s simple.o ../obj/elf/asm-xml.o -o simple
/usr/bin/ld: i386 architecture of input file `../obj/elf/asm-xml.o' is incompatible with i386:x86-64 output

第一时间想到从网上下载一个64位的.o文件代替,还真找到一个,https://pkg.freebsd.org/FreeBSD:14:amd64/latest/All/asm-xml-1.4.pkg,从中解压出来libasm-xml.a,但其实它也是32位的。

gcc -s simple.o /par/libasm-xml.a -o simple
/usr/bin/ld: i386 architecture of input file `/par/libasm-xml.a(elf.So)' is incompatible with i386:x86-64 output

asm-xml作者讲到,它的源代码是用fasm汇编的,我就用它汇编了一个,结果也是32位的。问题依旧

./fasm elf.asm
flat assembler  version 1.73.32  (16384 kilobytes memory)
4 passes, 19364 bytes.
root@6ae32a5ffcde:/par# ls elf*
elf.asm  elf.o
root@6ae32a5ffcde:/par# cd /par/asm-xml-1.4
root@6ae32a5ffcde:/par/asm-xml-1.4# cd examples

root@6ae32a5ffcde:/par/asm-xml-1.4/examples# gcc -s simple.o /par/elf.o -o simple
/usr/bin/ld: i386 architecture of input file `/par/elf.o' is incompatible with i386:x86-64 output

没办法了,只好去问DeepSeek

请问在64位Linux上编译和运行32位Linux程序的步骤

他的答复是

好的,在 64 位 Linux 系统上编译和运行 32 位程序需要安装对应的 32 位库和工具链。以下是详细的步骤:

核心原理

64 位系统(通常被称为 x86_64amd64)默认不包含运行 32 位 x86i386/i686)程序所需的库和链接器。因此,你需要启用多架构支持并安装必要的 32 位开发库。


步骤 1:启用多架构支持并安装运行时库

首先,你需要让系统知道它需要处理 32 位的软件包。这通过 dpkg 的多架构支持实现(适用于基于 Debian/Ubuntu 的系统)。

  1. 启用多架构

    sudo dpkg --add-architecture i386
    sudo apt update
    
  2. 安装最重要的 32 位 C 运行时库
    这是运行绝大多数 32 位程序的最基本要求。

    sudo apt install libc6:i386
    
  3. (可选但推荐)安装常用的 32 位库
    很多程序会依赖这些库(如图形界面库 GTKSDL 等)。安装一个元数据包可以省去很多麻烦。

    sudo apt install gcc-multilib
    

    注意:在较旧的系统上,这个包可能叫 ia32-libs,但在新版本中已被 gcc-multilib 和多架构支持取代。


步骤 2:编译 32 位程序

你有两个主要场景:编译你自己的代码,或者编译第三方源代码。

场景 A:编译你自己的 C/C++ 代码

在编译时,你需要告诉编译器生成 32 位代码。

  • 使用 GCC 编译
    gccg++ 命令后加上 -m32 参数。
    gcc -m32 -o my_program_32 my_program.c
    
    • -m32: 指示编译器生成 32 位目标代码。
    • 如果链接时报告找不到 crt1.o 等文件,说明你的 32 位开发库没装全。请确保已执行 步骤 1
场景 B:编译第三方源代码(使用 Autotools)

如果项目使用 ./configure 脚本,你通常可以通过设置环境变量来指定目标架构。

# 设置编译标志
export CFLAGS="-m32"
export CXXFLAGS="-m32"
export LDFLAGS="-m32"

# 运行配置和编译
./configure --build=i686-pc-linux-gnu
make
  • --build=i686-pc-linux-gnu 明确告诉配置系统目标是 32 位系统。
场景 C:编译第三方源代码(使用 CMake)

你可以在调用 cmake 时指定工具链文件或参数。

  1. 创建一个工具链文件,例如 i686-linux-gnu.cmake

    set(CMAKE_SYSTEM_NAME Linux)
    set(CMAKE_SYSTEM_PROCESSOR i686)
    set(CMAKE_C_FLAGS -m32)
    set(CMAKE_CXX_FLAGS -m32)
    set(CMAKE_EXE_LINKER_FLAGS -m32)
    set(CMAKE_FIND_ROOT_PATH /usr/lib/i386-linux-gnu)
    set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
    set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
    set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
    
  2. 使用该工具链文件进行编译

    mkdir build32 && cd build32
    cmake -DCMAKE_TOOLCHAIN_FILE=../i686-linux-gnu.cmake ..
    make
    

步骤 3:运行 32 位程序

如果已经按照 步骤 1 安装了必要的 32 位运行时库(libc6:i386 等),运行 32 位程序就和运行普通程序一样:

./my_program_32

系统会自动识别它是 32 位 ELF 文件,并使用已安装的 32 位库来加载和执行它。


故障排除

  1. 错误:No such file or directory

    • 现象:明明文件存在,一运行却报这个错。
    • 原因:最常见的原因是你没有安装 32 位的 C 库 (libc6:i386)。
    • 解决:返回 步骤 1,执行 sudo apt install libc6:i386
  2. 错误:bash: ./program: Permission denied

    • 原因:文件没有执行权限。
    • 解决chmod +x ./program
  3. 错误:.so 库找不到(如 libSDL.so.1 not found

    • 原因:缺少某个特定的 32 位共享库。
    • 解决:使用 apt 搜索并安装对应的 32 位库。库名通常是 包名:i386
      # 例如,安装 32 位的 SDL1 库
      sudo apt install libsdl1.2-dev:i386
      # 或者只安装运行时库(如果不开发的话)
      sudo apt install libsdl1.2:i386
      
    • 可以使用 ldd 命令查看程序依赖哪些库以及哪些没找到:
      ldd ./my_program_32
      
  4. 编译错误:fatal error: bits/c++config.h: No such file or directory

    • 原因:缺少 32 位 C++ 开发库。
    • 解决:安装 g++-multilib
      sudo apt install g++-multilib
      

总结

步骤 操作 命令示例
1 启用多架构并安装基础库 sudo dpkg --add-architecture i386 && sudo apt update
sudo apt install libc6:i386 gcc-multilib
2 编译代码(加 -m32 标志) gcc -m32 -o hello32 hello.c
3 运行程序 ./hello32

对于基于 RHEL/CentOS/Fedora 的系统,概念类似,但命令不同:

  1. 安装支持:sudo dnf install glibc.i686 (基础库)
  2. 安装开发工具链:sudo dnf install glibc-devel.i686 libstdc++-devel.i686
  3. 编译时同样使用 gcc -m32

先测试一下-m32选项是否存在,结果不存在

root@6ae32a5ffcde:/par/asm-xml-1.4/examples# gcc -O2 -fomit-frame-pointer -I ../include -c c/simple/simple.c -o simple.o -m32
In file included from c/simple/simple.c:6:
/usr/include/stdio.h:27:10: fatal error: bits/libc-header-start.h: No such file or directory
   27 | #include <bits/libc-header-start.h>
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.

我就按照他说的第一步骤安装了

root@6ae32a5ffcde:/par/asm-xml-1.4/examples# dpkg --add-architecture i386
root@6ae32a5ffcde:/par/asm-xml-1.4/examples# apt install libc6:i386
root@6ae32a5ffcde:/par/asm-xml-1.4/examples# apt install gcc-multilib

但是用-m32选项编译一个最简单的程序

#include <stdio.h>
int main(){puts("Hello World!");}

仍然不行

root@6ae32a5ffcde:/par/asm-xml-1.4/examples# gcc /par/testc.c -o testc -m32
/usr/bin/ld: cannot find crt1.o: No such file or directory
/usr/bin/ld: cannot find crti.o: No such file or directory
/usr/bin/ld: skipping incompatible /usr/local/lib/gcc/x86_64-linux-gnu/14.2.0/libgcc.a when searching for -lgcc
/usr/bin/ld: cannot find -lgcc: No such file or directory
/usr/bin/ld: cannot find -lgcc_s: No such file or directory
collect2: error: ld returned 1 exit status

在网上搜了各种解决办法
把32位库安装目录加入LIBRARY_PATH,仍然不行

whereis crt1.o
crt1.o: /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib32/crt1.o
export LIBRARY_PATH=/usr/lib32/:/usr/lib/x86_64-linux-gnu:$LIBRARY_PATH
 gcc /par/testc.c -o testc -m32
/usr/bin/ld: skipping incompatible /usr/local/lib/gcc/x86_64-linux-gnu/14.2.0/libgcc.a when searching for -lgcc
/usr/bin/ld: cannot find -lgcc: No such file or directory
/usr/bin/ld: cannot find -lgcc_s: No such file or directory
collect2: error: ld returned 1 exit status

又把libgcc_s.so.1改名复制到当前目录,还是不行

cp /usr/lib32/libgcc_s.so.1 ./libgcc_s.so
cp /usr/lib32/libgcc_s.so.1 ./libgcc.so
root@6ae32a5ffcde:/par/asm-xml-1.4/examples# gcc /par/testc.c -o testc -m32  -L  /usr/lib32/ -L .
/usr/bin/ld: i386:x86-64 architecture of input file `/usr/local/lib/gcc/x86_64-linux-gnu/14.2.0/crtbegin.o' is incompatible with i386 output
/usr/bin/ld: i386:x86-64 architecture of input file `/usr/local/lib/gcc/x86_64-linux-gnu/14.2.0/crtend.o' is incompatible with i386 output
collect2: error: ld returned 1 exit status

只好把上述错误信息再拿去问DeepSeek,

他说

这个错误非常典型,它表明你的编译环境存在配置冲突。错误信息说明:链接器(ld)正在尝试生成一个 32 位(i386)的可执行文件,但却找到了 64 位(x86-64)的启动文件(crtbegin.o, crtend.o)

问题根源分析

  1. crtbegin.ocrtend.o:这些是 GCC 工具链中至关重要的 C 运行时(C Runtime)启动和终止文件。它们在程序执行的开始(main 函数之前)和结束(main 函数返回之后)负责初始化和清理工作。
  2. 路径问题:你使用的 GCC 路径是 /usr/local/lib/gcc/x86_64-linux-gnu/14.2.0/。这表明你可能自己从源码编译并安装了一个新版本的 GCC(14.2.0)到 /usr/local/,而不是使用系统包管理器(如 apt)提供的 GCC。
  3. 关键点:你自己编译的 GCC 很可能没有同时安装 32 位的开发库和链接器支持。它默认只配置了生成 64 位代码的能力。因此,当你使用 -m32 选项时,它找不到对应的 32 位 crt 文件,反而错误地使用了它自己的 64 位版本,导致架构不匹配。

解决方案

你有两个主要的解决路径,强烈推荐方案一


方案一:使用系统自带的、支持 multilib 的 GCC(推荐)

这是最简单、最不容易出错的方法。系统通过 apt 包管理器安装的 GCC 可以和多架构库完美配合。

  1. 首先,确认并安装系统版本的 GCC 和 multilib 支持

    # 更新包列表
    sudo apt update
    
    # 安装系统默认的 C 和 C++ 编译器(如果尚未安装)
    sudo apt install gcc g++
    
    # 确保安装了完整的多库开发工具链
    # 这个包会提供 32 位编译所需的所有头文件、库和链接器脚本
    sudo apt install gcc-multilib g++-multilib
    
  2. 使用系统 GCC 进行编译
    现在,不要使用你安装在 /usr/local/ 下的 GCC,而是直接使用系统路径的 gcc

    # 直接使用 gcc 命令(它会调用系统默认的 /usr/bin/gcc)
    gcc -m32 -o my_program_32 my_program.c
    
    # 或者为了绝对明确,可以使用完整路径
    /usr/bin/gcc -m32 -o my_program_32 my_program.c
    

    这时,链接器应该能找到位于 /usr/lib32/ 或类似路径下的正确版本的 32 位 crt 文件,编译应该成功。

如何切换使用的 GCC?
你可以使用 which 命令查看当前优先使用的是哪个 gcc

which gcc
# 如果输出是 /usr/local/bin/gcc,说明你自己的 GCC 优先级更高

你可以通过指定完整路径(/usr/bin/gcc)来临时使用系统 GCC,或者调整你的 PATH 环境变量,将 /usr/bin 放在 /usr/local/bin 之前:

export PATH=/usr/bin:$PATH

然后再次尝试编译。


方案二:修复你自己编译的 GCC,使其支持 Multilib

这个方法更复杂,仅在你必须使用自己编译的 GCC 14.2.0 进行 32 位开发时才需要考虑。

原因:从源码编译 GCC 时,默认配置通常只构建原生架构(即 64 位)。要支持 32 位,你需要明确启用 multilib 并在构建时准备好 32 位的库(如 libc6-dev-i386)。

  1. 安装构建 GCC multilib 所需的 32 位开发库

    sudo apt install libc6-dev-i386
    # 可能还需要其他 32 位库,这取决于你的配置
    
  2. 重新配置和编译你的 GCC
    这需要你回到 GCC 的源码目录。

    • 关键配置选项:在运行 configure 时,你必须确保没有使用 --disable-multilib 选项。最好显式地移除它或使用 --enable-multilib
    • 示例配置命令
      # 在你的 GCC 源码构建目录中
      ../configure --prefix=/usr/local --enable-languages=c,c++ --enable-multilib
      
    • 然后重新编译和安装
      make -j$(nproc) # 使用所有CPU核心进行编译
      sudo make install
      
  3. 验证
    安装完成后,你的 /usr/local/lib/gcc/x86_64-linux-gnu/14.2.0/ 目录下应该会有一个 32/ 子目录,里面包含 crtbegin.o, crtend.o 等文件的 32 位版本

    ls /usr/local/lib/gcc/x86_64-linux-gnu/14.2.0/32/
    

    如果这个目录存在且里面有文件,那么你的 GCC 就已经支持 -m32 了。

总结

  • 根本原因:你自己编译的 GCC 缺少 32 位支持(multilib)。
  • 最简单快速的解决方案使用系统自带的 apt 安装的 gcc-multilib。执行 sudo apt install gcc-multilib g++-multilib,然后使用 /usr/bin/gcc -m32 进行编译。
  • 除非有特殊需求,否则不建议自己从源码编译 GCC 用于日常开发,因为包管理器管理的版本与系统的库集成得更好。

看了这个才注意到,刚才安装过程中确实安装了gcc 12,应该就是他说的支持gcc-multilib的编译器。

whereis gcc-12
gcc-12: /usr/bin/gcc-12
root@6ae32a5ffcde:/par/asm-xml-1.4/examples# /usr/bin/gcc-12 /par/testc.c -o testc -m32
root@6ae32a5ffcde:/par/asm-xml-1.4/examples# ./testc
Hello World!

为了消除环境变量影响,退出gcc容器再次进去,果然gcc-12自动识别32位库,无需人工指定库文件位置,再编译asm-xml-1.4/examples的示例程序就成功了

root@6ae32a5ffcde:/par/asm-xml-1.4/examples# exit
exit
root@DESKTOP-59T6U68:/mnt/c/Users/lt# docker exec -it gcc bash
/usr/bin/gcc-12 /par/testc.c -o testc -m32
root@6ae32a5ffcde:/par/asm-xml-1.4/examples# ./testc
Hello World!

root@6ae32a5ffcde:/par/asm-xml-1.4/examples# gcc-12 -O2 -fomit-frame-pointer -I ../include -c c/simple/simple.c -o simple.o -m32
root@6ae32a5ffcde:/par/asm-xml-1.4/examples# gcc-12 -s simple.o ../obj/elf/asm-xml.o -o simple -m32
/usr/bin/ld: warning: ../obj/elf/asm-xml.o: missing .note.GNU-stack section implies executable stack
/usr/bin/ld: NOTE: This behaviour is deprecated and will be removed in a future version of the linker
/usr/bin/ld: warning: simple has a LOAD segment with RWX permissions
root@6ae32a5ffcde:/par/asm-xml-1.4/examples# ls
c  cpp  data  libgcc.so  libgcc_s.so  mac.mak  mingw.mak  simple  simple.o  table.csv  testc  unix.mak
root@6ae32a5ffcde:/par/asm-xml-1.4/examples# ./simple
================================
Employee id.: 001
Manager id..:
First Name..: Brian
Last Name...: Williams
Email.......: bwilliams@company.com
Position....: Chief Executive Officer
================================
Employee id.: 123
Manager id..: 001
First Name..: John
Last Name...: Smith
Email.......: jsmith@company.com
Position....: Sales Manager
================================
Employee id.: 456
Manager id..: 001
First Name..: Robert
Last Name...: Anderson
Email.......: randerson@company.com
Position....: Marketing Manager
================================
Employee id.: 789
Manager id..: 123
First Name..: David
Last Name...: Moore
Email.......: dmoore@company.com
Position....: Sales Agent

需要指出,gcc-12编译生成每个.o文件时-m32选项都不可少,否则还是会错

root@6ae32a5ffcde:/par/asm-xml-1.4/examples# gcc-12 -O2 -fomit-frame-pointer -I ../include -c c/simple/simple.c -o simple.o
root@6ae32a5ffcde:/par/asm-xml-1.4/examples# gcc-12 -s simple.o ../obj/elf/asm-xml.o -o simple
/usr/bin/ld: i386 architecture of input file `../obj/elf/asm-xml.o' is incompatible with i386:x86-64 output
root@6ae32a5ffcde:/par/asm-xml-1.4/examples# gcc-12 -s simple.o ../obj/elf/asm-xml.o -o simple -m32
/usr/bin/ld: i386:x86-64 architecture of input file `simple.o' is incompatible with i386 output

网站公告

今日签到

点亮在社区的每一天
去签到