无法将共享库与 -mx32 和 gcc 4.7 或 gcc 4.8 链接 [英] Can't link shared library with -mx32 and gcc 4.7 or gcc 4.8
问题描述
我正在尝试编译为 32 位嵌入式处理器编写的大型代码库,以便在 64 位桌面处理器上运行以进行模拟/单元测试.我需要生成的对象是一个共享库.这在 Windows 中不是问题,我可以构建这样的 dll (/DWIN32) 并且它运行良好.
I'm trying to compile a large codebase written for a 32 bit embedded processor to run on a 64 bit desktop processor for simulation/unit testing. I need the resulting object to be a shared library. This is not an issue in Windows, I can build a dll like this (/DWIN32) and it runs fine.
在 Linux 中,我能够编译和链接给 gcc 和链接器的 -m32 选项,并得到一个共享库.问题是,这个库是(就像我用 -m32 指定的)一个 32 位库,不会在我的 64 位架构上运行.使用 Python,我尝试加载库(使用 ctypes.cdll.LoadLibrary())
In Linux, I'm able to compile and link with the -m32 option given to both gcc and the linker and get a shared library out. The problem is, this library is (just like I specified with -m32) a 32 bit library and will not run on my 64 bit arch. With Python, I try to load the library (using ctypes.cdll.LoadLibrary())
OSError: out.so: wrong ELF class: ELFCLASS32
我发现了 -mx32 选项,并且根据 docs 这正是我想要的:
I discovered the -mx32 option, and according to the docs this is exactly what I want:
-mx32 选项将 int、long 和指针类型设置为 32 位,并且为 x86-64 架构生成代码.
The -mx32 option sets int, long, and pointer types to 32 bits, and generates code for the x86-64 architecture.
因此,我将 -mx32 传递给编译器和链接器(替换我的 -m32 选项)并获得以下内容(截断输出):
So, I pass -mx32 to the compiler and the linker (replacing my -m32 option) and get the following (snipped the output):
/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.
I get the same results with gcc 4.7 and gcc 4.8. The above output is from gcc 4.8.
我安装了 gcc-4.8-multilib 和 g++-4.8-multilib.
I have gcc-4.8-multilib and g++-4.8-multilib installed.
我的库路径是:
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/内容.
From .bashrc I've specified it like this (below), in despair adding the /4.8/ and /4.8/32/ stuff after reading that the linker would only bind with the libraries that work.
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 位,整个过程应该在 x86_64 上运行.-mx32 说它会做到这一点(对吧?).
As I mention, this works quite well already on Windows as a dll, I have to believe I'm just missing something. Pointers should be 32 bits and longs should be 32 bits, the whole thing should run on x86_64. -mx32 says it will do exactly that (right?).
在 -m32 中编译后检查其中一个对象:
Checking one of the objects after compiling in -m32:
$:~/project$ file foo.o
foo.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
并在使用 -mx32 编译后检查相同的对象:
And checking the same object after compiling with -mx32:
$:~/project$ file foo.o
foo.o: ELF 32-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
我是不是用错了方法?我还可以使用带有某种兼容层的 32 位共享库吗?
Am I going about this the wrong way? Can I still use my 32-bit shared library with some sort of compatibility layer?
我看到了针对 gcc 4.7 的错误报告关于这些链接错误......但我没有从中看到太多结论.此页面说 gcc 4.8 是 x32 的推荐最低要求,所以我安装了它.仍然 - 我无法将其链接.-m32 链接正常.
I saw a bug report against gcc 4.7 regarding these link errors... But I didn't see much conclusion from it. This page says that gcc 4.8 is the recommended minimum for x32, so I installed it. Still -- I can't get it to link. -m32 links fine.
推荐答案
-m32
是正常的 32 位模式,是的,大多数 x86-64 GNU/Linux 系统都支持 32 位的多架构如果尚未安装,您可以安装这些库.
-m32
is normal 32-bit mode, and yes most x86-64 GNU/Linux systems have multiarch support with 32-bit libraries that you can install if not already installed.
-mx32
选项根本不是您想要的.它为 x32 ABI 编译代码,它使用带有 64 位寄存器的 32 位地址和指示.生成的代码与 32 位处理器不兼容(因为它使用 64 位指令),但也与 64 位代码(将使用 64 位地址)不兼容.所以用户空间中的所有东西都必须在编译时考虑到它,包括 libc,甚至内核也需要支持 x32 用户空间和系统调用:https://unix.stackexchange.com/questions/121424/linux-and-x32-abi-how-to-use(即只是就像支持 32 位二进制文件一样,x32 实际上是一个独立的架构.)
The -mx32
option is not what you want at all. It compiles code for 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 (i.e. just like supporting 32-bit binaries, x32 is effectively a separate architecture.)
更复杂的是,您在 Windows 上所做的测试根本没有按照您的想法进行.将 /DWIN32
传递给 Visual C++ 编译器只定义了一个名为 WIN32
的宏(就像 -DWIN32
用于 GCC);它不会让编译器生成 32 位二进制文件.64 位 Windows 可执行文件无法加载 32 位库;您一直在测试的库实际上是 64 位的.
Complicating matters further, the testing you've been doing on Windows hasn't been doing what you think at all. Passing /DWIN32
to the Visual C++ compiler only defines a macro called WIN32
(like -DWIN32
would for GCC); it doesn't make the compiler generate 32-bit binaries. 64-bit Windows executables cannot load 32-bit libraries; the libraries you've been testing with have actually been 64-bit.
如果您想对 32 位代码进行单元测试,则需要在像 -m32
这样的完整 32 位目标架构上进行测试.x32 不是这样的系统.(不过,64 位内核下的 32 位代码很好,除非您担心嵌入式系统中的用户空间只能使用 2G 或 3GiB 的地址空间,而不是 64 位内核下的 4GiB.)
If you want to unit-test 32-bit code, you'll need to test it on a fully 32-bit target architecture like -m32
. x32 is not such a system. (32-bit code under a 64-bit kernel is fine, though, unless you're worried about only having 2G or 3GiB of address-space usable by user-space in your embedded system, instead of 4GiB under a 64-bit kernel.)
这篇关于无法将共享库与 -mx32 和 gcc 4.7 或 gcc 4.8 链接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!