如何編譯Rust程序,使其不使用__cxa_thread_atexit_impl?

我為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 (從objdump的小w旗看到),然而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.18說Flags:none.應該說Flags:WEAK.幸運的是我找到了 an amazing page where someone shows how to fix this .不幸的是它涉及十六進位制編輯二進位制文件!

獲取.gnu.version_r表(0x001e4c)的偏移量,為GLIBC_2.18(0x00a0)新增條目偏移量,然後在該地址(0x04)處為結構的flags欄位新增偏移量.這給出了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在不使用此符號的情況下構建程序?

你需要一個為glibc 2.16或更早版本編譯的Rust工具鏈. glibc 2.17可能也有效,因為它缺少__cxa_thread_atexit_impl,因此它不會在二進位制文件中攜帶GLIBC_2.18符號版本.

在Rust程式碼中使用弱符號並不是特別有用,因為GNU的特定版本的ELF符號版本控制沒有弱符號版本.我們最終可能會改變它,但是現在,解決這個問題的最好方法是使用足夠舊的工具鏈進行編譯.

另一種選擇是將符號反向移植到您使用的glibc中.這應該是一個相當孤立的backport,可能包含這些提交:

>

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,但就這些事情而言,看起來並不是特別困難.)

翻譯自:https://stackoverflow.com/questions/39744926/how-can-i-compile-a-rust-program-so-it-doesnt-use-cxa-thread-atexit-impl