2016-06-21 15 views
2

ich ein Beispielprogramm wie dieses:Klirren - Symbol Sichtbarkeit funktioniert nicht wie erwartet

#include <stdio.h> 

#if 1 
#define FOR_EXPORT __attribute__ ((visibility("hidden"))) 
#else 
#define FOR_EXPORT 
#endif 

FOR_EXPORT void mylocalfunction1(void) 
{ 
    printf("function1\n"); 
} 

void mylocalfunction2(void) 
{ 
    printf("function2\n"); 
} 

void mylocalfunction3(void) 
{ 
    printf("function3\n"); 
} 

void printMessage(void) 
{ 
    printf("Running the function exported from the shared library\n"); 
} 

Und es

gcc -shared -fPIC -fvisibility=hidden -o libdefaultvisibility.so defaultvisibility.c 

nun nach der Kompilierung mit kompilieren ich tun:

$ nm libdefaultvisibility.so 
nm libdefaultvisibility.so 
0000000000000eb0 t _mylocalfunction1 
0000000000000ed0 t _mylocalfunction2 
0000000000000ef0 t _mylocalfunction3 
0000000000000f10 t _printMessage 
       U _printf 
       U dyld_stub_binder 

Das heißt, soweit ich das beurteilen kann, werden trotz -fvisibility=hidden alle Symbole exportiert. Das Buch, dem ich folgte, behauptete, dass nur die mit FOR_EXPORT markierte Funktion exportiert werden sollte.

Ich schaute outp mehrere andere Ressourcen, aber für den einfachen Test, den ich tue -fvisibility=hidden sollte ausreichen.

Meine Klirren Version:

$ clang -v 
clang -v 
Apple LLVM version 7.3.0 (clang-703.0.31) 
Target: x86_64-apple-darwin15.0.0 
Thread model: posix 
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin 

Antwort

5

Sie die Ausgabe von nm Missverständnis. Blättern Sie durch man nm und Sie werden Sie lesen, dass das t Flag bedeutet, das Symbol ist ein lokales (statisches) Symbol in der text Abschnitt. Der Linker kann es nicht sehen. Wenn es global (extern) wäre, wäre die Flagge T. Alle vier Funktionen sind also lokal.

Kontrast:

$ clang -shared -fPIC -fvisibility=hidden -o libdefaultvisibility.so defaultvisibility.c 
$ nm libdefaultvisibility.so | grep ' t ' 
0000000000000570 t deregister_tm_clones 
0000000000000600 t __do_global_dtors_aux 
0000000000200e08 t __do_global_dtors_aux_fini_array_entry 
0000000000000640 t frame_dummy 
0000000000200e00 t __frame_dummy_init_array_entry 
0000000000000670 t mylocalfunction1 
0000000000000690 t mylocalfunction2 
00000000000006b0 t mylocalfunction3 
00000000000006d0 t printMessage 
00000000000005b0 t register_tm_clones 

mit den -fvisibility=hidden fallen:

$ clang -shared -fPIC -o libdefaultvisibility.so defaultvisibility.c 
$ nm libdefaultvisibility.so | grep ' t ' 
0000000000000600 t deregister_tm_clones 
0000000000000690 t __do_global_dtors_aux 
0000000000200e08 t __do_global_dtors_aux_fini_array_entry 
00000000000006d0 t frame_dummy 
0000000000200e00 t __frame_dummy_init_array_entry 
0000000000000700 t mylocalfunction1 
0000000000000640 t register_tm_clones 
$ nm libdefaultvisibility.so | grep ' T ' 
0000000000000780 T _fini 
00000000000005b0 T _init 
0000000000000720 T mylocalfunction2 
0000000000000740 T mylocalfunction3 
0000000000000760 T printMessage 

Dann nur die explizit versteckt mylocalfunction1 lokal bleibt, und die anderen drei sind jetzt global.

Sie sollten nicht erwarten, dass ein mit __attribute__ ((visibility("hidden"))) markiertes Symbol unter allen Umständen von einer gemeinsam genutzten Bibliothek exportiert wird.Das Attribut bedeutet genau , dass es nicht sein wird, ob es explizit auf ein Symbol angewendet wird, wie in diesem Fall oder standardmäßig in Anwesenheit der Linkeroption -fvisibility=hidden erworben wird.

