在网上搜快速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_64
或 amd64
)默认不包含运行 32 位 x86
(i386
/i686
)程序所需的库和链接器。因此,你需要启用多架构支持并安装必要的 32 位开发库。
步骤 1:启用多架构支持并安装运行时库
首先,你需要让系统知道它需要处理 32 位的软件包。这通过 dpkg
的多架构支持实现(适用于基于 Debian/Ubuntu 的系统)。
启用多架构:
sudo dpkg --add-architecture i386 sudo apt update
安装最重要的 32 位 C 运行时库:
这是运行绝大多数 32 位程序的最基本要求。sudo apt install libc6:i386
(可选但推荐)安装常用的 32 位库:
很多程序会依赖这些库(如图形界面库GTK
,SDL
等)。安装一个元数据包可以省去很多麻烦。sudo apt install gcc-multilib
注意:在较旧的系统上,这个包可能叫
ia32-libs
,但在新版本中已被gcc-multilib
和多架构支持取代。
步骤 2:编译 32 位程序
你有两个主要场景:编译你自己的代码,或者编译第三方源代码。
场景 A:编译你自己的 C/C++ 代码
在编译时,你需要告诉编译器生成 32 位代码。
- 使用 GCC 编译:
在gcc
或g++
命令后加上-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
时指定工具链文件或参数。
创建一个工具链文件,例如
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)
使用该工具链文件进行编译:
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 位库来加载和执行它。
故障排除
错误:
No such file or directory
- 现象:明明文件存在,一运行却报这个错。
- 原因:最常见的原因是你没有安装 32 位的 C 库 (
libc6:i386
)。 - 解决:返回 步骤 1,执行
sudo apt install libc6:i386
。
错误:
bash: ./program: Permission denied
- 原因:文件没有执行权限。
- 解决:
chmod +x ./program
错误:
.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
编译错误:
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 的系统,概念类似,但命令不同:
- 安装支持:
sudo dnf install glibc.i686
(基础库) - 安装开发工具链:
sudo dnf install glibc-devel.i686 libstdc++-devel.i686
- 编译时同样使用
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)。
问题根源分析
crtbegin.o
和crtend.o
:这些是 GCC 工具链中至关重要的 C 运行时(C Runtime)启动和终止文件。它们在程序执行的开始(main
函数之前)和结束(main
函数返回之后)负责初始化和清理工作。- 路径问题:你使用的 GCC 路径是
/usr/local/lib/gcc/x86_64-linux-gnu/14.2.0/
。这表明你可能自己从源码编译并安装了一个新版本的 GCC(14.2.0)到/usr/local/
,而不是使用系统包管理器(如apt
)提供的 GCC。 - 关键点:你自己编译的 GCC 很可能没有同时安装 32 位的开发库和链接器支持。它默认只配置了生成 64 位代码的能力。因此,当你使用
-m32
选项时,它找不到对应的 32 位crt
文件,反而错误地使用了它自己的 64 位版本,导致架构不匹配。
解决方案
你有两个主要的解决路径,强烈推荐方案一。
方案一:使用系统自带的、支持 multilib 的 GCC(推荐)
这是最简单、最不容易出错的方法。系统通过 apt
包管理器安装的 GCC 可以和多架构库完美配合。
首先,确认并安装系统版本的 GCC 和 multilib 支持:
# 更新包列表 sudo apt update # 安装系统默认的 C 和 C++ 编译器(如果尚未安装) sudo apt install gcc g++ # 确保安装了完整的多库开发工具链 # 这个包会提供 32 位编译所需的所有头文件、库和链接器脚本 sudo apt install gcc-multilib g++-multilib
使用系统 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
)。
安装构建 GCC multilib 所需的 32 位开发库:
sudo apt install libc6-dev-i386 # 可能还需要其他 32 位库,这取决于你的配置
重新配置和编译你的 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
- 关键配置选项:在运行
验证:
安装完成后,你的/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