關鍵詞:--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\n", 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沒有匹配上。