Wenn Sie nur, dass eine Funktion in dem Beispiel mittels einer visibility Zuschreibung exportieren möchten würden Sie haben:

#define FOR_EXPORT __attribute__ ((visibility("default"))) 

Dann:

$ clang -shared -fPIC -fvisibility=hidden -o libdefaultvisibility.so defaultvisibility.c 
$ nm libdefaultvisibility.so | grep ' T ' 
0000000000000720 T _fini 
0000000000000550 T _init 
00000000000006a0 T mylocalfunction1 

Es ist global, weil die explizite Die Zuweisung überschreibt die Befehlszeilenoption und alle anderen Funktionen sind lokal. Vielleicht verwirrend, default Sichtbarkeit ist immer public.

Und man könnte dies zu erreichen, ohne visibility Aufgaben an eine Zuflucht - die sind nicht tragbar - einfach alle Funktionen erklärt, die Sie tun nicht als static exportieren möchten. Dann wird der Compiler würde sich an den Linker in erster Linie nicht aussetzen:

foo.c

#include <stdio.h> 

void mylocalfunction1(void) 
{ 
    printf("function1\n"); 
} 

static void mylocalfunction2(void) 
{ 
    printf("function2\n"); 
} 

static void mylocalfunction3(void) 
{ 
    printf("function3\n"); 
} 

static void printMessage(void) 
{ 
    printf("Running the function exported from the shared library\n"); 
} 

, mit dem Sie wieder bekommen: -

$ clang -shared -fPIC -o libfoo.so foo.c 
$ nm libfoo.so | grep ' T ' 
00000000000006c0 T _fini 
0000000000000550 T _init 
00000000000006a0 T mylocalfunction1 

Obwohl der Unterschied tut Machen Sie sich in Ihrem Beispiel nicht bemerkbar Sie sollten verstehen, dass während ein lokales/statisches Symbol nicht vom Linker gesehen wird und (daher) nicht für dynamisch verfügbar ist Verknüpfung, ein globales/externes Symbol kann oder kann nicht für dynamische Verknüpfung verfügbar sein. visibility steuert die Verfügbarkeit von globalen Symbolen für dynamische Verknüpfung, nur.

+0

Danke, in der Tat habe ich die Ausgabe von 'nm' missverstanden, vor allem in Bezug auf' T' vs 't'. Es hat tatsächlich wie erwartet funktioniert. Das Buch, das ich lese, ist ziemlich kurz, um die Ausgabe von 'nm' zu interpretieren, und deshalb war ich mir nicht wirklich sicher, was ich sah. Diese Antwort hat es für mich geklärt. – Max

1

Nach GCC Wiki auf Sichtbarkeit, sollten Sie:

Verwenden nm -C -D auf dem ausgegebenen DSO [Dynamic Shared Object] vor und nach dem zu vergleichen, um zu sehen, der Unterschied macht es.

Wie auf nm Handbuch angegeben:

-D wird die dynamische Symbole angezeigt werden, anstatt die normalen Symbole

Wenn ich den Code genau kompilieren, wie Sie habe ich die folgenden Objekte erhalten :

$ nm -C -D libdefaultvisibility.so 
nm -C -D libdefaultvisibility.so 
0000000000200a68 B __bss_start 
       w __cxa_finalize 
0000000000200a68 D _edata 
0000000000200a70 B _end 
00000000000006c8 T _fini 
       w __gmon_start__ 
0000000000000518 T _init 
       w _ITM_deregisterTMCloneTable 
       w _ITM_registerTMCloneTable 
       w _Jv_RegisterClasses 
       U puts 

Und wenn ich es ohne diekompiliereOption erhalte ich die Objekte:

$ nm -C -D libdefaultvisibility.so 
nm -C -D libdefaultvisibility.so 
0000000000200ae8 B __bss_start 
       w __cxa_finalize 
0000000000200ae8 D _edata 
0000000000200af0 B _end 
0000000000000748 T _fini 
       w __gmon_start__ 
00000000000005a0 T _init 
       w _ITM_deregisterTMCloneTable 
       w _ITM_registerTMCloneTable 
       w _Jv_RegisterClasses 
0000000000000712 T mylocalfunction2 
0000000000000724 T mylocalfunction3 
0000000000000736 T printMessage 
       U puts