2016-03-22 2 views
10

Мы недавно поймали отчет из-за GCC 5.1, libstdc++ and Dual ABI. Кажется Clang is not aware of the GCC inline namespace changes, поэтому он генерирует код на основе одного набора пространств имен или символов, тогда как GCC использует другой набор пространств имен или символов. Во время соединения возникают проблемы из-за отсутствия символов.Устранение проблем, связанных с символами с помощью abi :: cxx11?

Если я правильно разобрал страницу Dual ABI, это выглядит как поворот на _GLIBCXX_USE_CXX11_ABI и abi::cxx11 с некоторыми дополнительными трудностями. Более подробное чтение доступно в блоге Red Hat по адресу GCC5 and the C++11 ABI и The Case of GCC-5.1 and the Two C++ ABIs.

Ниже приведено устройство Ubuntu 15. Машина обеспечивает 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] 

Как я могу генерировать двоичный с символами, используя как декорации («сосуществование», как блог Red Hat называет это)?

Или, какие у нас варианты?


Я пытаюсь достичь «он просто работает» для пользователей. Меня не волнует, есть ли два слабых символа с двумя разными типами поведения (std::string не хватает копий-на-запись, а std::string[abi:cxx11] обеспечивает копирование на запись). Или, может быть, псевдоним для другого.

У Debian есть лодка похожих ошибок на Debian Bug report logs: Bugs tagged libstdc++-cxx11. Их решение состояло в том, чтобы перестроить все под новым ABI, но он не обрабатывал угловой случай смешивания/сопоставления компиляторов по модулю изменений ABI.

В мире Apple, я думаю, что это близко к жирному двоичному. Но я не уверен, что делать в мире Linux/GCC. Наконец, мы не контролируем, как дистрибутив создает библиотеку, и мы не контролируем, какие компиляторы используются для связывания приложений с библиотекой.

+0

Ваш продукт? Библиотека или программа? –

+0

@ н.м. - продукт Wei Dai's [Crypto ++] (http://www.cryptopp.com/). Его библиотека C++. Его построено Debian и поставляется как часть дистрибутива. – jww

ответ

3

Вот один из способов сделать это, но его не очень элегантно. Мне также непонятно, как заставить GCC автоматизировать его, поэтому мне не нужно делать что-то дважды.

Во-первых, пример, который будет превращен в библиотеку:

$ cat test.cxx 
#include <string> 

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

Тогда:

$ 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 

Наконец, посмотрим, что мы получили:

$ 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 

И:

$ 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

Отказ от ответственности, следующее не проверено на производстве, используйте на свой страх и риск.

Вы можете сами выпускать свою библиотеку под двойным ABI. Это более или менее похоже на OSX «fat binary», но полностью построено на C++.

Самый простой способ сделать это - собрать библиотеку дважды: с -D_GLIBCXX_USE_CXX11_ABI=0 и с -D_GLIBCXX_USE_CXX11_ABI=1.Поместите всю библиотеку в двух различных пространствах имен в зависимости от значения макроса:

#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 
    } 
} 

Теперь пользователи могут использовать CryptoPP::whatever как обычно, это карты либо CryptoPP::cxx11::whatever или CryptoPP::cxx03::whatever в зависимости от выбранного ABI.

Обратите внимание, что в руководстве GCC говорится, что этот метод изменит искаженные имена всего, что определено в помеченном встроенном пространстве имен. По моему опыту этого не происходит.

Другой метод будет помечать каждый класс, функцию и переменную __attribute__((abi_tag("cxx11"))), если _GLIBCXX_USE_CXX11_ABI отличен от нуля. Этот атрибут красиво добавляет [cxx11] к выходу демангера. Я думаю, что использование пространства имен работает так же хорошо, но требует меньше изменений в существующем коде.

В теории вы не должны дублировать всю библиотеку, только функции и классы, которые используют std::string и std::list, а функции и классы, которые используют эти функции и классы, и так далее рекурсивно. Но на практике это, вероятно, не стоит усилий, особенно если библиотека не очень большая.

+0

Спасибо @ н.м. Общий объект является проблематичным для неподготовленных компиляторов, таких как текущий Clang. Общий объект в порядке для известных компиляторов. Для несогласованных компиляторов общий объект нуждается в символах для 'CryptoPP :: cxx11 :: whatever' и' CryptoPP :: cxx03 :: whatever'. Материалы в заголовках должны быть в порядке, как вы описываете. Я по-прежнему скручиваю биты, чтобы узнать, что можно сделать, чтобы помочь несогласованным компиляторам. – jww

+0

"Общий объект требует символов для CryptoPP :: cxx11 :: whatever и CryptoPP :: cxx03 :: whatever" Да, это то, что я говорю. Вы комбинируете обе версии в одной и той же библиотеке. –

+0

Если вы хотите поддержать clang или других компиляторов, не подозревающих об abi_tag, просто не используйте '__attribute __ ((abi_tag (« cxx11 »))). –

Смежные вопросы