Skip to content

Latest commit

 

History

History
264 lines (206 loc) · 7.97 KB

201507241022.txt.md

File metadata and controls

264 lines (206 loc) · 7.97 KB

16.15 制作so文件时如何指定导出哪些符号

http://scz.617.cn/unix/201507241022.txt

Q:

制作so文件只想导出几个函数,其余函数不导出,就像Windows下dll一样。

A: Ulrich Drepper [email protected] 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

$ vi test_0.c


#include <stdio.h> #include <stdlib.h>

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修饰符。

$ vi test_1.c


#include <stdio.h> #include <stdlib.h>

#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。

$ vi test_2.c


#include <stdio.h> #include <stdlib.h>

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

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上就是无效。