问题描述
我已经为armv7-unknown-linux-gnueabihf
编译了Rust程序,并且希望它在安装了glibc 2.16的系统上运行.不幸的是,运行它时出现此错误:
I have compiled a Rust program for armv7-unknown-linux-gnueabihf
, and I want it to run on a system that has glibc 2.16 installed. Unfortunately when running it I get this error:
./foo: /lib/libc.so.6: version `GLIBC_2.18' not found (required by ./foo)
运行objdump -T foo
显示glibc 2.18所需的唯一符号是:
Running objdump -T foo
reveals that the only symbol needed from glibc 2.18 is:
00000000 w DF *UND* 00000000 GLIBC_2.18 __cxa_thread_atexit_impl
铁锈使较弱的符号(如objdump
的小w
标志所示),但是GCC显然是愚蠢的,即使来自GLIBC_2.18的所有符号仍然很弱使GLIBC_2.18本身成为一个强大的要求.您可以通过readelf
看到这一点:
Rust makes __cxa_thread_atexit_impl
a weak symbol (as seen by the little w
flag from objdump
), however GCC is apparently stupid and even though all the symbols from GLIBC_2.18 are weak it still makes GLIBC_2.18 itself a strong requirement. You can see that with readelf
:
$ readelf -V foo
...
Version needs section '.gnu.version_r' contains 5 entries:
Addr: 0x0000000000001e4c Offset: 0x001e4c Link: 6 (.dynstr)
000000: Version: 1 File: ld-linux-armhf.so.3 Cnt: 1
0x0010: Name: GLIBC_2.4 Flags: none Version: 9
0x0020: Version: 1 File: librt.so.1 Cnt: 1
0x0030: Name: GLIBC_2.4 Flags: none Version: 5
0x0040: Version: 1 File: libgcc_s.so.1 Cnt: 4
0x0050: Name: GCC_4.3.0 Flags: none Version: 10
0x0060: Name: GCC_3.0 Flags: none Version: 7
0x0070: Name: GCC_3.5 Flags: none Version: 6
0x0080: Name: GCC_3.3.1 Flags: none Version: 4
0x0090: Version: 1 File: libc.so.6 Cnt: 2
0x00a0: Name: GLIBC_2.18 Flags: none Version: 8
0x00b0: Name: GLIBC_2.4 Flags: none Version: 3
0x00c0: Version: 1 File: libpthread.so.0 Cnt: 1
0x00d0: Name: GLIBC_2.4 Flags: none Version: 2
请注意,GLIBC_2.18
表示Flags: none
.应该说Flags: WEAK
.幸运的是,我发现了一个了不起的页面,有人可以看到如何解决这个问题.不幸的是,它涉及到 hex编辑二进制文件 !
Notice that GLIBC_2.18
says Flags: none
. It should say Flags: WEAK
. Fortunately I found an amazing page where someone shows how to fix this. Unfortunately it involves hex editing the binary!
获取该.gnu.version_r
表(0x001e4c
)的偏移量,添加GLIBC_2.18
(0x00a0
)的条目偏移量,然后为该地址的struct的flags字段添加一个偏移量(0x04
).这给出了0x001EF0
.在该地址上应该有两个零字节:0x0000
.将它们更改为0x0200
.
Take the offset of that .gnu.version_r
table (0x001e4c
), add the entry offset for GLIBC_2.18
(0x00a0
), then add an offset for the flags field of the struct at that address (0x04
). That gives 0x001EF0
. At that address there should be two zero bytes: 0x0000
. Change them to 0x0200
.
通过readelf
验证:
Version needs section '.gnu.version_r' contains 5 entries:
Addr: 0x0000000000001e4c Offset: 0x001e4c Link: 6 (.dynstr)
000000: Version: 1 File: ld-linux-armhf.so.3 Cnt: 1
0x0010: Name: GLIBC_2.4 Flags: none Version: 9
0x0020: Version: 1 File: librt.so.1 Cnt: 1
0x0030: Name: GLIBC_2.4 Flags: none Version: 5
0x0040: Version: 1 File: libgcc_s.so.1 Cnt: 4
0x0050: Name: GCC_4.3.0 Flags: none Version: 10
0x0060: Name: GCC_3.0 Flags: none Version: 7
0x0070: Name: GCC_3.5 Flags: none Version: 6
0x0080: Name: GCC_3.3.1 Flags: none Version: 4
0x0090: Version: 1 File: libc.so.6 Cnt: 2
0x00a0: Name: GLIBC_2.18 Flags: WEAK Version: 8
0x00b0: Name: GLIBC_2.4 Flags: none Version: 3
0x00c0: Version: 1 File: libpthread.so.0 Cnt: 1
0x00d0: Name: GLIBC_2.4 Flags: none Version: 2
成功!除非它仍然不起作用:
Success! Except it still doesn't work:
./foo: /lib/libc.so.6: weak version `GLIBC_2.18' not found (required by ./foo)
./foo: relocation error: ./foo: symbol __cxa_thread_atexit_impl, version GLIBC_2.18 not defined in file libc.so.6 with link time reference
仍然需要弱版本吗?!我等不及glibc死了.
How is the weak version still required?! I can't wait for glibc to die.
有没有办法让Rust在不使用此符号的情况下构建程序?
Is there any way to get Rust to build the program without using this symbol?
推荐答案
您需要一个为glibc 2.16或更早版本编译的Rust工具链. glibc 2.17可能也很好,因为它缺少__cxa_thread_atexit_impl
,因此它不会在二进制文件中携带GLIBC_2.18
符号版本.
You need a Rust toolchain which was compiled for glibc 2.16 or earlier. glibc 2.17 likely works as well because it lacks __cxa_thread_atexit_impl
, so that it will not carry a GLIBC_2.18
symbol version in the binary.
在Rust代码中使用弱符号不是特别有用,因为GNU的ELF符号版本控制的特定版本没有弱符号版本.我们可能最终会对此进行更改,但是现在,解决此问题的最佳方法是使用足够陈旧的工具链进行编译.
The use of the weak symbol in the Rust code is not particularly useful because GNU's particular version of ELF symbol versioning does not have weak symbol versions. We might change that eventually, but right now, the best way to deal with this is to compile with a sufficiently old toolchain.
另一个选择是将符号反向移植到您使用的glibc中.这应该是一个相当隔离的backport,可能包含以下提交:
Another option is to backport the symbol into the glibc you use. This should be a fairly isolated backport, probably consisting of these commits:
- C ++ 11 thread_local析构函数支持
- 避免在静态链接中无条件__call_tls_dtors调用
- 也可以使用l_tls_dtor_count来决定对象卸载(BZ#18657)
- Harden tls_dtor_list与指针修改[BZ #19018]
- C++11 thread_local destructors support
- Avoid unconditional __call_tls_dtors calls in static linking.
- Also use l_tls_dtor_count to decide on object unload (BZ #18657)
- Harden tls_dtor_list with pointer mangling [BZ #19018]
(我没有尝试过向glibc 2.16的反向移植,但是就目前而言,它看起来并不特别困难.)
(I have not attempted the backport to glibc 2.16, but as far as such things go, it does not look particularly difficult.)
这篇关于如何编译Rust程序,使其不使用__cxa_thread_atexit_impl?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!