Version Script
Table of Contents
1. Version Script
1.1. 声明 global, local 符号
与 gcc 的 visibility attribute 功能类似
$> cat v.map { global: foo; local: *; }; $> cat test.c void foo() {} void bar() {} $> gcc -shared test.c -Wl,--version-script,vb.map $> readelf -a ./a.out Symbol table '.dynsym' contains 6 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND ... 5: 000000000000050a 7 FUNC GLOBAL DEFAULT 11 foo
1.2. 定义符号的 version
$> cat v.map LIBTEST_V1.0 { global: foo; local: *; }; LIBTEST_V1.1 { global: bar; local: *; }; $> cat test.c void foo() { printf("foo from LIBTEST_V1.0\n"); } void bar() { printf("bar from libTEST_V1.1\n"); } $> cat main.c extern void foo(); extern void bar(); int main(int argc, char *argv[]) { foo(); bar(); } $> gcc -shared test.c -Wl,--version-script,v.map -o libtest.so $> gcc main.c ./libtest.so $> readelf -a ./a.out Symbol table '.dynsym' contains 9 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND ... 2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND bar@LIBTEST_V1.1 (2) ... 7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND foo@LIBTEST_V1.0 (4) ...
1.3. .symver directive
除了使用 version script, gcc 允许使用 .symver directive 在代码中指定 version
$> cat v.map LIBTEST_V1.0 { }; LIBTEST_V1.1 { }; $> cat test.c __asm__ (".symver foo, foo@LIBTEST_V1.0"); void foo() { printf("foo from LIBTEST_V1.0\n"); } __asm__ (".symver bar, bar@LIBTEST_V1.1"); void bar() { printf("bar from libTEST_V1.1\n"); } $> cat main.c __asm__(".symver foo, foo@LIBTEST_V1.0"); __asm__(".symver bar, bar@LIBTEST_V1.1"); extern void foo(); extern void bar(); int main(int argc, char *argv[]) { foo(); bar(); } $> gcc -shared test.c -o libtest.so $> gcc main.c ./libtest.so $> readelf -a ./a.out Symbol table '.dynsym' contains 13 entries: Num: Value Size Type Bind Vis Ndx Name ... 3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND bar@LIBTEST_V1.1 (3) ... 5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND foo@LIBTEST_V1.0 (4) ...
1.3.1. 使用 .symver directive 实现同一个函数的多个版本
$> cat v.map LIBTEST_V1.0 { }; LIBTEST_V1.1 { }; $> cat test.c __asm__ (".symver foo1, foo@LIBTEST_V1.0"); void foo1() { printf("foo from LIBTEST_V1.0\n"); } __asm__ (".symver foo2, foo@LIBTEST_V1.1"); void foo2() { printf("foo from libTEST_V1.1\n"); } $> cat main.c __asm__(".symver foo, foo@LIBTEST_V1.0"); extern void foo(); int main(int argc, char *argv[]) { foo(); } $> ./a.out foo from LIBTEST_V1.0 $> cat main.c __asm__(".symver foo, foo@LIBTEST_V1.1"); extern void foo(); int main(int argc, char *argv[]) { foo(); } $> ./a.out foo from libTEST_V1.1 $> readelf -a libtest.so Symbol table '.dynsym' contains 17 entries: Num: Value Size Type Bind Vis Ndx Name ... 6: 000000000000073d 19 FUNC GLOBAL DEFAULT 13 foo@LIBTEST_V1.1 ... 9: 000000000000072a 19 FUNC GLOBAL DEFAULT 13 foo@LIBTEST_V1.0 ...
Backlinks
GCC Attribute (GCC Attribute > visibility): 通过 Version Script, 也可以控制符号的 visibility. 另外, linkage 也会影响符号的 visibility, 例如 inline, static 等关键字