2016-09-28 19 views
7

Tôi đã biên soạn một chương trình Rust cho armv7-unknown-linux-gnueabihf và tôi muốn nó chạy trên hệ thống có cài đặt glibc 2,16. Thật không may khi chạy nó Tôi nhận được lỗi này:Làm thế nào tôi có thể biên dịch một chương trình Rust để nó không sử dụng __cxa_thread_atexit_impl?

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

Chạy objdump -T foo tiết lộ rằng biểu tượng chỉ cần từ glibc 2.18 là:

00000000 w DF *UND* 00000000 GLIBC_2.18 __cxa_thread_atexit_impl 

Rust makes __cxa_thread_atexit_impl a weak symbol (như được thấy bởi ít w cờ từ objdump), tuy nhiên GCC dường như là ngu ngốc và mặc dù tất cả các biểu tượng từ GLIBC_2.18 đều yếu nhưng nó vẫn khiến GLIBC_2.18 trở thành một yêu cầu mạnh mẽ. Bạn có thể thấy rằng với 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 

ý rằng GLIBC_2.18 nói Flags: none. Nó sẽ nói Flags: WEAK. May mắn thay tôi tìm thấy an amazing page where someone shows how to fix this. Thật không may nó liên quan đến hex chỉnh sửa nhị phân!

Rẽ bù đắp điều đó .gnu.version_r bảng (0x001e4c), thêm các mục nhập bù đắp cho GLIBC_2.18 (0x00a0), sau đó thêm một offset cho cờ trường của struct tại địa chỉ đó (0x04). Điều đó cho phép 0x001EF0. Tại địa chỉ đó, phải có hai byte không: 0x0000. Thay đổi chúng thành 0x0200.

Xác nhận với 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 

thành công! Ngoại trừ nó vẫn không hoạt động:

./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 

thế nào là phiên bản yếu vẫn cần ?! Tôi không thể đợi glibc chết.

Có cách nào để Rust tạo chương trình mà không sử dụng biểu tượng này không?

+2

Chấp nhận khi mọi thứ khủng khiếp là cách duy nhất [chúng được cải tiến] (https://www.musl-libc.org/). Xin lỗi nếu tôi xúc phạm bất kỳ nhà phát triển GNU nào. – Timmmm

+0

Bạn đang cố ý xúc phạm * rất * người có thể trả lời câu hỏi của bạn. Tôi sẽ thứ hai @tumdum và đề nghị bạn loại bỏ các bộ phận phản tác dụng. Là một câu trả lời một phần, có * là * lý do chính xác GLIBC hoạt động theo cách của nó. Và nếu bạn tin rằng Musl là câu trả lời, chính xác thì điều gì ngăn cản bạn sử dụng nó? –

+0

'armv7-unknown-linux-muscl' không có sẵn như là một mục tiêu nhưng không may. Ngoài ra nếu tôi * có thể * có được điều này để làm việc glibc 2.4 là đủ tuổi (2006) mà đòi hỏi nó không phải là không hợp lý và nó tiết kiệm không gian so với muscl. Nếu không có cách nào xung quanh yêu cầu 2.18 (2013) thì muscl chắc chắn là một lựa chọn tốt hơn. – Timmmm

Trả lời

0

Bạn cần một chuỗi công cụ Rust được biên dịch cho glibc 2.16 hoặc cũ hơn. glibc 2,17 có khả năng hoạt động tốt vì nó thiếu __cxa_thread_atexit_impl, do đó nó sẽ không mang một phiên bản biểu tượng GLIBC_2.18 trong nhị phân.

Việc sử dụng ký hiệu yếu trong mã Rust không đặc biệt hữu ích vì phiên bản biểu tượng ELF cụ thể của GNU không có phiên bản ký hiệu yếu. Chúng ta có thể thay đổi điều đó cuối cùng, nhưng ngay bây giờ, cách tốt nhất để giải quyết vấn đề này là biên dịch với một toolchain đầy đủ.

Tùy chọn khác là quay lại biểu tượng vào glibc bạn sử dụng.Đây phải là một backport tương đối biệt lập, có lẽ bao gồm những cam kết:

(Tôi đã không cố gắng các backport để glibc 2.16, nhưng theo như những thứ như vậy đi, nó không nhìn đặc biệt khó khăn.)

+0

Có bất kỳ suy nghĩ nào mà bạn có thể đưa ra cho việc sử dụng glib của chuỗi công cụ để có thể thư giãn việc sử dụng __cxa_thread_atexit_impl không? Có thể chức năng này chỉ được sử dụng bởi một cuộc gọi rõ ràng từ chuỗi công cụ, hoặc là có một con đường để kết thúc gián tiếp bằng cách sử dụng nó? – Digikata

Các vấn đề liên quan