16.15 制作so文件时如何指定导出哪些符号 https://scz.617.cn/unix/201507241022.txt Q: 制作so文件只想导出几个函数,其余函数不导出,就像Windows下dll一样。 A: Ulrich Drepper 2005-01-22 一般来说至少有四种办法: 1) static 2) __attribute__ ((visibility("hidden"))) 3) Export Maps 4) libtool: -export-symbols (实测无效) 更详细的介绍参看下文: How To Write Shared Libraries http://people.redhat.com/drepper/dsohowto.pdf A: scz 2015-07-24 10:22 虽然下面以可执行程序举例,但相关技术同样适用于共享库。 $ gcc --version gcc (Debian 4.9.2-10) 4.9.2 1) $ vi test_0.c -------------------------------------------------------------------------- #include #include static unsigned int bar ( void ) { return( 100 ); } /* end of bar */ int main ( int argc, char * argv[] ) { unsigned int a, b; a = bar(); b = ( unsigned int )rand(); return( a + b ); } /* end of main */ -------------------------------------------------------------------------- $ gcc -Wl,--export-dynamic -Wall -pipe -O0 -s -o test_0 test_0.c $ gcc -rdynamic -Wall -pipe -O0 -s -o test_0 test_0.c "-Wl,--export-dynamic"与"-rdynamic"等效。 $ readelf -Ws test_0 Symbol table '.dynsym' contains 20 entries: Num: Value Size Type Bind Vis Ndx Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 1: 00000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTable 2: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 3: 00000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.0 (2) 4: 00000000 0 FUNC GLOBAL DEFAULT UND rand@GLIBC_2.0 (2) 5: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 6: 00000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable 7: 080498d8 0 NOTYPE GLOBAL DEFAULT 24 _edata 8: 080498d0 0 NOTYPE GLOBAL DEFAULT 24 __data_start 9: 080498dc 0 NOTYPE GLOBAL DEFAULT 25 _end 10: 080498d0 0 NOTYPE WEAK DEFAULT 24 data_start 11: 080486ac 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used 12: 08048620 97 FUNC GLOBAL DEFAULT 13 __libc_csu_init 13: 080484e0 0 FUNC GLOBAL DEFAULT 13 _start 14: 080486a8 4 OBJECT GLOBAL DEFAULT 15 _fp_hw 15: 080498d8 0 NOTYPE GLOBAL DEFAULT 25 __bss_start 16: 080485e5 50 FUNC GLOBAL DEFAULT 13 main 17: 08048474 0 FUNC GLOBAL DEFAULT 11 _init 18: 08048690 2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini 19: 08048694 0 FUNC GLOBAL DEFAULT 14 _fini $ nm -D test_0 080486ac R _IO_stdin_used w _ITM_deregisterTMCloneTable w _ITM_registerTMCloneTable w _Jv_RegisterClasses 080498d8 B __bss_start 080498d0 D __data_start w __gmon_start__ 08048690 T __libc_csu_fini 08048620 T __libc_csu_init U __libc_start_main 080498d8 D _edata 080498dc B _end 08048694 T _fini 080486a8 R _fp_hw 08048474 T _init 080484e0 T _start 080498d0 W data_start 080485e5 T main U rand 符号bar未被导出,因为用了static修饰符。 2) $ vi test_1.c -------------------------------------------------------------------------- #include #include #define EXPORT __attribute__ ((visibility("default"))) EXPORT unsigned int bar ( void ) { return( 100 ); } /* end of bar */ int main ( int argc, char * argv[] ) { unsigned int a, b; a = bar(); b = ( unsigned int )rand(); return( a + b ); } /* end of main */ -------------------------------------------------------------------------- $ gcc -rdynamic -fvisibility=hidden -Wall -pipe -O0 -s -o test_1 test_1.c "-fvisibility=hidden"将缺省visibility由default改为hidden,test_1.c中没有明 确EXPORT的符号便不会导出。 $ readelf -Ws test_1 Symbol table '.dynsym' contains 20 entries: Num: Value Size Type Bind Vis Ndx Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 1: 00000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTable 2: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 3: 00000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.0 (2) 4: 00000000 0 FUNC GLOBAL DEFAULT UND rand@GLIBC_2.0 (2) 5: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 6: 00000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable 7: 080498d8 0 NOTYPE GLOBAL DEFAULT 24 _edata 8: 080485db 10 FUNC GLOBAL DEFAULT 13 bar 9: 080498d0 0 NOTYPE GLOBAL DEFAULT 24 __data_start 10: 080498dc 0 NOTYPE GLOBAL DEFAULT 25 _end 11: 080498d0 0 NOTYPE WEAK DEFAULT 24 data_start 12: 080486ac 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used 13: 08048620 97 FUNC GLOBAL DEFAULT 13 __libc_csu_init 14: 080484e0 0 FUNC GLOBAL DEFAULT 13 _start 15: 080486a8 4 OBJECT GLOBAL DEFAULT 15 _fp_hw 16: 080498d8 0 NOTYPE GLOBAL DEFAULT 25 __bss_start 17: 08048478 0 FUNC GLOBAL DEFAULT 11 _init 18: 08048690 2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini 19: 08048694 0 FUNC GLOBAL DEFAULT 14 _fini $ nm -D test_1 080486ac R _IO_stdin_used w _ITM_deregisterTMCloneTable w _ITM_registerTMCloneTable w _Jv_RegisterClasses 080498d8 B __bss_start 080498d0 D __data_start w __gmon_start__ 08048690 T __libc_csu_fini 08048620 T __libc_csu_init U __libc_start_main 080498d8 D _edata 080498dc B _end 08048694 T _fini 080486a8 R _fp_hw 08048478 T _init 080484e0 T _start 080485db T bar 080498d0 W data_start U rand 与Export Maps技术相比,visibility技术生成的代码更高效,hidden的函数不经过 PLT。 3) $ vi test_2.c -------------------------------------------------------------------------- #include #include unsigned int bar ( void ) { return( 100 ); } /* end of bar */ int main ( int argc, char * argv[] ) { unsigned int a, b; a = bar(); b = ( unsigned int )rand(); return( a + b ); } /* end of main */ -------------------------------------------------------------------------- $ vi test_2.map -------------------------------------------------------------------------- { global : bar; _IO_stdin_used; local : *; }; -------------------------------------------------------------------------- $ gcc -Wl,--version-script=test_2.map -rdynamic -Wall -pipe -O0 -s -o test_2 test_2.c Export Maps必须与-rdynamic一起使用,否则无意义。 test_2.map中额外指定了_IO_stdin_used,否则该符号不会被导出,而test_1导出了 该符号。这是个啥,有必要导出吗? $ readelf -Ws test_2 Symbol table '.dynsym' contains 6 entries: Num: Value Size Type Bind Vis Ndx Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 1: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 2: 00000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.0 (2) 3: 00000000 0 FUNC GLOBAL DEFAULT UND rand@GLIBC_2.0 (2) 4: 0804840b 10 FUNC GLOBAL DEFAULT 13 bar 5: 080484dc 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used $ nm -D test_2 080484dc R _IO_stdin_used w __gmon_start__ U __libc_start_main 0804840b T bar U rand 4) libtool的"-export-symbols"是传说中的第4种方案,据我实测无效。 $ vi test_2.sym -------------------------------------------------------------------------- bar _IO_stdin_used -------------------------------------------------------------------------- $ libtool --mode=compile gcc -Wall -pipe -O0 -c -o test_3.o test_2.c $ libtool --mode=link gcc -export-symbols test_2.sym -rdynamic -Wall -pipe -O0 -s -o test_3 test_3.o 或 $ libtool --mode=link gcc -export-symbols-regex "^bar" -rdynamic -Wall -pipe -O0 -s -o test_4 test_2.c "-export-symbols"或"-export-symbols-regex"直接被忽略了。放狗搜了一下,好像 在Linux上就是无效。