so文件解析,与dll文件的区别
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
dll和so文件区别与构成
动态链接,在可执行文件装载时或运行时,由操作系统的装载程序加载库。
大多数操作系统将解析外部引用(比如库)作为加载过程的一部分。
在这些系统上,可执行文件包含一个叫做im port directo ry的表,该表的每一项包含一个库的名字。
根据表中记录的名字,装载程序在硬盘上搜索需要的库,然后将其加载到内存中预先不确定的位置,之后根据加载库后确定的库的地址更新可执行程序。
可执行程序根据更新后的库信息调用库中的函数或引用库中的数据。
这种类型的动态加载成为装载时加载,被包括Wind ows和Li nux的大多数系统采用。
装载程序在加载应用软件时要完成的最复杂的工作之一就是加载时链接。
其他操作系统可能在运行时解析引用。
在这些系统上,可执行程序调用操作系统AP I,将库的名字,函数在库中的编号和函数参数一同传递。
操作系统负责立即解析然后代表应用调用合适的函数。
这种动态链接叫做运行时链接。
因为每个调用都会有系统开销,运行时链接要慢得多,对应用的性能有负面影响。
现代操作系统已经很少使用运行时链接。
可以动态链接的库,在Window s上是dyn amic link library(DLL),在UNIX或L inux上是Shared Library。
库文件是预先编译链接好的可执行文件,存储在计算机的硬盘上。
大多数情况下,同一时间多个应用可以使用一个库的同一份拷贝,操作系统不需要加载这个库的多个实例。
Windows和Linux 的加载时链接是由操作系统来完成的,格式在不同的系统下有不同的区别,但是原理还是一样的。
linux下文件的类型是不依赖于其后缀名的,但一般来讲:
.o,是目标文件,相当于wind ows中的.obj文件
.so 为共享库,是shared object,用于动态连接的,和dll差不多
.a为静态库,是好多个.o合在一起,用于静态连接
.la为libt ool自动生成的一些共享库,vi编辑查看,主要记录了一些配置信息。
可以用如下命令查看*.la文件的格式$file *.la
*.la: ASCII English text
所以可以用vi来查看其内容。
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
创建.a库文件和.o库文件:
[yufei@localho st perl_c2]$ pwd
/home/yufei/perl_c2
[yufei@localho st perl_c2]$ cat mylib.c
#include <stdio.h>
#include <string.h>
void hello(){
printf("success call from perl to c library\n");
[yufei@localho st perl_c2]$ cat mylib.h
externvoid hello();
[yufei@localho st perl_c2]$ gcc -c mylib.c
[yufei@localho st perl_c2]$ dir
mylib.c mylib.h mylib.o
[yufei@localho st perl_c2]$ ar -r mylib.a mylib.o
ar: 正在创建mylib.a
[yufei@localho st perl_c2]$ dir
mylib.a mylib.c mylib.h mylib.o
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
11111111111111111111111111111111111111111111111111111111111111111111 1111111111111111111111111111111
动态链接库*.so的编译与使用- -
动态库*.so在linu x下用c和c++编程时经常会碰到,最近在网站找了几篇文章介绍动态库的编译和链接,总算搞懂了这个之前一直不太了解得东东,这里做个笔记,也为其它正为动态库链接库而苦恼的兄弟们提供一点帮助。
1、动态库的编译
下面通过一个例子来介绍如何生成一个动态库。
这里有一个头文件:so_test.h,三个.c文件:test_a.c、test_b.c、test_c.c,我们将这几个文件编译成一个动态库:libtest.so。
so_test.h:
#include <stdio.h>
#include <stdlib.h>
void test_a();
void test_b();
void test_c();
test_a.c:
#include "so_test.h"
void test_a()
{
printf("this is in test_a...\n");
test_b.c:
#include "so_test.h"
void test_b()
{
printf("this is in test_b...\n");
}
test_c.c:
#include "so_test.h"
void test_c()
{
printf("this is in test_c...\n");
}
将这几个文件编译成一个动态库:libtest.so
$ gcc test_a.c test_b.c test_c.c -fPIC -shared-o libtest.so
2、动态库的链接
在1、中,我们已经成功生成了一个自己的动态链接库libtes t.so,下面我们通过一个程序来调用这个库里的函数。
程序的源文件为:test.c。
test.c:
#include "so_test.h"
int main()
{
test_a();
test_b();
test_c();
return0;
}
l将test.c与动态库li btest.so链接生成执行文件tes t:
$ gcc test.c -L. -ltest -o test
l测试是否动态连接,如果列出lib test.so,那么应该是连接正常了$ ldd test
l执行test,可以看到它是如何调用动态库中的函数的。
3、编译参数解析
最主要的是GC C命令行的一个选项:
-shared该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。
相当于一个可执行文件
l-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
l-L.:表示要连接的库在当前目录中
l-ltest:编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上li b,后面加上.so来确定库的名称
l LD_LIBR ARY_PA TH:这个环境变量指示动态连接器可以装载动态库的路径。
l当然如果有ro ot权限的话,可以修改/etc/ld.so.conf文件,然后调用/sbin/ldconfi g来达到同样的目的,不过如果没有r oot权限,那么只能采用输出LD_LI BRARY_PATH的方法了。
4、注意
调用动态库的时候有几个问题会经常碰到,有时,明明已经将库的头文件所在目录通过“-I” include进来了,库所在文件通过“-L”参数引导,并指定了“-l”的库名,但通过ldd命令察看时,就是死活找不到你指定链接的so 文件,这时你要作的就是通过修改LD_LIBR ARY_PA TH或者/etc/ld.so.conf文件来指定动态库的目录。
通常这样做就可以解决库无法链接的问题了。
makefil e里面怎么正确的编译和连接生成.so库文件,然后又是在其他程序的mak efile里面如何编译和连接才能调用这个库文件的函数
答:
你需要告诉动态链接器、加载器ld.so在哪里才能找到这个共享库,可以设置环境变量把库的路径添加到库目录/lib和/usr/lib,
LD_LIBR ARY_PA TH=$(pwd),这种方法采用命令行方法不太方便,一种替代方法^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^注释
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LD_LIBR ARY_PA TH可以在/etc/profile还是~/.profile还是./bash_pr ofile里设置,或者.bashrc里,
改完后运行so urce /etc/profile或. /etc/profile
更好的办法是添入/etc/ld.so.conf, 然后执行/sbin/ldconfi g
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^注释
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
是把库路径添加到/etc/ld.so.conf,然后以root身份运行ld config
也可以在连接的时候指定文件路径和名称-I-L.
GCC=gcc
CFLAGS=-Wall-ggdb-fPIC
#CFLAGS=
all:libfunc test
libfunc:func.o func1.o
$(GCC)-shared-Wl,-soname,libfunc.so.1-o libfunc.so.1.1$<
ln-sf libfunc.so.1.1libfunc.so.1
ln-sf libfunc.so.1libfunc.so
***********************************************注释
************************************************
ln -s是用来创建软链接,也就相当于wi ndows中的快捷方式,在当前目录中创建上一级目录中的文件tt t的命名为t tt2软链接的命令是ln -s ../ttt ttt2,如果原文件也就是ttt文件删除的话,ttt2也变成了空文件。
ln -d是用来创建硬链接,也就相当于wi ndows中文件的副本,当原文件删除的时候,并不影响“副本”的内容。
编译目标文件时使用gcc的-fPIC选项,产生与位置无关的代码并能被加载到任何地址:
gcc –fPIC –g –c liberr.c –o liberr.o
使用gcc的-shared和-soname选项;
使用gcc的-Wl选项把参数传递给连接器ld;
使用gcc的-l选项显示的连接C库,以保证可以得到所需的启动(startup)代码,从而避免程序在使用不同的,可能不兼容版本的C库的系统上不能启动执行。
gcc –g –shared–Wl,-soname,liberr.so –o liberr.so.1.0.0 liberr.o –lc
建立相应的符号连接:
ln –s liberr.so.1.0.0 liberr.so.1;
ln –s liberr.so.1.0.0 liberr.so;
在MAKEFI LE中:
$@
表示规则中的目标文件集。
在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。
$%
仅当目标是函数库文件中,表示规则中的目标成员名。
例如,如果一个目标是"foo.a(bar.o)",那么,"$%"就是"bar.o","$@"就是"foo.a"。
如果目标不是函数库文件(Unix下是[.a],Windows下是[.lib]),那么,其值为空。
$<
依赖目标中的第一个目标名字。
如果依赖目标是以模式(即"%")定义的,那么"$<"将是符合模式的一系列的文件集。
注意,其是一个一个取出来的。
$?
所有比目标新的依赖目标的集合。
以空格分隔。
$^
所有的依赖目标的集合。
以空格分隔。
如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。
*********************************************注释
******************************************************************** ***
test:test.o libfunc
$(GCC)-o test test.o-L.-lfunc
%.o:%.c
$(GCC)-c$(CFLAGS)-o$@$<
clean:
rm-fr*.o
rm-fr*.so*
rm-fr test
要生成.so文件,cc要带-shared参数;要调用.so的文件,比如libfu nc.so,可以在cc命令最后加上-lfunc,还要视情况加上-L/usr/xxx指出libfu nc.so的路径;这样,在你要编译的源文件中就可以调用libf unc.so这个库文件的函数.
前面的都说的差不多了,最后提醒一下最好提供一个接口头文件
动态加载,用dlopen,dlclose,dlsym
ref:http://niefeiidne/blog/ccid/do_show one/tid_42855.html
1. 介绍
使用GNU的工具我们如何在Linux下创建自己的程序函数库?一个“程序函数库”简单的说就是一个文件包含了一些编译好的代码和数据,这些编译好的代码和数据可以在事后供其他的程序使用。
程序函数库可以使整个程序更加模块化,更容易重新编译,而且更方便升级。
程序函数库可分为3种类型:静态函数库(staticlibrari es)、共享函数库(sharedlibrari es)和动态加载函数库(dynamic ally loadedlibrari es)。
静态函数库是在程序执行前就加入到目标程序中去了;而共享函数库则是在程序启动的时候加载到程序中,它可以被不同的程序共享;动态加载函数库则可以在程序运行的任何时候动态的加载。
实际上,动态函数库并非另外一种库函数格式,区别是动态加载函数库是如何被程序员使用的。
后面我们将举例说明。
本文档主要参考Progra m Library HOWTO,作者是lust er(**************),任何非商业目的的再次发行本文档都是允许的,但是请保留作者信息和本版权声明。
本文档首先在w ww.linuxai 发布。
2. 静态函数库
静态函数库实际上就是简单的一个普通的目标文件的集合,一般来说习惯用“.a”作为文件的后缀。
可以用ar这个程序来产生静态函数库文件。
Ar 是archiv er的缩写。
静态函数库现在已经不在像以前用得那么多了,主要是共享函数库与之相比较有很多的优势的原因。
慢慢地,大家都喜欢使用共享函数库了。
不过,在一些场所静态函数库仍然在使用,一来是保持一些与以前某些程序的兼容,二来它描述起来也比较简单。
静态库函数允许程序员把程序lin k起来而不用重新编译代码,节省了重新编译代码的时间。
不过,在今天这么快速的计算机面前,一般的程序的重新编译也花费不了多少时间,所以这个优势已经不是像它以前那么明显了。
静态函数库对开发者来说还是很有用的,例如你想把自己提供的函数给别人使用,但是又想对函数的源代码进行保密,你就可以给别人提供一个静态函数库文件。
理论上说,使用ELF格式的静态库函数生成的代码可以比使用共享函数库(或者动态函数库)的程序运行速度上快一些,大概1-5%。
创建一个静态函数库文件,或者往一个已经存在地静态函数库文件添加新的目标代码,可以用下面的命令:
ar rcs my_libr ary.a file1.o file2.o
这个例子中是把目标代码fi le1.o和file2.o加入到my_librar y.a这个函数库文件中,如果my_li brary.a不存在则创建一个新的文件。
在用ar命令创建静态库函数的时候,还有其他一些可以选择的参数,可以参加ar的使用帮助。
这里不再赘述。
一旦你创建了一个静态函数库,你可以使用它了。
你可以把它作为你编译和连接过程中的一部分用来生成你的可执行代码。
如果你用gcc来编译产生可执行代码的话,你可以用“-l”参数来指定这个库函数。
你也可以用ld来做,使用它的“-l”和“-L”参数选项。
具体用法,可以参考inf o:gcc。
3. 共享函数库
共享函数库中的函数是在当一个可执行程序在启动的时候被加载。
如果一个共享函数库正常安装,所有的程序在重新运行的时候都可以自动加载最新的函数库中的函数。
对于Linux系统还有更多的可以实现的功能:
o 升级了函数库但是仍然允许程序使用老版本的函数库。
o 当执行某个特定程序的时候可以覆盖某个特定的库或者库中指定的函数。
o 可以在库函数被使用的过程中修改这些函数库。
3.1. 一些约定
如果你要编写的共享函数库支持所有有用的特性,你在编写的过程中必须遵循一系列约定。
你必须理解库的不同的名字间的区别,例如它的“soname”和“real name”之间的区别和它们是如何相互作用的。
你同样还要知道你应该把这些库函数放在你文件系统的什么位置等等。
下面我们具体看看这些问题。
3.1.1. 共享库的命名
每个共享函数库都有个特殊的名字,称作“soname”。
Soname名字命名必须以“lib”作为前缀,然后是函数库的名字,然后是“.so”,最后是版本号信息。
不过有个特例,就是非常底层的C库函数都不是以lib开头这样命名的。
每个共享函数库都有一个真正的名字(“real name”),它是包含真正库函数代码的文件。
真名有一个主版本号,和一个发行版本号。
最后一个发行版本号是可选的,可以没有。
主版本号和发行版本号使你可以知道你到底是安装了什么版本的库函数。
另外,还有一个名字是编译器编译的时候需要的函数库的名字,这个名字就是简单的sona me名字,而不包含任何版本号信息。
管理共享函数库的关键是区分好这些名字。
当可执行程序需要在自己的程序中列出这些他们需要的共享库函数的时候,它只要用son ame就可以了;反过来,当你要创建一个新的共享函数库的时候,你要指定一个特定的文件名,其中包含很细节的版本信息。
当你安装一个新版本的函数库的时候,你只要先将这些函数库文件拷贝到一些特定的目录中,运行ldcon fig这个实用就可以。
Ldconfi g检查已经存在的库文件,然后创建son ame的符号链接到真正的函数库,同时设置/etc/ld.so.cache这个缓冲文件。
这个我们稍后再讨论。
Ldconfi g并不设置链接的名字,通常的做法是在安装过程中完成这个链接名字的建立,一般来说这个符号链接就简单的指向最新的soname或者最新版本的函数库文件。
最好把这个符号链接指向so name,因为通常当你升级你的库函数的后,你就可以自动使用新版本的函数库勒。
我们来举例看看:
/usr/lib/libread line.so.3 是一个完全的完整的sona me,ldconfi g可以设置一个符号链接到其他某个真正的函数库文件,例如是/usr/lib/libread line.so.3.0。
同时还必须有一个链接名字,例如/usr/lib/libread line.so 就是一个符号链接指向
/usr/lib/libread line.so.3。
3.1.2. 文件系统中函数库文件的位置
共享函数库文件必须放在一些特定的目录里,这样通过系统的环境变量设置,应用程序才能正确的使用这些函数库。
大部分的源码开发的程序都遵循GNU的一些标准,我们可以看in fo帮助文件获得相信的说明,info信息的位置
是:info: standar ds#Directo ry_Var iables。
GNU标准建议所有的函数库文件都放在/usr/local/lib目录下,而且建议命令可执行程序都放在/usr/local/b in目录下。
这都是一些习惯问题,可以改变的。
文件系统层次化标准FHS(Filesys tem Hierarc hy Standar d)
(http://www.pathnam /fhs)规定了在一个发行包中大部分的函数库文件应该安装到/usr/lib目录下,但是如果某些库是在系统启动的时候要加载的,则放到/lib目录下,而那些不是系统本身一部分的库则放到/usr/local/lib下面。
上面两个路径的不同并没有本质的冲突。
GNU提出的标准主要对于开发者开发源码的,而FHS的建议则是针对发行版本的路径的。
具体的位置信息可以看/etc/ld.so.conf里面的配置信息。
3.2. 这些函数库如何使用
在基于GNUglibc的系统里,包括所有的li nux系统,启动一个ELF格式的二进制可执行文件会自动启动和运行一个pro gram loader。
对于Linux系统,这个loade r的名字是/lib/ld-linux.so.X(X是版本号)。
这个loade r启动后,反过来就会load所有的其他本程序要使用的共享函数库。
到底在哪些目录里查找共享函数库呢?这些定义缺省的是放在
/etc/ld.so.conf文件里面,我们可以修改这个文件,加入我们自己的一些特殊的路径要求。
大多数RedH at系列的发行包的/etc/ld.so.conf文件里面不包括
/usr/local/lib这个目录,如果没有这个目录的话,我们可以修改/etc/ld.so.co nf,自己手动加上这个条目。
如果你想覆盖某个库中的一些函数,用自己的函数替换它们,同时保留该库中其他的函数的话,你可以在/etc/ld.so.preload中加入你想要替换的库(.o结尾的文件),这些prelo ading的库函数将有优先加载的权利。
当程序启动的时候搜索所有的目录显然会效率很低,于是Linux系统实际上用的是一个高速缓冲的做法。
Ldconfi g缺省情况下读出/etc/ld.so.conf相关信息,然后设置适当地符号链接,然后写一个ca che到/etc/ld.so.cache这个文件中,而这个/etc/ld.so.cache则可以被其他程序有效的使用了。
这样的做法可以大大提高访问函数库的速度。
这就要求每次新增加一个动态加载的函数库的时候,就要运行ldc onfig来更新这个ca che,如果要删除某个函数库,或者某个函数库的路径修改了,都要重新运行l dconfi g来更新这个cache。
通常的一些包管理器在安装一个新的函数库的时候就要运行ldcon fig。
另外,FreeBSD使用cach e的文件不一样。
FreeBSD的ELF cache
是/var/run/ld-elf.so.hints,而a.out的cac he责是/var/run/ld.so.hints。
它们同样是通过ldconf ig来更新。
3.3. 环境变量
各种各样的环境变量控制着一些关键的过程。
例如你可以临时为你特定的程序的一次执行指定一个不同的函数库。
Linux系统中,通常变量
LD_LIBR ARY_PA TH就是可以用来指定函数库查找路径的,而且这个路径通常是在查找标准的路径之前查找。
这个是很有用的,特别是在调试一个新的函数库的时候,或者在特殊的场合使用一个肥标准的函数库的时候。
环境变量
LD_PRELOA D列出了所有共享函数库中需要优先加载的库文件,功能和
/etc/ld.so.preload类似。
这些都是有/lib/ld-linux.so这个loa der来实现的。
值得一提的是,LD_LIBR ARY_PA TH可以在大部分的UNI X-linke系统下正常起作用,但是并非所有的系统下都可以使用,例如HP-UX系统下,就是用
SHLIB_P ATH这个变量,而在AIX下则使用LIBP ATH这个变量。
LD_LIBR ARY_PA TH在开发和调试过程中经常大量使用,但是不应该被一个普通用户在安装过程中被安装程序修改,大家可以去参
考/~barr/ldpath.html,这里有一个文档专门介绍为什么不使用LD_LIBRA RY_PAT H这个变量。
事实上还有更多的环境变量影响着程序的调入过程,它们的名字通常就是以LD_或者RTLD_打头。
大部分这些环境变量的使用的文档都是不全,通常搞得人头昏眼花的,如果要真正弄清楚它们的用法,最好去读loa der的源码(也就是gcc的一部分)。
允许用户控制动态链接函数库将涉及到se tuid/setgid这个函数如果特殊的功能需要的话。
因此,GNU loader通常限制或者忽略用户对这些变量使用se tuid 和s etgid。
如果loade r通过判断程序的相关环境变量判断程序的是否使用了setuid或者setgi d,如果uid和e uid不同,或者gid和e gid部一样,那么loade r就假定程序已经使用了s etuid或者setgid,然后就大大的限制器控制这个老链接的权限。
如果阅读GNU glibc的库函数源码,就可以清楚地看到这一点,特别的我们可以看elf/rtld.c和sysde ps/generic/dl-sysdep.c这两个文件。
这就意味着如果你使得uid和gid与e uid和eg id分别相等,然后调用一个程序,那么这些变量就可以完全起效。
3.4. 创建一个共享函数库
现在我们开始学习如何创建一个共享函数库。
其实创建一个共享函数库非常容易。
首先创建obj ect文件,这个文件将加入通过gcc–fPIC 参数命令加入到共享函数库里面。
PIC的意思是“位置无关代码”(Positio n Indepen dent Code)。
下面是一个标准的格式:
gcc -shared-Wl,-soname,your_so name -o library_namefile_li st library_list下面再给一个例子,它创建两个ob ject文件(a.o和b.o),然后创建一个包
含a.o和b.o的共享函数库。
例子中”-g”和“-Wall”参数不是必须的。
gcc -fPIC -g -c -Wall a.cgcc -fPIC -g -c -Wall b.cgcc -shared-Wl,
-soname,liblust erstuf f.so.1 -o liblust erstuf f.so.1.0.1 a.o b.o -lc
下面是一些需要注意的地方:
·不用使用-fomit-frame-pointer这个编译参数除非你不得不这样。
虽然使用了这个参数获得的函数库仍然可以使用,但是这使得调试程序几乎没有用,无法跟踪调试。
·使用-fPIC来产生代码,而不是-fpic。
·某些情况下,使用gcc 来生成obje ct文件,需要使用“-Wl,-export-dynamic”这个选项参数。
通常,动态函数库的符号表里面包含了这些动态的对象的符号。
这个选项在创建ELF 格式的文件时候,会将所有的符号加入到动态符号表中。
可以参考ld的帮助获得更详细的说明。
3.5. 安装和使用共享函数库
一旦你了一个共享函数库,你还需要安装它。
其实简单的方法就是拷贝你的库文件到指定的标准的目录(例如/usr/lib),然后运行ldc onfig。
如果你没有权限去做这件事情,例如你不能修改/usr/lib目录,那么你就只好通过修改你的环境变量来实现这些函数库的使用了。
首先,你需要创建这些共享函数库;然后,设置一些必须得符号链接,特别是从son ame到真正的函数库文件的符号链接,简单的方法就是运行ldco nfig:
ldconfi g -n directo ry_wit h_shar ed_lib raries
然后你就可以设置你的LD_LIBRAR Y_PATH这个环境变量,它是一个以逗号分隔的路径的集合,这个可以用来指明共享函数库的搜索路径。
例如,使用bash,就可以这样来启动一个程序m y_prog ram:
LD_LIBR ARY_PA TH=.:$LD_LIBR ARY_PA TH my_prog ram
如果你需要的是重载部分函数,则你就需要创建一个包含需要重载的函数的object文件,然后设置LD_PRELOA D环境变量。
通常你可以很方便的升级你的函数库,如果某个API改变了,创建库的程序会改变sona me。
然而,如果一个函数升级了某个函数库而保持了原来的sona me,你可以强行将老版本的
函数库拷贝到某个位置,然后重新命名这个文件(例如使用原来的名字,然后后面加.orig后缀),然后创建一个小的“wrapper”脚本来设置这个库函数和相关的东西。
例如下面的例子:
#!/bin/sh exportLD_LIBR ARY_PA TH=/usr/local/my_lib:$LD_LIBR ARY_PA TH exec
/usr/bin/my_prog ram.orig $*
我们可以通过运行ldd来看某个程序使用的共享函数库。
例如你可以看l s 这个实用工具使用的函数库:
ldd /bin/ls
libterm cap.so.2 => /lib/libterm cap.so.2 (0x4001c000)
libc.so.6 => /lib/libc.so.6 (0x40020000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
通常我么可以看到一个son ame的列表,包括路径。
在所有的情况下,你都至少可以看到两个库:
· /lib/ld-linux.so.N(N是1或者更大,一般至少2)。
这是这个用力加载其他所有的共享库的库。
· libc.so.N(N应该大于或者等于6)。
这是C语言函数库。
值得一提的是,不要在对你不信任的程序运行ldd命令。
在ldd的ma nual 里面写得很清楚,ldd是通过设置某些特殊的环境变量(例如,对于ELF对象,设置LD_TR ACE_LO ADED_O BJECTS),然后运行这个程序。
这样就有可能使得某地程序可能使得ldd来执行某些意想不到的代码,而产生不安全的隐患。
3.6. 不兼容的函数库
如果一个新版的函数库要和老版本的二进制的库不兼容,则soname需要改变。
对于C语言,一共有4个基本的理由使得它们在二进制代码上很难兼容:
o. 一个函数的行文改变了,这样它就可能与最开始的定义不相符合。
o. 输出的数据项改变了。
o. 某些输出的函数删除了。
o. 某些输出函数的接口改变了。
如果你能避免这些地方,你就可以保持你的函数库在二进制代码上的兼容,或者说,你可以使得你的程序的应用二进制接口(ABI:Applica tion BinaryInterfa ce)上兼容。
4. 动态加载的函数库Dynam ically Loaded(DL) Librari es
动态加载的函数库Dynam ically loaded(DL) librari es是一类函数库,它可以在程序运行过程中的任何时间加载。
它们特别适合在函数中加载一些模块和pl ugin扩展模块的场合,因为它可以在当程序需要某个plugin模块时才动态的加载。
例如,Pluggab le Authent icatio n Modules(PAM)系统就是用动态加载函数库来使得管理员可以配置和重新配置身份验证信息。
Linux系统下,DL函数库与其他函数库在格式上没有特殊的区别,我们前面提到过,它们创建的时候是标准的ob ject格式。
主要的区别就是这些函数库不是在程序链接的时候或者启动的时候加载,而是通过一个A PI来打开一个函数库,寻找符号表,处理错误和关闭函数库。
通常C语言环境下,需要包含这个头文件。
Linux中使用的函数和S olaris中一样,都是dlpoe n()API。
当时不是所有的平台都使用同样的接口,例如HP-UX使用shl_load()机制,而Window s平台用另外的其他的调用接口。
如果你的目的是使得你的代码有很强的移植性,你应该使用一些wrappi ng函数库,这样的wrap ping函数库隐藏不同的平台的接口区别。
一种方法是使用glibc函数库中的对动态加载模块的支持,它使用一些潜在的动态加载函数库界面使得它们可以夸平台使用。
具体可以参考h ttp:
//develop /doc/API/glib/glib-dynamic-loading-of-modules.html. 另外一个方法是使用libl tdl,是GNU libtool的一部分,可以进一步参考CORBA相关资料。
4.1. dlopen()
dlopen函数打开一个函数库然后为后面的使用做准备。
C语言原形是:void * dlopen(const char *filenam e, int flag);。