无法 link 与 -mx32 和 gcc 4.7 或 gcc 4.8 共享库

Can't link shared library with -mx32 and gcc 4.7 or gcc 4.8

我正在尝试将为 32 位嵌入式处理器编写的大型代码库编译为 运行 在 64 位桌面处理器上进行 simulation/unit 测试。我需要生成的对象是一个共享库。这在 Windows 中不是问题,我可以像这样构建一个 dll (/DWIN32),它 运行 没问题。

在 Linux 中,我能够使用为 gcc 和 linker 提供的 -m32 选项进行编译和 link,并获得一个共享库。问题是,这个库(就像我用 -m32 指定的那样)是一个 32 位库,不会在我的 64 位 arch 上 运行。使用 Python,我尝试加载库(使用 ctypes.cdll.LoadLibrary())

OSError: out.so: wrong ELF class: ELFCLASS32

我发现了 -mx32 选项,根据 docs 这正是我想要的:

The -mx32 option sets int, long, and pointer types to 32 bits, and generates code for the x86-64 architecture.

因此,我将 -mx32 传递给编译器和 linker(替换我的 -m32 选项)并获得以下内容(截断输出):

/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/4.8/libstdc++.so when searching for -lstdc++
/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/4.8/libstdc++.a when searching for -lstdc++
/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/4.8/32/libstdc++.so when searching for -lstdc++
/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/4.8/32/libstdc++.a when searching for -lstdc++
/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/4.8/libstdc++.so when searching for -lstdc++
/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/4.8/libstdc++.a when searching for -lstdc++
/usr/bin/ld: cannot find -lstdc++
/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libm.so when searching for -lm
/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libm.a when searching for -lm
/usr/bin/ld: skipping incompatible /usr/lib/x86_64-linux-gnu/libm.so when searching for -lm
/usr/bin/ld: skipping incompatible /usr/lib/x86_64-linux-gnu/libm.a when searching for -lm
/usr/bin/ld: skipping incompatible /usr/lib/x86_64-linux-gnu/libm.so when searching for -lm
/usr/bin/ld: skipping incompatible /usr/lib/x86_64-linux-gnu/libm.a when searching for -lm
/usr/bin/ld: cannot find -lm

我在 gcc 4.7 和 gcc 4.8 上得到了相同的结果。以上输出来自 gcc 4.8。

我安装了 gcc-4.8-multilib 和 g++-4.8-multilib。

我的库路径是:

LIBRARY_PATH=/usr/lib/x86_64-linux-gnu:/usr/lib/gcc/x86_64-linux-gnu/4.8/32:/usr/lib/gcc/x86_64-linux-gnu/4.8/

从 .bashrc 我已经像这样指定了它(如下),绝望地添加了 /4.8/ 和 /4.8/32/ 的东西,在读到 linker 只会绑定那些库工作。

export LIBRARY_PATH=/usr/lib/$(gcc -print-multiarch):/usr/lib/gcc/x86_64-linux-gnu/4.8/32:/usr/lib/gcc/x86_64-linux-gnu/4.8/

正如我所提到的,这已经在 Windows 作为一个 dll 运行良好,我不得不相信我只是遗漏了一些东西。指针应该是 32 位,long 应该是 32 位,整个东西应该 运行 on x86_64。 -mx32 说它会做到这一点(对吗?)。

在 -m32 中编译后检查其中一个对象:

$:~/project$ file foo.o
foo.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped

并在使用 -mx32 编译后检查同一个对象:

$:~/project$ file foo.o
foo.o: ELF 32-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

我是不是走错了路?我仍然可以使用具有某种兼容层的 32 位共享库吗?

我看到 bug report against gcc 4.7 regarding these link errors... But I didn't see much conclusion from it. This page 说 gcc 4.8 是 x32 的推荐最低版本,所以我安装了它。仍然 - 我无法达到 link。 -m32 link很好。

-m32 是正常的 32 位模式,是的,大多数 x86-64 GNU/Linux 系统都支持 32 位库的多体系结构,如果尚未安装,您可以安装这些库。

-mx32选项根本不是你想要的。它为 the x32 ABI, which uses 32-bit addresses with 64-bit registers and instructions. The resulting code is not compatible with 32-bit processors (as it uses 64-bit instructions), but is also not compatible with 64-bit code (which will use 64-bit addresses). So everything in user-space has to be compiled with it in mind, including libc, and even the kernel needs to support x32 user-space and syscalls: https://unix.stackexchange.com/questions/121424/linux-and-x32-abi-how-to-use 编译代码(即就像支持 32 位二进制文​​件一样,x32 实际上是一个单独的体系结构。)

更复杂的是,您在 Windows 上所做的测试根本没有按照您的想法进行。将 /DWIN32 传递给 Visual C++ 编译器只定义了一个名为 WIN32 的宏(就像 GCC 的 -DWIN32 一样);它不会使编译器生成 32 位二进制文​​件。 64 位 Windows 可执行文件 不能 加载 32 位库;您一直在测试的库实际上是 64 位的。

如果要对 32 位代码进行单元测试,则需要在 -m32 这样的完全 32 位目标架构上对其进行测试。 x32 不是这样的系统。 (不过,64 位内核下的 32 位代码很好,除非您担心只有 2G 或 3GiB 的地址-space 可由用户-space 在您的嵌入式系统中使用,而不是在 64 位内核下为 4GiB。)

你的初始错误,试图加载你成功构建的库,表明你没有使用 Python 的 32 位版本,因此它无法构建 32 位共享库。

如果您安装 Python 的 i386(32 位)版本,它应该能够加载该库。更重要的是,这是您需要在嵌入式 i386 目标上 运行 Python 的版本。

请注意,以上所有内容均假定您的“32 位嵌入式处理器”与 i386 兼容。如果不是(它是 ARM 或 MIPS 或其他一些 32 位嵌入式处理器),您需要为该目标安装交叉编译器来构建您的库和模拟器(例如 QEMU)到 运行 可执行文件。