无法将共享库与 -mx32 和 gcc 4.7 或 gcc 4.8 链接

Posted

技术标签:

【中文标题】无法将共享库与 -mx32 和 gcc 4.7 或 gcc 4.8 链接【英文标题】:Can't link shared library with -mx32 and gcc 4.7 or gcc 4.8 【发布时间】:2016-01-18 08:47:39 【问题描述】:

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

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

OSError: out.so: wrong ELF class: ELFCLASS32

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

-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 的 bug report...但我没有从中看到太多结论。 This page 说 gcc 4.8 是 x32 的推荐最低版本,所以我安装了它。仍然-我无法链接。 -m32 链接正常。

【问题讨论】:

假设您确实需要 ELF 64-bits ,链接器似乎无法找到 glibc 提供的 libm.so。可以在库路径中添加/usr/lib64 吗? 感谢@alvits 的回复,但是我没有这个目录:$ cd /usr/lib64 bash: cd: /usr/lib64: No such file or directory 【参考方案1】:

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

-mx32 选项根本不是您想要的。它为the 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 的宏(就像-DWIN32 用于GCC);它不会使编译器生成 32 位二进制文​​件。 64 位 Windows 可执行文件无法加载 32 位库;您一直在测试的库实际上是 64 位的。

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

【讨论】:

谢谢@duskwuff。你能解释一下 Visual Studio 如何能够完成我想要的吗?是否已经存在某种允许 32 位 dll 运行的抽象层? 它没有;您在 Windows 上的测试方法有缺陷。 /DWIN32 只是定义了一个名为“WIN32”的宏;它实际上并没有让 Visual Studio 构建 32 位代码。 为什么它会在 Windows 中编译和链接?我想真正的问题是为什么我不能与 mx32 链接?之后我会弄清楚是什么坏了。或者,我应该采取的下一个方法是什么? @duskwuff 它在 Windows 中编译为 64 位库。 /DWIN32 不支持 32 位。如果要测试 32 位库,则需要将其加载到 32 位可执行文件中;没有办法。 好的。因此,唯一的做法是在出现 gcc 错误时处理它们(尽管事实上我在 Visual Studio 中没有相同的错误),并忘记 -m32 (因为最终目标是加载并运行它来自 64 位进程)。是否有某些原因我无法链接 -mx32 并发现它无法正常运行? (在一天结束时,我宁愿现在找出(谢谢)我需要构建为原生 64 位,但我的问题的标题是 -mx32 的链接错误)。【参考方案2】:

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

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

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

【讨论】:

最终目标是从 64 位版本的 Matlab 加载它。我不需要完全模拟目标。我已经对目标特定位(例如 eeprom 读取等)进行了抽象。而且我已经可以在 Windows 中做我想做的事了。我以为我可以在 Linux 中构建相同的代码……听起来答案是,正确移植它,或者忘记它。

以上是关于无法将共享库与 -mx32 和 gcc 4.7 或 gcc 4.8 链接的主要内容,如果未能解决你的问题,请参考以下文章

使用预编译的C共享库与JNI / NDK

ubuntu下交叉编译windows c程序

cc1plus:错误:无法识别的命令行选项'-std = c ++ 11'Ubuntu gcc 4.7

gcc默认链接到libc.a或libc.so吗?

在centOS7.2上编译gcc4.4.7

使用 GCC (ARM) 配置 FreeRTOS