Linux库文件名的描述版本信息
library filename = lib + <libaray name> + .so + <libarary version information>
库版本信息通常使用以下格式:
dynamic libarary version information = <M>.<m>.<p>
其中,M用一位或多位数字表示库文件的主版本号,m用一位或多位数字表示库文件的次版本号,而p用一位或多位数字来表示库文件的修订版本号。
库的soname与库的文件名
库的文件名定义:
library filename = lib + <libaray name> + .so + <libarary version information>
库的soname定义:
library soname = lib + <libaray name> +.so + <(only the)library major version digit(s)>
很显然只要有了soname,我们就基本上可以定位某个特定的库文件名了,唯一的问题在于soname只有动态库的主版本号,并不包含完整的版本控制信息。
升级动态库时使用软链接和soname
下面列出升级动态库的过程:
1:当软链接和实际的动态库放置在一个目录下时,将软链接指向实际的动态库文件。
2:软链接的文件名与指向的动态库soname相同,这样一来,软链接实际包含的库文件名会具有松散的版本控制信息。(也就是只包含主版本信息。
3:一般来说,客户二进制文件从来不会链接文件名包含完整版本信息的动态库,相反,你会看到客户二进制文件的构建过程只会有目的性地和文件名包含库soname的文件进行链接
4:采取这种方法的原因很简单:链接时指定完整且精确的动态库版本控制信息将使我们日后无法链接同一个库的新版本,从而引发太对不必要的限制。
但在实际链接的过程中:只将库文件名传递给连接器,而不提供版本控制信息
比如:
gcc -shared <inputs> -lm -ldl -lpthread -lxmlz -lzyz -o <clientBinary>
链接过程如图所示:
soname详解
soname嵌入了二进制文件中,ELF格式预留了一块存储动态库soname信息的字段,在链接阶段,链接器将这个特殊的soname字符串写入ELF格式指定的区域中。
在构建动态库时,你可以使用一条特定的链接器选项来指定库文件的soname
gcc -shared <list of linker inputs> -wl, -soname,<soname> -o <library filename>
链接器会将指定的sonme嵌入二进制文件的DT_SONMA字段中。
gcc -fPIC -c test.c -o test.o
gcc -shared test.o -wl.-soname,libtest.so.1 -o libtest.so.1.0.0
readelf -d libtest.so.1.0.0
###################################################################
tag type Name/Value
0x00000001 (NEEDED) shared library:[libc.so.6]
0x0000000e (SONAME) Librara soname :[libtest.so.1]
###################################################################
链接器版本控制脚本
来看下基于动态库libsimple.so 的简单示例,该动态库提供了3个函数如下
simple.c
int first_function(int x)
{
return (x+1);
}
int second_function(int x)
{
return (x+2);
}
int third_function(int x)
{
return (x+3);
}
simpleVersionScript
LIBSIMPLE_1.0{
global:
first_function;second_function;
local:
*
};
最后构建动态库文件,我们可以通过以下链接器选线将版本控制器脚本文件传递给链接器使用:
gcc -fPIC -c simple.c
gcc -shared simple.o -wl,--version-script,simpleVersionScript -o libsimple.1.0.0
若后面增次版本号:只需要对前面的做细微的改动,如下图,在新的此版本号中增加了fourth_function,只需要在.c和.h增加定义声明后,在版本控制脚本加如下内容:
simpleVersionScript:
LIBSIMPLE_1.0{
global:
first_function;second_function;
local:
*
};
LIBSIMPLE_1.1{
global:
fourth_function;
local:
*
};
此时版本控制信息中不仅包含了原来的1.0版本还包含了最新的1.1版本,如图:
readelf -v libsimple.so
#####################################################################
version definition section ‘.gnu.version_d’ contains 3 enteries
0000: rec:1 Flags:BASE Index:1 Cnt:1 Name:libsimple.so.1.1
001c: rev:1 Flags:none Index:2 Cnt:1 Name:LIBSIMPLE_1.0
001c: rev:1 Flags:none Index:3 Cnt:1 Name:LIBSIMPLE_1.1
#####################################################################
若后面增改了主版本函数,如first_function
对应的代码修改如下:
simpleVersionScript:
LIBSIMPLE_1.0{
global:
first_function;second_function;
local:
*
};
LIBSIMPLE_1.1{
global:
fourth_function;
local:
*
};
LIBSIMPLE_2.0{
global:
first_function;
local:
*
};
simple.c 修改内容如下:
...
__asm__(".symver first_function_1_0,first_function@LIBSIMPLE_1.0");
int first_function(int x)
{
printf("lib:%s\n",__FUNCTION__);
return (x+1);
}
__asm__(".symver first_function_1_0,first_function@LIBSIMPLE_2.0");
int first_function(int x)
{
printf("lib:%s\n",__FUNCTION__);
return 1000*(x+1);
}
...