Usuwanie współdzielonych bibliotek linuxowych
Niedawno zostaliśmy poproszeni o wysłanie wersji Linuksa jednej z naszych bibliotek, wcześniej opracowywaliśmy ją pod Linuksem i wysyłaliśmy dla Windows, gdzie wdrażanie bibliotek jest na ogół dużo łatwiejsze. Problem, na który się natknęliśmy, polega na pozbyciu się eksportowanych symboli tylko do tych znajdujących się w odsłoniętym interfejsie. Istnieją trzy dobre powody, dla których chcesz to zrobić
Aby chronić zastrzeżone aspekty naszej technologii przed ekspozycją poprzez eksportowane symbole.Aby zapobiec problemom użytkowników z konfliktowymi nazwami symboli.Aby przyspieszyć ładowanie biblioteki (przynajmniej tak mi się mówi).Weźmy prosty przykład:
test.cpp
#include <cmath>
float private_function(float f)
{
return std::abs(f);
}
extern "C" float public_function(float f)
{
return private_function(f);
}
skompilowany z (g ++ 4.3.2, ld 2.18.93.20081009)
g++ -shared -o libtest.so test.cpp -s
i sprawdzanie symboli za pomocą
nm -DC libtest.so
daje
w _Jv_RegisterClasses
0000047c T private_function(float)
000004ba W std::abs(float)
0000200c A __bss_start
w __cxa_finalize
w __gmon_start__
0000200c A _edata
00002014 A _end
00000508 T _fini
00000358 T _init
0000049b T public_function
oczywiście niewystarczające. Tak więc, ponownie określamy funkcję publiczną jako
extern "C" float __attribute__ ((visibility ("default")))
public_function(float f)
i skompiluj z
g++ -shared -o libtest.so test.cpp -s -fvisibility=hidden
co daje
w _Jv_RegisterClasses
0000047a W std::abs(float)
0000200c A __bss_start
w __cxa_finalize
w __gmon_start__
0000200c A _edata
00002014 A _end
000004c8 T _fini
00000320 T _init
0000045b T public_function
co jest dobre, z wyjątkiem tego, że std :: abs jest odsłonięty. Bardziej problematyczne jest, gdy zaczynamy linkowanie w innych (statycznych) bibliotekach poza naszą kontrolą,wszystkie symbole, których używamy z tych bibliotek, zostaną wyeksportowane. Ponadto, gdy zaczynamy używać kontenerów STL:
#include <vector>
struct private_struct
{
float f;
};
void other_private_function()
{
std::vector<private_struct> v;
}
kończymy na wielu dodatkowych eksportach z biblioteki C ++
00000b30 W __gnu_cxx::new_allocator<private_struct>::deallocate(private_struct*, unsigned int)
00000abe W __gnu_cxx::new_allocator<private_struct>::new_allocator()
00000a90 W __gnu_cxx::new_allocator<private_struct>::~new_allocator()
00000ac4 W std::allocator<private_struct>::allocator()
00000a96 W std::allocator<private_struct>::~allocator()
00000ad8 W std::_Vector_base<private_struct, std::allocator<private_struct> >::_Vector_impl::_Vector_impl()
00000aaa W std::_Vector_base<private_struct, std::allocator<private_struct> >::_Vector_impl::~_Vector_impl()
00000b44 W std::_Vector_base<private_struct, std::allocator<private_struct> >::_M_deallocate(private_struct*, unsigned int)
00000a68 W std::_Vector_base<private_struct, std::allocator<private_struct> >::_M_get_Tp_allocator()
00000b08 W std::_Vector_base<private_struct, std::allocator<private_struct> >::_Vector_base()
00000b6e W std::_Vector_base<private_struct, std::allocator<private_struct> >::~_Vector_base()
00000b1c W std::vector<private_struct, std::allocator<private_struct> >::vector()
00000bb2 W std::vector<private_struct, std::allocator<private_struct> >::~vector()
NB: W przypadku optymalizacji należy upewnić się, że wektor jest rzeczywiście używany, aby kompilator nie optymalizował nieużywanych symboli.
Uważam, że mój kolega zdołał zbudować rozwiązanie ad hoc obejmujące pliki wersji i modyfikujące nagłówki STL (!), Które wydają się działać, ale chciałbym zapytać:
Czy istnieje czysty sposób, aby usunąć wszystkie niepotrzebne symbole (te z IE, które nie są częścią ujawnionej funkcjonalności biblioteki) z biblioteki współdzielonej linux? Próbowałem wiele opcji zarówno dla g ++, jak i ld z małym powodzeniem, więc wolę odpowiedzi, o których wiadomo, że działają, a nie wierzą.
W szczególności:
Symbole z bibliotek statycznych (z zamkniętym źródłem) nie są eksportowane.Symbole z biblioteki standardowej nie są eksportowane.Symbole niepubliczne z plików obiektowych nie są eksportowane.Nasz eksportowany interfejs to C.
Jestem świadomy innych podobnych pytań dotyczących SO:
NIE współdzielenie wszystkich klas z biblioteką współdzielonąJak NAPRAWDĘ usunąć binarny plik w MacOGNU linker: alternatywa dla skryptu --version do wyświetlenia wyeksportowanych symboli w wierszu poleceń?ale nie udało się uzyskać odpowiedzi.