0

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

在 Linux 中,我可以使用 gcc 和链接器的 -m32 选项进行编译和链接,并获得一个共享库。问题是,这个库(就像我用 -m32 指定的一样)是一个 32 位库,不会在我的 64 位拱上运行。使用 Python,我尝试加载库(使用 ctypes.cdll.LoadLibrary())

OSError: out.so: wrong ELF class: ELFCLASS32

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

-mx32 选项将 int、long 和指针类型设置为 32 位,并为 x86-64 体系结构生成代码。

因此,我将 -mx32 传递给编译器和链接器(替换我的 -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/ 东西。

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 位,长应该是 32 位,整个事情应该在 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 位共享库吗?

我看到了一份针对 gcc 4.7 的关于这些链接错误的错误报告……但我没有从中看到太多的结论。 这个页面说 gcc 4.8 是 x32 的推荐最低版本,所以我安装了它。仍然-我无法链接。-m32 链接正常。

4

2 回答 2

4

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

-mx32选项根本不是您想要的。它为x32 ABI编译代码,它使用 32 位地址和 64 位寄存器和指令。生成的代码与 32 位处理器不兼容(因为它使用 64 位指令),但也不兼容 64 位代码(将使用 64 位地址)。因此,用户空间中的所有内容都必须在编译时考虑到它,包括 libc,甚至内核也需要支持 x32 用户空间和系统调用:https ://unix.stackexchange.com/questions/121424/linux-and- x32-abi-how-to-use(即就像支持 32 位二进制文​​件一样,x32 实际上是一个单独的架构。)

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

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

于 2015-10-19T21:18:30.847 回答
1

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

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

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

于 2015-10-19T21:26:09.967 回答