Se si dichiara test1()
nascosta (__attribute__((__visibility__("hidden")))
, il salto sarà diretta.
Ora test1()
non può essere definita nella sua unità di traduzione fonte come nascosto, ma credo che nessun danno dovrebbe venire da quella discrepanza tranne il linguaggio C garantire che &test1 == &test1
possa essere danneggiato al momento dell'esecuzione se uno dei puntatori è stato ottenuto tramite un riferimento nascosto e uno tramite uno pubblico (il riferimento pubblico potrebbe essere stato interposto tramite il precaricamento o un DSO precedente a quello corrente nello scope di ricerca , mentre il riferimento nascosto (che si traduce in salti diretti) efficace impedisce qualsiasi tipo di interposizione)
Un modo più corretto per risolvere questo problema consiste nella definizione di due nomi per test1()
: un nome pubblico e un nome privato/nascosto.
In gcc e clang, questo può essere fatto con qualche magia di alias, che può essere eseguita solo nell'unità di traduzione che definisce il simbolo.
macro possono rendere più bella:
#define PRIVATE __attribute__((__visibility__("hidden")))
#define PUBLIC __attribute__((__visibility__("default")))
#define PRIVATE_ALIAS(Alias,OfWhat) \
extern __typeof(OfWhat) Alias __attribute((__alias__(#OfWhat), \
__visibility__("hidden")))
#if HERE
PUBLIC void test1(void) { }
PRIVATE_ALIAS(test1__,test1);
#else
PUBLIC void test1(void);
PRIVATE void test1__(void);
#endif
void call_test1(void) { test1(); }
void call_test1__(void) { test1__(); }
void call_ext0(void) { void ext0(void); ext0(); }
void call_ext1(void) { PRIVATE void ext1(void); ext1(); }
Le compila sopra (-O3, x86-64) in:
call_test1:
jmp [email protected]
call_test1__:
jmp test1__
call_ext0:
jmp [email protected]
call_ext1:
jmp ext1
(Definizione qui = 1 in aggiunta inlines la chiamata test1 dal momento che è piccolo e locale e -O3 è acceso).
Esempio dal vivo al https://godbolt.org/g/eZvmp7.
-fno-semantic-interposition
farà anche il lavoro, ma interromperà anche la garanzia del linguaggio C, ed è una sorta di grosso martello che non ha la granularità di aliasing.
Intendi per chiamate all'interno della tua libreria/eseguibile? Questo dovrebbe essere possibile in qualche modo, magari definendo un alias privato o qualcosa del genere. Ma per le chiamate alle funzioni nelle librerie alle quali si collega solo dinamicamente, non sono sicuro che il linker di runtime * possa * risolvere tali riferimenti. –
@PeterCordes Senza '-fpic', il linker riscrive automaticamente i riferimenti ai simboli ai riferimenti PLT ove appropriato/richiesto. Questo è il comportamento che voglio, cioè il compilatore che genera chiamate normali a tutte le funzioni e il linker riscrive le chiamate che vanno a un altro oggetto condiviso. – fuz
Does ['-fno-semantic-interposition'] (http://stackoverflow.com/questions/35745543/new-option-in-gcc-5-3-fno-semantic-interposition) fa quello che vuoi? Vedi anche http://stackoverflow.com/questions/34102989/shared-object-in-linux-without-symbol-interposition-fno-semantic-interposition. Questa domanda è una copia di entrambi? –