关键词:--version-script、Symbol Versioning等等。
gcc提供了Symbol Versioning,通过对Symbol进行版本化,可以达到symbol级别的兼容性检查。
1. 概要介绍
Symbol Versinoning只适用于动态库,首先对需要Versioning的Symbol通过--version-script指定,进行Versioning。
然后引用者可以指定所需要的Symbol并指定Version。
最后在运行时,动态库加载时会对Symbol和Version进行匹配,失败后会报错并停止加载运行。
2. 相关参考文档
- GCC官方关于Symbol Versioning介绍:《Symbol Versioning》,这里介绍了三篇相关文档:
- Symbol Versioning实现细节《ELF Symbol Versioning》:Symbol Versioning相关结构体;动态加载器如何进行Version检查,以及错误处理;如何进行符号查找。
- 介绍如何使用Symbol Versioing《VERSION Command》。
- 《How To Write Shared LIbraries》的3.3 ABI Versioning。
- 以及:《带版本号的符号 versioned symbol》、《An example of Linux/glibc symbol versioning》
3. 示例
3.1 创建示例程序
目录结构如下,主程序main.c,以及库文件liba和CMakeLists.txt。
├── CMakeLists.txt
├── liba
│ ├── a.c
│ ├── a.h
│ └── a.lds
└── main.c
CMakeLists.txt:
cmake_minimum_required(VERSION 3.0) project(versionsymbol C CXX) set(A_SRCS "") include_directories("${PROJECT_SOURCE_DIR}/liba/") file(GLOB_RECURSE A_SRCS ${PROJECT_SOURCE_DIR}/liba/*.c) file(GLOB_RECURSE A_LDS ${PROJECT_SOURCE_DIR}/liba/a.lds) message(${A_LDS}) add_library(a SHARED ${A_SRCS}) target_link_libraries(a "-Wl,--version-script=${A_LDS}") set(MAIN_SRCS "") file(GLOB_RECURSE MAIN_SRCS ${PROJECT_SOURCE_DIR}/main.c) add_executable(main ${MAIN_SRCS}) target_link_libraries(main a)
liba:
a.c: #include <stdio.h> int func_versioning() { return 1; } a.h: int func_versioning(); a.lds: VER_1.0{ func_versioning; };
main:
#include <stdio.h> #include <a.h> int main(void) { printf("func_versioning()=%d ", func_versioning()); }
3.2 测试1
首先编译VER_1.0版本的func_with_version,查看main和lib.so的符号:
File: liba.so Symbol table '.dynsym' contains 14 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND ... 8: 0000000000000000 0 OBJECT GLOBAL DEFAULT ABS VER_1.0 9: 0000000000201028 0 NOTYPE GLOBAL DEFAULT 23 _end 10: 00000000000006c0 11 FUNC GLOBAL DEFAULT 12 func_versioning@@VER_1.0 ... Symbol table '.symtab' contains 56 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND ... 46: 00000000000006c0 11 FUNC GLOBAL DEFAULT 12 func_versioning ... File: main Symbol table '.dynsym' contains 21 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND ... 3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND func_versioning@VER_1.0 (4) ... 9: 0000000000000000 0 OBJECT GLOBAL DEFAULT ABS VER_1.0 ... Symbol table '.symtab' contains 70 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND ... 56: 0000000000000000 0 FUNC GLOBAL DEFAULT UND func_versioning@@VER_1.0 ...
即可生成带版本号的符号。
修改a.lds为:
VER_2.0{ func_versioning; };
然后用VER_1.0的main和VER_2.0的liba.so:
./main_1.0: /home/al/versioned_symbol/liba.so: version `VER_1.0' not found (required by ./main_1.0)
用VER_2.0的main和VER_1.0的liba.so:
./main_2.0: /home/al/versioned_symbol/liba.so: version `VER_2.0' not found (required by ./main_2.0)
这是检查Versioning版本号没有报错。
3.3 测试2
增加一个函数:
#include <stdio.h> int func_versioning() { return 1; } int func2_versioning() { return 1; }
前后两次修改a.lds后如下:
VER_1.0{ func_versioning; func2_versioning; }; VER_2.0{ };
再次:
VER_1.0{ func2_versioning; }; VER_2.0{ func_versioning; };
执行结果如下:
./main_1.0: relocation error: ./main_1.0: symbol func_versioning, version VER_1.0 not defined in file liba.so with link time reference
这是检查到了Versioning版本号,但是对应符号func_versioning的VER_1.0没有匹配上。