2016-03-22 13 views
10

Gần đây, chúng tôi đã nhận được báo cáo vì GCC 5.1, libstdc++ and Dual ABI. Có vẻ như Clang is not aware of the GCC inline namespace changes, do đó, nó tạo mã dựa trên một bộ không gian tên hoặc ký hiệu, trong khi GCC đã sử dụng một bộ không gian tên hoặc ký hiệu khác. Tại thời gian liên kết, có vấn đề do thiếu biểu tượng.Liên kết các sự cố do biểu tượng với abi :: cxx11?

Nếu tôi phân tích cú pháp trang Dual ABI chính xác, có vẻ như vấn đề xoay vòng trên _GLIBCXX_USE_CXX11_ABIabi::cxx11 với một số khó khăn bổ sung. Đọc thêm có sẵn trên blog của Red Hat tại GCC5 and the C++11 ABIThe Case of GCC-5.1 and the Two C++ ABIs.

Dưới đây là từ máy Ubuntu 15. Máy cung cấp GCC 5.2.1.

$ cat test.cxx 
#include <string> 

std::string foo __attribute__ ((visibility ("default"))); 
std::string bar __attribute__ ((visibility ("default"))); 

$ g++ -g3 -O2 -shared test.cxx -o test.so 

$ nm test.so | grep _Z3 
... 
0000201c B _Z3barB5cxx11 
00002034 B _Z3fooB5cxx11 

$ echo _Z3fooB5cxx11 _Z3barB5cxx11 | c++filt 
foo[abi:cxx11] bar[abi:cxx11] 

Làm cách nào để tạo một nhị phân có biểu tượng sử dụng cả trang trí ("cùng tồn tại" như blog Red Hat gọi)?

Hoặc các tùy chọn có sẵn cho chúng tôi là gì?


Tôi đang cố gắng đạt được "nó chỉ hoạt động" cho người dùng. Tôi không quan tâm nếu có hai ký hiệu yếu với hai hành vi khác nhau (std::string thiếu bản sao ghi-on-write, trong khi std::string[abi:cxx11] cung cấp sao chép-ghi-ghi). Hoặc, người ta có thể là bí danh cho người khác.

Debian có một số lượng lỗi tương tự tại số Debian Bug report logs: Bugs tagged libstdc++-cxx11. Giải pháp của họ là xây dựng lại tất cả mọi thứ theo ABI mới, nhưng nó không xử lý được trường hợp góc của các trình biên dịch trộn/kết hợp với các thay đổi của ABI.

Trong thế giới Apple, tôi nghĩ rằng điều này là gần với một chất béo nhị phân. Nhưng tôi không chắc phải làm gì trong thế giới Linux/GCC. Cuối cùng, chúng tôi không kiểm soát cách xây dựng thư viện của distro và chúng tôi không kiểm soát những trình biên dịch nào được sử dụng để liên kết ứng dụng với thư viện.

+0

Sản phẩm của bạn là gì? Thư viện hoặc chương trình? –

+0

