GLIBC中的Symbol Versioning
Posted ithiker
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GLIBC中的Symbol Versioning相关的知识,希望对你有一定的参考价值。
文章目录
前言
由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
- https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
- https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html
- https://man7.org/conf/lca2006/shared_libraries/slide19a.html#:~:text=Allows%20a%20single%20library%20to,version%20number%20of%20the%20library.
以上是关于GLIBC中的Symbol Versioning的主要内容,如果未能解决你的问题,请参考以下文章
Qt sqlite3.o: undefined reference to symbol ‘dlclose@@GLIBC_2.2.5‘
全网首发:终极解决办法:/usr/bin/ld: libcc.so: no symbol version section for versioned symbol `memcpy@GLIBC_2.0‘
[C++]共享内存cmake报错undefined reference to symbol ‘shm_unlink@@GLIBC_2.2.5
安装mysql_sniffer报错undefined reference to symbol 'pthread_setspecific@@GLIBC_2.2.5'问题
linux下开发,解决cocos2d-x中编译出现的一个小问题, undefined reference to symbol 'pthread_create@@GLIBC_2.2.5&