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 等关键字

Author: [email protected]
Date: 2017-04-01 Sat 00:00
Last updated: 2022-03-29 Tue 12:09

知识共享许可协议