@ n.m. - Sản phẩm là [Crypto ++] của Wei Dai (http://www.cryptopp.com/). Thư viện C++ của nó. Nó được xây dựng bởi Debian và được cung cấp như một phần của bản phân phối. – jww

Trả lời

3

Đây là một cách để làm điều đó, nhưng nó không phải là rất thanh lịch. Nó cũng không rõ ràng với tôi làm thế nào để làm cho GCC tự động hóa nó vì vậy tôi không phải làm những việc hai lần.

Đầu tiên, ví dụ đó là sẽ được biến thành một thư viện:

$ cat test.cxx 
#include <string> 

std::string foo __attribute__ ((visibility ("default"))); 
std::string bar __attribute__ ((visibility ("default"))); 

Sau đó:

$ g++ -D_GLIBCXX_USE_CXX11_ABI=0 -c test.cxx -o test-v1.o 
$ g++ -D_GLIBCXX_USE_CXX11_ABI=1 -c test.cxx -o test-v2.o 

$ ar cr test.a test-v1.o test-v2.o 
$ ranlib test.a 

$ g++ -shared test-v1.o test-v2.o -o test.so 

Cuối cùng, xem những gì chúng tôi đã nhận:

$ nm test.a 

test-v1.o: 
00000004 B bar 
     U __cxa_atexit 
     U __dso_handle 
00000000 B foo 
0000006c t _GLOBAL__sub_I_foo 
00000000 t _Z41__static_initialization_and_destruction_0ii 
     U _ZNSsC1Ev 
     U _ZNSsD1Ev 

test-v2.o: 
     U __cxa_atexit 
     U __dso_handle 
0000006c t _GLOBAL__sub_I__Z3fooB5cxx11 
00000018 B _Z3barB5cxx11 
00000000 B _Z3fooB5cxx11 
00000000 t _Z41__static_initialization_and_destruction_0ii 
     U _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1Ev 
     U _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev 

Và:

$ nm test.so 

00002020 B bar 
00002018 B __bss_start 
00002018 b completed.7181 
     U [email protected]@GLIBC_2.1.3 
     w [email protected]@GLIBC_2.1.3 
00000650 t deregister_tm_clones 
000006e0 t __do_global_dtors_aux 
00001ef4 t __do_global_dtors_aux_fini_array_entry 
00002014 d __dso_handle 
00001efc d _DYNAMIC 
00002018 D _edata 
00002054 B _end 
0000087c T _fini 
0000201c B foo 
00000730 t frame_dummy 
00001ee8 t __frame_dummy_init_array_entry 
00000980 r __FRAME_END__ 
00002000 d _GLOBAL_OFFSET_TABLE_ 
000007dc t _GLOBAL__sub_I_foo 
00000862 t _GLOBAL__sub_I__Z3fooB5cxx11 
     w __gmon_start__ 
000005e0 T _init 
     w _ITM_deregisterTMCloneTable 
     w _ITM_registerTMCloneTable 
00001ef8 d __JCR_END__ 
00001ef8 d __JCR_LIST__ 
     w _Jv_RegisterClasses 
00000690 t register_tm_clones 
00002018 d __TMC_END__ 
00000640 t __x86.get_pc_thunk.bx 
0000076c t __x86.get_pc_thunk.dx 
0000203c B _Z3barB5cxx11 
00002024 B _Z3fooB5cxx11 
00000770 t _Z41__static_initialization_and_destruction_0ii 
000007f6 t _Z41__static_initialization_and_destruction_0ii 
     U [email protected]@GLIBCXX_3.4 
     U [email protected]@GLIBCXX_3.4 
     U [email protected]@GLIBCXX_3.4.21 
     U [email protected]@GLIBCXX_3.4.21 
5

Tuyên bố từ chối trách nhiệm, những điều sau đây không được thử nghiệm trong sản xuất, bạn có thể tự chịu rủi ro.

Bạn có thể tự mình phát hành thư viện của mình theo ABI kép. Điều này tương tự với OSX "chất béo nhị phân", nhưng được xây dựng hoàn toàn bằng C++.

Cách dễ nhất để làm như vậy là biên dịch thư viện hai lần: với -D_GLIBCXX_USE_CXX11_ABI=0 và với -D_GLIBCXX_USE_CXX11_ABI=1.Đặt toàn bộ thư viện thuộc hai không gian tên khác nhau tùy thuộc vào giá trị của macro:

#if _GLIBCXX_USE_CXX11_ABI 
# define DUAL_ABI cxx11 __attribute__((abi_tag("cxx11"))) 
#else 
# define DUAL_ABI cxx03 
#endif 

namespace CryptoPP { 
    inline namespace DUAL_ABI { 
    // library goes here 
    } 
} 

Bây giờ người dùng của bạn có thể sử dụng CryptoPP::whatever như thường lệ, các bản đồ này cho một trong hai CryptoPP::cxx11::whatever hoặc CryptoPP::cxx03::whatever tùy theo ABI chọn.

Lưu ý, hướng dẫn GCC cho biết phương pháp này sẽ thay đổi tên bị xáo trộn của mọi thứ được xác định trong không gian tên nội tuyến được gắn thẻ. Theo kinh nghiệm của tôi, điều này không xảy ra.

Phương pháp khác sẽ gắn thẻ mọi lớp, chức năng và biến với __attribute__((abi_tag("cxx11"))) nếu _GLIBCXX_USE_CXX11_ABI không khác. Thuộc tính này độc đáo thêm [cxx11] vào đầu ra của trình gỡ rối. Tôi nghĩ rằng bằng cách sử dụng một không gian tên hoạt động cũng như mặc dù, và yêu cầu sửa đổi ít hơn để mã hiện có.

Về lý thuyết bạn không cần phải lặp lại toàn bộ thư viện, chỉ có chức năng và các lớp học sử dụng std::stringstd::list, và các chức năng và các lớp học sử dụng những chức năng và các lớp học, và vân vân đệ quy. Nhưng trong thực tế nó có lẽ không đáng để nỗ lực, đặc biệt nếu thư viện không phải là rất lớn.

+0

Cảm ơn @ n.m. Các đối tượng được chia sẻ là vấn đề cho các trình biên dịch không nhận thức, giống như Clang hiện tại. Các đối tượng được chia sẻ là OK cho các trình biên dịch nhận thức. Đối với các trình biên dịch không nhận thức, đối tượng được chia sẻ cần ký hiệu cho cả 'CryptoPP :: cxx11 :: whatever' và' CryptoPP :: cxx03 :: whatever'. Nội dung trong tiêu đề phải OK khi bạn mô tả. Tôi vẫn còn bit twiddling để xem những gì có thể được thực hiện để giúp các trình biên dịch không biết. – jww

+0

"đối tượng được chia sẻ cần ký hiệu cho cả CryptoPP :: cxx11 :: bất cứ điều gì và CryptoPP :: cxx03 :: bất cứ điều gì" Vâng đó là những gì tôi đang nói. Bạn kết hợp cả hai phiên bản trong cùng một thư viện. –

+0

Nếu bạn muốn hỗ trợ clang hoặc các trình biên dịch khác không biết về abi_tag, chỉ cần không sử dụng '__attribute __ ((abi_tag (" cxx11 ")))'. –

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