Ci è stato recentemente chiesto di spedire una versione Linux di una delle nostre librerie, in precedenza abbiamo sviluppato sotto Linux e spedito per Windows dove la distribuzione di librerie è generalmente molto più semplice. Il problema che abbiamo riscontrato è quello di rimuovere i simboli esportati solo verso quelli nell'interfaccia esposta. Ci sono tre buoni motivi per voler fare questoStripping librerie condivise di linux
- Per proteggere gli aspetti proprietari della nostra tecnologia dall'esposizione attraverso i simboli esportati.
- Per evitare che gli utenti abbiano problemi con nomi di simboli in conflitto.
- Per velocizzare il caricamento della libreria (almeno così mi è stato detto).
Prendendo un esempio semplice allora:
test.cpp
#include <cmath>
float private_function(float f)
{
return std::abs(f);
}
extern "C" float public_function(float f)
{
return private_function(f);
}
compilato con (g ++ 4.3.2, ld 2.18.93.20081009)
g++ -shared -o libtest.so test.cpp -s
e di ispezione delle simboli con
nm -DC libtest.so
dà
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
ovviamente inadeguata. Così la prossima abbiamo ridichiarare la funzione pubblica come
extern "C" float __attribute__ ((visibility ("default")))
public_function(float f)
e compilare con
g++ -shared -o libtest.so test.cpp -s -fvisibility=hidden
che dà
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
che è buono, se non che std :: abs è esposto. Più problematico è quando iniziamo il collegamento in altre librerie (statiche) al di fuori del nostro controllo, tutti i simboli che usiamo da quelle librerie vengono esportati. Inoltre, quando iniziare a usare contenitori STL:
#include <vector>
struct private_struct
{
float f;
};
void other_private_function()
{
std::vector<private_struct> v;
}
si finisce con molte esportazioni aggiuntivi dalla libreria 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: Con ottimizzazioni su Avrai bisogno di assicurarsi che il vettore è effettivamente utilizzato in modo che il compilatore non ottimizzi i simboli non utilizzati.
Credo che la mia collega è riuscito a costruire una soluzione ad hoc che coinvolgono file di versione e modificando le intestazioni STL che sembra funzionare, ma vorrei chiedere (!):
C'è un modo pulito rimuovere tutti i simboli non necessari (quelli che non fanno parte della funzionalità della libreria esposta) da una libreria condivisa Linux? Ho provato un sacco di opzioni per g + + e ld con scarso successo quindi preferirei le risposte che funzionano meglio di quanto si creda.
In particolare:
- Simboli (closed-source) librerie statiche non vengono esportati.
- I simboli della libreria standard non vengono esportati.
- I simboli non pubblici dai file oggetto non vengono esportati.
La nostra interfaccia è esportato C.
sono a conoscenza delle altre domande simili su SO:
- NOT sharing all classes with shared library
- How to REALLY strip a binary in MacOs
- GNU linker: alternative to --version-script to list exported symbols at the command line?
ma h ave avuto poco successo con le risposte.
Sul collegamento statico delle librerie di sistema: è illegale per voi farlo. Cioè, poiché [(e)] (http://www.eglibc.org/) [GLIBC] (http://www.gnu.org/software/libc/) è concesso in licenza in [LGPL] (http://opensource.org/licenses/LGPL-3.0) e dal momento che tale licenza si applica a tutto il codice che lo utilizza eccetto se collegato dinamicamente, collegando staticamente il codice viene coperto da LGPL e viene richiesto di fornire le fonti (a chiunque abbia dato il binario e chiedono delle fonti). Questo non si applica a libgcc e libstdC++, che in particolare non si applicano a nessun codice utilizzando solo API pubbliche, indipendentemente dal collegamento. –
Ne sono a conoscenza, e non mi riferivo ai simboli di glibc, tutti i simboli sopra sono generati dall'istanza dei template dalla libreria standard C++ e sono, per necessità, generati nei miei file oggetto (poiché le istanze dei template possono ' essere in biblioteca!). –