提交 5cb8c3fa 编写于 作者: 编程进阶之路's avatar 编程进阶之路

符号版本化

上级 726abf58
......@@ -70,4 +70,4 @@
:page 736},
:content {:text "[:span]", :image 1694437268292},
:properties {:color "purple"}}],
:extra {:page 755}}
:extra {:page 757}}
#include <stdio.h>
void xyz(void) {
printf("v1 xyz\n");
}
#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");
}
#include <stdlib.h>
int main(int argc, char *argv[]) {
void xyz(void);
xyz();
exit(EXIT_SUCCESS);
}
\ No newline at end of file
VER_1 {
global:
xyz;
local:
*;
};
\ No newline at end of file
VER_1 {
global:
xyz;
local:
*;
};
VER_2 {
global:
pqr;
} VER_1;
......@@ -227,8 +227,117 @@
```
- 可以看出 `vis_comm()` 不再对外可见了
- ## 符号版本化
collapsed:: true
- 符号版本化允许一个共享库提供同一个函数的多个版本。每个程序会使用它与共享库进行(静态)链接时函数的当前版本。这种处理方式的结果是可以对共享库进行不兼容的改动而无需提升库的主要版本号。从极端的角度来讲,符号版本化可以取代传统的共享库主要和次要版本化模型。glibc 从 2.1 开始使用了这种符号版本化技术,因此 glibc 2.0 以及之前的所有版本都是通过单个主要库版本(`libc.so.6`)来支持的
- 下面通过一个简单的例子来展示符号版本化的用途。首先使用一个版本脚本来创建共享库的第一个版本
-
- 在一个 `sv_lib_v1.c` 文件键入
- ```c
#include <stdio.h>
void xyz(void) {
printf("v1 xyz\n");
}
```
-`sv_v1.map` 中键入
- ```c
VER_1 {
global: xyz;
local: *;
};
```
- 为了使例子尽量简单点,这里没有使用显式的库 soname 和库主要版本号
- ```shell
[dyp@dyp symbolic_version]$ gcc -g -c -fPIC -Wall sv_lib_v1.c
[dyp@dyp symbolic_version]$ gcc -g -shared -o libsv.so sv_lib_v1.o -Wl,--version-script,sv_v1.map
```
- 在这个阶段,版本脚本 `sv_v1.map` 只用来控制共享库的符号的可见性,即只导出 `xyz()`,同时隐藏其他所有符号(在这个简短的例子中没有其他符号了)。接着创建一个程序 `p1` 来使用这个库
id:: 65001349-5ac5-439f-93f2-64ea09bcb0e7
- ```c
#include <stdlib.h>
int main(int argc, char *argv[]) {
void xyz(void);
xyz();
exit(EXIT_SUCCESS);
}
```
- ```shell
[dyp@dyp symbolic_version]$ gcc -g -o p1 sv_prog.c libsv.so
[dyp@dyp symbolic_version]$ ./p1
./p1: error while loading shared libraries: libsv.so: cannot open shared object file: No such file or directory
[dyp@dyp symbolic_version]$ LD_LIBRARY_PATH=. ./p1
v1 xyz
```
- 现在假设需要修改库中 `xyz()` 的定义,但同时仍然需要确保程序 `pl` 继续使用老版本的函数。为完成这个任务,必须要在库中定义两个版本的 `xyz()`。我们在 `sv_lib_v2.c` 中键入
- ```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");
}
```
- 这里两个版本的 `xyz()` 是通过函数 `xyz_old()``xyz_new()` 来实现的
- `xyz_old()` 函数对应于原来的 `xyz()` 定义,`p1` 程序应该继续使用这个函数
- `xyz_new()` 函数提供了与库的新版本进行链接的程序所使用的` xyz()` 的定义
- 修改过的版本脚本(稍后给出)中的两个 `.symver` 汇编器指令将这两个函数绑定到了两个不同的版本标签上,下面将使用这个脚本来创建共享库的新版本。第一个指令指示与版本标签 `VER_1` 进行链接的应用程序(即程序 `p1`)所使用的 `xyz()` 的实现是 `xyz_old()`,与版本标签 `VER_2` 进行链接的应用程序所使用的 `xyz()` 的实现是 `xyz_new()`
- 第二个`.symver` 指令使用`@@`(不是`@`)来指示当应用程序与这个共享库进行静态链接时应该使用的 `xyz()` 的默认定义。一个符号的 `.symver` 指令中应该只有一个指令使用 `@@` 标记
- 下面是与修改过之后的库对应的版本脚本
- ```
VER_1 {
global:
xyz;
local:
*;
};
VER_2 {
global:
pqr;
} VER_1; # 标记依赖 VER_1
```
- 这个版本脚本提供了一个新版本标签 `VER_2`,它依赖于标签` VER_1`。这种依赖关系是通过 `} VER_1;` 进行标记的
- 现在按照以往方式构建库的新版本
- ```shell
[dyp@dyp symbolic_version]$ gcc -g -c -fPIC -Wall sv_lib_v2.c
[dyp@dyp symbolic_version]$ gcc -g -shared -o libsv.so sv_lib_v2.o -Wl,--version-script,sv_v2.map
```
- 现在创建一个新程序` p2`,它使用了 `xyz()` 的新定义,同时程序 `p1` 使用了旧版的 `xyz()`
- ```shell
[dyp@dyp symbolic_version]$ gcc -g -o p2 sv_prog.c libsv.so
[dyp@dyp symbolic_version]$ LD_LIBRARY_PATH=. ./p2
v2 xyz
[dyp@dyp symbolic_version]$ LD_LIBRARY_PATH=. ./p1
v1 xyz
```
- [[$green]]==可执行文件的版本标签依赖是在静态链接时进行记录的==。使用 `objdump –t` 可以打印出每个可执行文件的符号表,从而能够显示出两个程序中不同的版本标签依赖
- ```shell
[dyp@dyp symbolic_version]$ objdump -t p1 | grep xyz
0000000000000000 F *UND* 0000000000000000 xyz@VER_1
[dyp@dyp symbolic_version]$ objdump -t p2 | grep xyz
0000000000000000 F *UND* 0000000000000000 xyz@VER_2
```
- ## 初始化和终止函数
- [[#green]]==可以定义一个或多个在 **共享库被加载和卸载时自动执行** 的函数,这样在使用共享库时就能够完成一些初始化和终止工作了==。不管库是自动被加载还是使用 `dlopen` 接口显式加载的,初始化函数和终止函数都会被执行
- 初始化和终止函数是使用 `gcc``constructor``destructor` 特性来定义的
- 在库被加载时需要执行的所有函数都应该定义成下面的形式
- ```c
```
-
-
-
-
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册