前言
由glibc编译得到的动态库是libc.so, glibc可以通过改变soname来发布新的版本,比如libc.so.6等等, 在实际中, 改变soname通常是大的发布, 如果需要一些小的改动,可以通过Symbol Versioning的方式实现.
一、Symbol Versioning的作用
Symbol Versioning主要有以下作用:
- 允许同一个库中导出单个符号的多个实现,也就是说对于同一个函数声明,可以有多个实现版本
- 不同的程序可以在链接时决定使用特定的版本
- 可以不用改变soname, 来发布新的库(非兼容性的)
当然symbol versioning不仅仅可以使用在glibc中,也可以使用到其它c语言的代码中.
二、Symbol Versioning的使用
这里按照Reference 3中的例子,来说明如何使用symbol versioning:
- 首先定义一个函数以及它的version map 文件, 编译这个文件并生成动态库:
bash$ cat sv_lib_v1.c #include <stdio.h> void xyz(void) { printf("v1 xyz\n"); } bash$ cat sv_v1.map VER_1 { global: xyz; local: *; # Hide all other symbols }; bash$ gcc -g -c -fPIC -Wall sv_lib_v1.c bash$ gcc -g -shared -o libsv.so sv_lib_v1.o -Wl,--version-script,sv_v1.map
- 运行程序, 该程序使用生成的动态库中VER_1的xyz的函数:
bash$ cat sv_prog.c #include <stdlib.h> int main(int argc, char *argv[]) { void xyz(void); xyz(); exit(EXIT_SUCCESS); } bash$ gcc -g -o p1 sv_prog.c libsv.so
- 修改动态库的源文件增加一个新的xyz实现:
上面源文件中的汇编指令分别说明了xyz_old是VER_1版本的xyz函数的实现, xyz_new是VER_2版本的xyz函数的实现; sv_v2.map是新的symbol versioning map. 重新生成新的binary:$ cat sv_lib_v2.c #include <stdio.h> __asm__(".symver xyz_old,xyz@VER_1"); __asm__(".symver xyz_new,xyz@@VER_2"); void xyz_old(void) { printf("v1 xyz\n"); } void xyz_new(void) { printf("v2 xyz\n"); } void pqr(void) { printf("v2 pqr()\n"); } bash$ cat sv_v2.map VER_1 { global: xyz; local: *; # Hide all other symbols }; VER_2 { global: xyz; pqr; local: *; # Hide all other symbols }; bash$ gcc -g -c -fPIC -Wall sv_lib_v2.c bash$ gcc -g -shared -o libsv.so sv_lib_v2.o -Wl,--version-script,sv_v2.map
运行:$ gcc -g -o p2 sv_prog.c libsv.so.1
这里, 我们如果删除最初的libsv.so, 然后运行p1, 会发现找不到库, 但是如果继续添加一个libsv.so软链接到lib.sv.so.1, 则可以运行成功:$ LD_LIBRARY_PATH=. ./p2 v2 xyz $ LD_LIBRARY_PATH=. ./p1 v1 xyz
这是因为libsv.so.1中含有VER_1的xyz和VER_2的xyz:$ mv libsv.so libsv.so.bak $ LD_LIBRARY_PATH=. ./p1 ./p1: error while loading shared libraries: libsv.so: cannot open shared object file: No such file or directory $ ln -sf libsv.so.1 libsv.so $ LD_LIBRARY_PATH=. ./p1 v1 xyz
$ readelf -W --dyn-syms libsv.so.1 | grep @ 3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.2.5 (4) 7: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.2.5 (4) 8: 0000000000000709 18 FUNC GLOBAL DEFAULT 12 pqr@@VER_2 11: 00000000000006f7 18 FUNC GLOBAL DEFAULT 12 xyz@@VER_2 12: 00000000000006e5 18 FUNC GLOBAL DEFAULT 12 xyz@VER_1
Reference
版权声明:本文为gigglesun原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。