如何编译Rust程序,以便它不使用__cxa_thread_atexit_impl?

时间:2016-09-28 10:31:21

标签: rust glibc

我为armv7-unknown-linux-gnueabihf编译了一个Rust程序,我想让它在安装了glibc 2.16的系统上运行。不幸的是,在运行它时我收到了这个错误:

./foo: /lib/libc.so.6: version `GLIBC_2.18' not found (required by ./foo)

运行objdump -T foo显示glibc 2.18所需的唯一符号是:

00000000  w   DF *UND*  00000000  GLIBC_2.18  __cxa_thread_atexit_impl

Rust makes __cxa_thread_atexit_impl a weak symbol(从w的小objdump标志看到),但GCC显然是愚蠢的,即使GLIBC_2.18中的所有符号虽然很弱,但它仍然是GLIBC_2.18本身的强烈要求。你可以看到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.18Flags: none。应该说Flags: WEAK。幸运的是我找到了an amazing page where someone shows how to fix this。不幸的是,它涉及 十六进制编辑二进制文件

获取.gnu.version_r表(0x001e4c)的偏移量,添加GLIBC_2.180x00a0)的条目偏移量,然后为标志字段添加偏移量该地址的结构(0x04)。这给了0x001EF0。在该地址处应该有两个零字节:0x0000。将它们更改为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

成功!除了它仍然没有工作:

./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死了。

有没有办法让Rust在不使用此符号的情况下构建程序?

1 个答案:

答案 0 :(得分:1)

你需要一个为glibc 2.16或更早版本编译的Rust工具链。 glibc 2.17可能也有效,因为它缺少__cxa_thread_atexit_impl,因此它不会在二进制文件中携带GLIBC_2.18符号版本。

在Rust代码中使用弱符号并不是特别有用,因为GNU的特定版本的ELF符号版本控制没有弱符号版本。我们最终可能会改变这种情况,但是现在,解决这个问题的最佳方法是使用足够旧的工具链进行编译。

另一种选择是将符号反向移植到您使用的glibc中。这应该是一个相当孤立的backport,可能包含这些提交:

(我没有尝试过backport到glibc 2.16,但就这些事情而言,看起来并不是特别困难。)

相关问题