C语言dll和so文件区别与重组

动态链接,在可执行文件装载时要运行时,由操作系统的装载程序加载库。大多数操作系统将分析外部引用(比如库)作为加载过程的一模一样组成部分。在这些系统上,可执行文件包含一个称import
 
directory的阐明,该表的诸一样宗包含一个仓库底名。根据表中记录的讳,装载程序于硬盘上找用的堆栈,然后将该加载到内存中预先不确定的位置,之后因加载库后确定的堆栈底地方更新可执行程序。可执行程序根据更新后底库信息调用库中的函数或引用库中之数据。这种类型的动态加载成为装载时加载
 
,被连Windows和Linux的多数体系利用。装载程序于加载应用软件时要到位的最好复杂的办事有就是是加载时链接。
 

   

 
其他操作系统可能以运行时分析引用。在这些网及,可执行程序调用操作系统API,将仓库的名,函数在库房中的编号和函数参数一同传递。操作系统负责及时解析然后表示采取调用合适的函数。这种动态链接叫做运行时链接
 
。因为每个调用都见面来网出,运行时链接要磨磨蹭蹭得差不多,对用的属性有负面影响。现代操作系统已经死少使运行时链接。
 

   

  可以动态链接的堆栈,在Windows上是dynamic   link   library  
(DLL),在UNIX或Linux上是Shared  
Library。库文件是先编译链接好的可执行文件,存储在电脑的硬盘上。大多数气象下,同一时间多个应用可采取一个仓房的同样份拷贝,操作系统不需加载是库房的基本上独实例。
 

   

  Windows   和   Linux  
的加载时链接是由于操作系统来形成的,格式在不同的系统下起两样之分,但是原理还是一样的。

linux下文件的类别是匪靠让该后缀名的,但一般来讲:

.o,是目标文件,相当给windows中之.obj文件

.so 为共享库,是shared object,用于动态连接的,和dll差不多

.a也静态库,是诸多独.o合在一起,用于静态连接

.la为libtool自动生成的一对共享库,vi编辑查看,主要记录了部分配置信息。可以就此如下命令查看*.la文件之格式
  $file *.la

      *.la: ASCII English text

因此可以为此vi来查看该情节。

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

创建.a库文件与.o库文件:

[yufei@localhost perl_c2]$ pwd

/home/yufei/perl_c2

[yufei@localhost perl_c2]$ cat mylib.c

#include <stdio.h>

#include <string.h>

void hello(){

        printf(“success call from perl to c library\n”);

}

[yufei@localhost perl_c2]$ cat mylib.h

extern void hello();

[yufei@localhost perl_c2]$ gcc -c mylib.c

[yufei@localhost perl_c2]$ dir

mylib.c  mylib.h  mylib.o

[yufei@localhost perl_c2]$ ar -r mylib.a mylib.o

ar: 正在创建 mylib.a

[yufei@localhost perl_c2]$ dir

mylib.a  mylib.c  mylib.h  mylib.o

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111

动态链接库*.so的编译和下- –

                                      

动态库*.so在linux下用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、中,我们都成十分成了一个谈得来的动态链接库libtest.so,下面我们由此一个次来调用这个库里的函数。程序的源文件为:test.c。

test.c:

#include “so_test.h”

int main()

{

    test_a();

    test_b();

    test_c();

    return 0;

}

l         将test.c与动态库libtest.so链接生成执行文书test:

$ gcc test.c -L. -ltest -o test

l         测试是否动态连接,如果列有libtest.so,那么该是接二连三正常了

$ ldd test

l         执行test,可以望它是哪调用动态库中之函数的。

3、编译参数解析

极致要的凡GCC命令行的一个精选:

          -shared
该选择指定生成动态连接库(让连接器生成T类型的导出符号表,有时候为生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当给一个可执行文件

l        
-fPIC:表示编译为位置独立的代码,不用此选项之语编译后的代码是岗位相关的用动态载入时凡通过代码拷贝的措施来满足不同进程的消,而无克上确实代码段共享的目的。

l         -L.:表示若连续的库在当前目录中

l        
-ltest:编译器查找动态连接库时有隐含的命名规则,即当吃有之名前加上lib,后面加上.so来确定库底称

l        
LD_LIBRARY_PATH:这个环境变量指示动态连接器可以载动态库的途径。

l         当然如果发root权限的话,可以改/etc/ld.so.conf文件,然后调用
/sbin/ldconfig来达成同等的目的,不过要没root权限,那么只能动用输出LD_LIBRARY_PATH的法门了。

4、注意

     
 调用动态库的时光起几乎独问题会时时遇到,有时,明明已以仓库底腔文件所在目录
通过 “-I” include进来了,库所在文件通过
“-L”参数引导,并点名了“-l”的库名,但由此ldd命令察看时,就是铁板钉钉找不至你指定链接的so文件,这时你一旦发的便是由此修改
LD_LIBRARY_PATH或者/etc/ld.so.conf文件来指定动态库的目录。通常这样做就好化解仓库无法链接的问题了。

makefile里面怎么是的编译和连接生成.so库文件,然后以是于其余程序的makefile里面如何编译和连接才能够调用这个库房文件之函数????

答:

     
 你要报动态链接器、加载器ld.so在哪才会找到这个共享库,可以装环境变量把库房底门径上加到仓库目录/lib和/usr/lib,LD_LIBRARY_PATH=$(pwd),这种措施应用命令执行措施无顶有利,一种替代方式

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^注释^^^^^^^^^^^^^^^^^^^^^^^^^^^^

LD_LIBRARY_PATH可以在/etc/profile还是 ~/.profile还是
./bash_profile里设置,或者.bashrc里,

变更了后运行source /etc/profile或 . /etc/profile

再次好的法是添入/etc/ld.so.conf, 然后执行 /sbin/ldconfig

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^注释^^^^^^^^^^^^^^^^^^^^^^^^^^^^

凡是管仓库路径上加到/etc/ld.so.conf,然后为root身份运行ldconfig

      也得以当连接的当儿指定文件路径和名 -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.1 libfunc.so.1

        ln -sf libfunc.so.1 libfunc.so

***********************************************注释************************************************

ln
-s是为此来创造软链接,也就是相当给windows中之快捷方式,在当前目录中创造及一级目录中之公文ttt的命名也ttt2脆弱链接的命是ln
-s ../ttt ttt2,如果原本文件也就算是ttt文件去的话,ttt2吧成了空文件。

ln
-d是为此来创造硬链接,也便相当给windows中文件之副本,当原文件去的当儿,并无影响“副本”的内容。

编译目标文件时以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;

在MAKEFILE中:

$@

   
表示规则中之靶子文件集。在模式规则中,如果产生差不多独对象,那么,”$@”就是匹配于目标被模式定义的联谊。

$%

   
仅当对象是函数库文件中,表示规则中的目标成员叫。例如,如果一个靶是”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的公文,比如libfunc.so,可以以cc命令最后加上-lfunc,还要看看情形增长
-L/usr/xxx
指出libfunc.so的门道;这样,在你如编译的源文件中即得调用libfunc.so这个库房文件之函数.

       前面的都说的几近了,最后提醒一下最好好提供一个接口头文件

       动态加载,用dlopen,dlclose,dlsym

 

ref:http://niefei.blog.ccidnet.com/blog/ccid/do\_showone/tid\_42855.html

  1. 介绍

  使用GNU的家伙我们怎么在Linux下开创和谐之程序函数库?一个“程序
函数库”简单的说哪怕是一个文书包含了一些编译好之代码和数码,这些编
译好之代码和多少好当此后供应其他的次采取。程序函数库可以要全程序更加模块化,更易重新编译,而且还有利于升级。程序函数库可分为3栽类型:静态函
数库(static libraries)、共享函数库(shared
libraries)和动态加载函数库(dynamically loaded libraries)。

  静态函数库是当程序执行前即进入到目标程序中失去了;而同步享函数库则是当程序启动的时节加载到程序中,它可被
不同之次第共享;动态加载函数库则好当程序运行的另外时刻动态的加载。实际上,动态函数库并非另外一种库函数格式,区别是动态加载函数库是怎给程序员
使用的。后面我们以举例说明。

  本文档主要参考Program Library
HOWTO,作者是luster(hwang@ustc.edu),任何非商业目的的重新发行本文档都是容的,但是要保留作者信息和本版权声明。本文档首先以www.linuxaid.com.cn发布。

  2. 静态函数库

 
 静态函数库实际上就简单的一个家常的对象文件之集结,一般的话习惯用“.a”作为文件之后缀。可以用ar这个顺序来闹静态函数库文件。Ar
是archiver的缩写。静态函数库现在早就休在比如以前用得那基本上矣,主要是同享函数库与之相较有很多底优势的来由。慢慢地,大家还欢喜以共享函数
库了。不过,在有场合静态函数库仍然在运,一来是维持有以及原先某些程序的相当,二来它描述起来呢比较简单。

  静态库函数允许程序
员把程序link起来而休用更编译代码,节省了还编译代码的日。不过,在今日这般快的微处理器面前,一般的次第的重新编译也花不了聊日子,所以
这个优势就不是诸如它原先那么显著了。静态函数库对开发者来说要不行有因此的,例如你想将团结提供的函数给他人用,但是还要想对函数的源代码进行保密,你虽
可以给他人提供一个静态函数库文件。理论及说,使用ELF格式的静态库函数生成的代码可以比较采用共享函数库(或者动态函数
库)的程序运行速度直达抢有,大概1-5%。

  创建一个静态函数库文件,或者为一个既存在地静态函数库文件上加新的靶子代码,可以为此底的一声令下:

ar rcs my_library.a file1.o file2.o

 
 这个事例中凡是将目标代码file1.o同file2.o加入到my_library.a这个函数库文件中,如果my_library.a不有
则创建一个初的公文。在用ar命令创建静态库函数的时光,还闹任何一些足以选择的参数,可以到ar的下帮助。这里不再赘述。

  一旦
你创造了一个静态函数库,你可以运用它了。你可将她当做你编译和连接过程中之平等组成部分据此来特别成你的只是实行代码。如果你用gcc来编译产生而
执行代码的话,你可以用“-l”参数来指定这个库函数。你吧足以为此ld来举行,使用它们的“-l”和“-L”参数选项。具体用法,可以参见info:gcc。

 3. 共享函数库

  共享函数库中之函数是在当一个可执行程序在起步之上让加载。如果一个共享函数库正常安装,所有的次第于再度运行的时候都可自行加载最新的函数库中的函数。对于Linux系统还有更多的足实现的效力:

o 升级了函数库但是仍然允许程序用老版本的函数库。 o
当尽某特定程序的时节可挂有特定的库或者库中指定的函数。 o
可以在库函数被以的历程中改这些函数库。

  3.1. 部分约定

 
 如果你而编制的共享函数库支持具有发生因此的特点,你以编排的历程遭到须以相同多元约定。你不能不明白库的异之讳中的界别,例如它的
“soname”和“real
name”之间的分别与其是怎相互作用的。你同样还要懂得您该拿这些库函数放在你文件系统的什么职位等等。下面我们具体看这些问题。

  3.1.1. 联袂享库的命名

  每个共享函数库都起个奇特的讳,称作“soname”。Soname名字命名必须为“lib”作为前缀,然后是函数库底名字,然后是“.so”,最后是本号信息。不过出个特例,就是非常底层的C库函数都无是因lib开头如此命名的。

  每个共享函数库都产生一个确的讳(“real
name”),它是带有真正库函数代码的公文。真名来一个主版本号,和一个批发版本号。最后一个发行版本号是可选的,可以无。主版本号和发行本号要你可以理解您到底是安了哟版本的库函数。

除此以外,还有一个名是编译器编译的当儿要之函数库的讳,这个名字即简的soname名字,而未含有其他版本号信息。

 
 管理共享函数库的要害是分好这些名。当可执行程序需要在融洽之次序中列有这些他们需要之共享库函数的时节,它如果用soname就好了;
反过来,当你若创造一个初的共享函数库底时,你要指定一个一定的文书称,其中含很细节之版本信息。当您安装一个新本子的函数库底时节,你若先拿这些
函数库文件拷贝到部分特定的目录中,运行ldconfig这个实用就足以。Ldconfig检查就是的库文件,然后创建soname的记号链接到实在
的函数库,同时设置/etc/ld.so.cache这个缓冲文件。这个我们稍后又讨论。

  Ldconfig并无装链接的名字,通常
的做法是于设置过程遭到好这个链接名字的确立,一般的话这符号链接就是概括的对准最新的soname
或者最新版本的函数库文件。最好拿这符号链接指向soname,因为一般当您升官而的库函数的后,你不怕得自行使用新本子的函数库勒。

  我们来比喻看看:

   /usr/lib/libreadline.so.3
是一个通通的完好的soname,ldconfig可以安装一个符号链接到其他有真正的函数库文件,例如是
/usr/lib/libreadline.so.3.0。同时还得出一个链接名字,例如/usr/lib/libreadline.so
就是一个号链接指向/usr/lib/libreadline.so.3。

3.1.2. 文件系统中函数库文件之位置

 
 共享函数库文件要放在有特定的目里,这样经过系统的环境变量设置,应用程序才会对的下这些函数库。大部分之源码开发之主次都以
GNU的部分正规,我们好看info帮助文件获得信任的征,info信息的职务是:info:
standards#Directory_Variables。GNU标准建议具有的函数库文件还放在/usr/local/lib目录下,而且建议命令
可执行程序都放在/usr/local/bin目录下。这还是片习以为常问题,可以转移的。

  文件系统层次化标准FHS(Filesystem Hierarchy
Standard)(http://www.pathname.com/fhs)规定了在一个发行包中大部分的函数库文件应该安装到/usr/lib目录
下,但是如果某些库是以系统启动的上要加载的,则坐/lib目录下,而那些无是系统自身有之库则放到/usr/local/lib下面。

  上面两独途径的不比并没实质的闯。GNU提出的正统要对开发者开发源码的,而FHS的提议则是本着批发本的门路的。具体的位置信息可以看/etc/ld.so.conf里面的配置信息。

  3.2. 这些函数库如何采取

   以冲GNU
glibc的系统里,包括持有的linux系统,启动一个ELF格式的二进制可执行文件会自行启动暨周转一个program
loader。对于Linux系统,这个loader的讳是/lib/ld-linux.so.X(X是版本号)。这个loader启动后,反过来就会见
load所有的外本程序要使用的共享函数库。

  到底在怎样目录里找并享函数库呢?这些概念缺省之是置身
/etc/ld.so.conf文件中,我们可改者文件,加入我们和好的组成部分
特殊之门路要求。大多数RedHat系列的批发包的/etc/ld.so.conf文件之中未包/usr/local/lib这个目录,如果没有此目
录的话,我们得以改/etc/ld.so.conf,自己手动加上这个条款。

  如果您想蒙某库中之组成部分函数,用好的函数替换其,同时保留该库中任何的函数的言语,你可以在/etc/ld.so.preload中入你想使替换的库(.o结尾的公文),这些preloading的库函数将起先加载的权。

 
 当程序启动之早晚找所有的目录明确会效率很没有,于是Linux系统实际上用的凡一个速缓冲的做法。Ldconfig缺省景下念出
/etc/ld.so.conf相关信息,然后设置适当地记链接,然后写一个cache到/etc/ld.so.cache这个文件中,而这个
/etc/ld.so.cache则好给外程序中之运了。这样的做法得以大大提高访问函数库的速。这便要求每次新添一个动态加载的函数库底常常
候,就要运行ldconfig来更新是cache,如果要抹某个函数库,或者某函数库底门道修改了,都设重新运行ldconfig来更新是
cache。通常的片承保管理器在设置一个初的函数库的下将运行ldconfig。

  另外,FreeBSD使用cache的文书不一样。FreeBSD的ELF
cache是/var/run/ld-elf.so.hints,而a.out的cache责是/var/run/ld.so.hints。它们同样是通过ldconfig来更新。

  3.3. 环境变量

 
 各种各样的环境变量控制正在有些主要之长河。例如你得临时为公一定的次序的同等次施行指定一个见仁见智之函数库。Linux系统中,通常变量
LD_LIBRARY_PATH就是得为此来指定函数库查找路径的,而且以此路通常是在探寻标准的路线之前找。这个是非常有因此底,特别是在调试一个新的
函数库底时光,或者当特的场子以一个肥标准的函数库的下。环境变量LD_PRELOAD列出了拥有共享函数库中需先加载的库文件,功能跟
/etc/ld.so.preload类似。这些都是有/lib/ld-linux.so这个loader来实现之。值得一提的是,
LD_LIBRARY_PATH可以于大多数底UNIX-linke系统下健康起作用,但是不要有的系统下还可行使,例如HP-UX系统下,就是用
SHLIB_PATH这个变量,而在AIX下虽动用LIBPATH这个变量。

  LD_LIBRARY_PATH以开发以及调剂过程被常常大量施用,但是非应有叫一个普通用户在安装过程被为安装程序修改,大家好去参考
http://www.visi.com/~barr/ldpath.html,这里有一个文档专门介绍为什么不使用LD\_LIBRARY\_PATH这个
变量。

  事实上还有再多的环境变量影响着程序的调入过程,它们的名便就是盖LD_或者RTLD_一马当先。大部分这些环境变量的利用的文档都是未统,通常为得人头昏目眩的,如果只要实在做明白她的用法,最好去读loader的源码(也尽管是gcc的平等片)。

 
 允许用户控制动态链接函数库将关乎到setuid/setgid这个函数如果非常规之效力需要的话。因此,GNU
loader通常限制还是忽视用户指向这些变量使用setuid和setgid。如果loader通过判断程序的相关环境变量判断程序的是否用了
setuid或者setgid,如果uid和euid不同,或者gid和egid部一样,那么loader就设程序都采取了setuid或者
setgid,然后就是大妈的限制器控制是老链接的权能。如果看GNU
glibc的库函数源码,就足以解地看出就一点,特别之我们可看elf/rtld.c和sysdeps/generic/dl-sysdep.c这半
个文本。这虽意味着如果你让uid和gid与euid和egid分别相当于,然后调用一个序,那么这些变量就得完全起效。

3.4. 开立一个共享函数库

 
 现在我们开始攻读怎么创造一个共享函数库。其实创建一个共享函数库非常容易。首先创建object文件,这个文件拿入通过gcc
–fPIC 参数命令在到共享函数库里面。PIC的意思是“位置无关代码”(Position
Independent Code)。下面是一个正式的格式:

gcc -shared -Wl,-soname,your_soname -o library_name file_list
library_list

  下面又被一个事例,它创建两只object文件(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,liblusterstuff.so.1 -o liblusterstuff.so.1.0.1 a.o b.o -lc

  下面是一些急需注意的地方:

·
不用采用-fomit-frame-pointer这个编译参数除非您只能这样。虽然使用了这个参数获得的函数库仍然可以利用,但是及时令调试程序几乎
没有用,无法跟踪调试。 · 使用-fPIC来发生代码,而不是-fpic。 ·
某些情况下,使用gcc
来生成object文件,需要利用“-Wl,-export-dynamic”这个选项参数。通常,动态函数库底标记表里面包含了这些动态的目标的符。
这个选项在创造ELF格式的公文上,会以享有的记号加入到动态符号表中。可以参见ld的扶持获得重新详尽的征。

  3.5. 装与使用共享函数库

  一旦而了一个共享函数库,你还需设置她。其实简单的章程就是拷贝你的库文件到指定的专业的目(例如/usr/lib),然后运行ldconfig。

 
 如果你莫权限去做这件工作,例如你无克改/usr/lib目录,那么你不怕不得不通过修改你的环境变量来促成这些函数库底采取了。首先,你要
创建这些共享函数库;然后,设置有须要得符号链接,特别是打soname到确实的函数库文件的记链接,简单的措施就是是运行ldconfig:

ldconfig -n directory_with_shared_libraries

  然后您就算可装你的LD_LIBRARY_PATH这个环境变量,它是一个坐逗号分隔的路的汇,这个可用来指明共享函数库底寻路径。例如,使用bash,就得如此来启动一个程序my_program:

LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH my_program

 
 如果您要的凡重载部分函数,则你就算得创造一个暗含需要重载的函数的object文件,然后设置LD_PRELOAD环境变量。通常你可以很
方便之晋级而的函数库,如果有API改变了,创建库底主次会改变soname。然而,如果一个函数升级了某个函数库而保持了原来的soname,你可
强行以总版的函数库拷贝到某某位置,然后重新命名这个文件(例如利用原来的名字,然后后面加.orig后缀),然后创建一个稍微的“wrapper”脚本
来装是库函数和连锁的物。例如下面的例证:

#!/bin/sh export
LD_LIBRARY_PATH=/usr/local/my_lib:$LD_LIBRARY_PATH exec

/usr/bin/my_program.orig $*

  我们可以通过运行ldd来拘禁有程序用的共享函数库。例如你得关押ls这个实用工具使用的函数库:

ldd /bin/ls

    libtermcap.so.2 => /lib/libtermcap.so.2 (0x4001c000)

    libc.so.6 => /lib/libc.so.6 (0x40020000)

    /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

  通常我么可以视一个soname的列表,包括路径。在颇具的动静下,你还至少得看出零星只仓库:

· /lib/ld-linux.so.N(N是1或者再次怪,一般至少2)。

马上是这个奋力加载其他有的共享库的堆栈。

· libc.so.N(N应该大于或者等于6)。这是C语言函数库。

 
 值得一提的凡,不要当对您莫信赖的程序运行ldd命令。在ldd的manual里面写得格外懂得,ldd是通过安装某些特殊之环境变量(例如,对
于ELF对象,设置LD_TRACE_LOADED_OBJECTS),然后运行是顺序。这样就算发出或令某地程序可能让ldd来施行某些意想不到的
代码,而发出不安全的隐患。

3.6. 请勿兼容的函数库

  如果一个新本子的函数库要跟老版本的二进制的仓库不般配,则soname需要变更。对于C语言,一共来4独核心的理由让它以二进制代码上老麻烦兼容:

  o. 一个函数的做改变了,这样它们便可能和顶开始之概念不相互契合。

  o. 输出的数据项改成了。

  o. 某些输出的函数删除了。

  o. 某些输出函数的接口改变了。

  如果您可知免这些地方,你便足以维持你的函数库在二进制代码上的配合,或者说,你可使得你的程序的采用二进制接口(ABI:Application
Binary Interface)上配合。

  4. 动态加载的函数库Dynamically Loaded (DL) Libraries

   动态加载的函数库Dynamically loaded (DL)
libraries是千篇一律看似函数库,它可以程序运行过程遭到的其余时间加载。它们特别吻合当函数中加载一些模块和plugin扩展模块的场合,因为它好在
当程序用有plugin模块时才动态的加载。例如,Pluggable Authentication
Modules(PAM)系统就是用动态加载函数库来让管理员可以安排与重新配置身份验证信息。

  Linux系统下,DL函数库与那个
他函数库在格式上尚无异常的别,我们前面提到过,它们创建的时节是正式的object格式。主要的分别就是是
这些函数库不是当次链接的当儿要启动之时光加载,而是通过一个API来开辟一个函数库,寻找符号表,处理错误和关函数库。通常C语言环境下,需要保证
含这个腔文件。

  Linux中采用的函数和Solaris中相同,都是dlpoen()
API。当时非是颇具的阳台都采取同一的接口,例如HP-UX使用shl_load()机制,而Windows平台用另外的另外的调用接口。如果你的目的
是使得你的代码有好强的移植性,你应有采取一些wrapping函数库,这样的wrapping函数库隐藏不同之平台的接口区别。一栽方式是采用
glibc函数库中之指向动态加载模块的支撑,它以一些潜在的动态加载函数仓房界面使得其可夸平台使用。具体可参见http:
//developer.gnome.org/doc/API/glib/glib-dynamic-loading-of-modules.html.
另外一个艺术是动libltdl,是GNU
libtool的同一有,可以更加参考CORBA相关资料。

  4.1. dlopen()

  dlopen函数打开一个函数库然后呢后面的运做准备。C语言原形是:

void * dlopen(const char *filename, int flag);

  如果文件名filename是盖“/”开头,也便是以绝对路径,那么dlopne就一直以其,而未错过探寻某些环境变量或者系统安装的函数库所在的目了。否则dlopen()

  就见面照下面的主次查找函数库文件:

  1. 环境变量LD_LIBRARY指明的路子。 2. /etc/ld.so.cache着的函数库列表。
    3.
    /lib目录,然后/usr/lib。不过有些很老的a.out的loader则是使相反的次序,也就算是先查/usr/lib,然后是/lib。

 
 Dlopen()函数中,参数flag的价必须是RTLD_LAZY或者RTLD_NOW,RTLD_LAZY的意是resolve
undefined symbols as code from the dynamic library is
executed,而RTLD_NOW的含义是resolve all undefined symbols before
dlopen() returns and fail if this cannot be done’。

  如果出一些独函数库,它们中发生部分因关系之言语,例如X依赖Y,那么你就算设先加载那些吃据之函数。例如先加载Y,然后加载X。

  dlopen()函数的返回值是一个句柄,然后后面的函数就经过下此句子柄来做越的操作。如果打开失败dlopen()就回一个NULL。如果一个函数库被反复打开,它会回同样的句柄。

  如果一个函数库里面来一个出口的函数名字吧_init,那么_init就见面于dlopen()这个函数返回前给实施。我们得以采取是函数在自家的函数库里面做片初始化的做事。我们后会延续讨论这个题材之。

  4.2. dlerror()

  通过调用dlerror()函数,我们好取得最终一不行调整用dlopen(),dlsym(),或者dlclose()的错误信息。

4.3. dlsym()

  如果你加载了一个DL函数库而不失采用本是匪容许的了,使用一个DL函数库的极度关键的一个函数就是dlsym(),这个函数在一个都打开的函数库里面找给定的符。这个函数如下概念:

void * dlsym(void *handle, char *symbol);

  函数中之参数handle就是由于dlopen打开后归来的句柄,symbol是一个盖NIL结尾的字符串。

 
 如果dlsym()函数没有找到需要寻找的symbol,则回NULL。如果您懂得有symbol的价值不可能是NULL或者0,那么就算老大
好,你便足以根据是返回结果判断查找的symbol是否是了;不过,如果某个symbol的价就是NULL,那么是判断即便来问题了。标准的判定方法
是事先调用dlerror(),清除以前或许存在的错误,然后调用dlsym()来拜会一个symbol,然后还调用dlerror()来判定是否出现了错
误。一个名列前茅的过程如下:

dlerror();

s = (actual_type) dlsym(handle, symbol_being_searched_for);

if ((err = dlerror()) != NULL)

{

}

else

{

}

  4.4. dlclose()

 
 dlopen()函数的反过程就是dlclose()函数,dlclose()函数用力关闭一个DL函数库。Dl函数库维持一个资源利用的计数
器,当调用dlclose的当儿,就拿这个计数器的计数减一,如果计数器为0,则委的放走掉。真正释放的时段,如果函数库里面有_fini()这个函
数,则自动调用_fini()这个函数,做有必要的处理。Dlclose()返回0表示成功,其他非0值表示错误。

  4.5. DL Library Example

  下面是一个例。例子中调入math函数库,然后打印2.0之余弦函数值。例子中老是都检查是否出错。应该是独科学的范例:

  #include

  #include

  #include

  int main(int argc, char **argv)

  {

    void *handle;

    double (*cosine)(double);

    char *error;

    handle = dlopen (“/lib/libm.so.6”, RTLD_LAZY);

    if (!handle) {

        fputs (dlerror(), stderr);

        exit(1);

    }

    cosine = dlsym(handle, “cos”);

    if ((error = dlerror()) != NULL)

  {

        fputs(error, stderr);

        exit(1);

    }

    printf (“%f “, (*cosine)(2.0));

    dlclose(handle);

}

  如果这个程序名字让foo.c,那么用脚的吩咐来编译:

  gcc -o foo foo.c -ldl

  1. 其他

  5.1. nm命令

 
 nm命令可以列出一个函数库文件被的符号表。它于静态的函数库和共享的函数库都起作用。对于一个加的函数库,nm命令可以列出函数库中定义
的具备符号,包括每个符号的价值与类别。还足以为有当原程序中是函数(符号)是当小行定义的,不过就不能不要求编译该函数库的上加“-l”选项。

 
 关于符号的种,这里我们重多讨论一下。符号的路是以一个字母的款式显得的,小写字母表示这标记是本地(local)的,而杀写字母则表示
这个符号是全局的(global,externel)。一般的话,类型有瞬间几种植:T、D、B、U、W。各自的义如下:T表示以代码段受到定义的一般变量
符号;D表示经常初始化过的数据段;B表示初始化的数据段;U表示从来不定义的,在斯库里面使用了,但是在外库中定义的符;W,weak的缩写,表示如
果其他函数库中也起指向斯符号的定义,则其它标志的概念可以覆盖这定义。

  如果你明白一个函数的讳,但是你无清楚这函数在啊库中定义的,那么可就此mn的“-o”选项和grep命令来查找库的讳。-o选项使得显示的各个一行还产生夫函数库文件称。例如,你如果摸“cos”这个是于啊地方定义的,大致可就此脚的授命:

nm -o /lib* /usr/local/libGROUP ( /lib/libc.so.6

/usr/lib/libc_nonshared.a )

  更多的消息方可参考texinfo文档中有关ld链接的本子部分。一般的信还好参考:
info:ld#Options 和info:ld#Commands,也得以参照info:ld#Option
Commands。

  5.4. GNU libtool

   如果你正在编译的系相互生便利的移植到外操作系统下,你可以运用GNU
libtool来创造和安装是函数库。GNU
libtool是一个函数库支持的杰出的本子。Libtool隐藏了使一个不过移栽的函数库底负责性。Libtool提供了一个足以移植的界面来创造
object文件,链接函数库(静态或者共享的),并且安装这些库。它还蕴含了libltdl,一个而移栽的动态函数库调入程序的wrapper。更多的
详细讨论,可以以http://www.gnu.org/software/libtool/manual.html看到。

  5.5. 剔除一些符号

  于一个产的公文中很多号都是为debug而带有的,占用了很多上空。如果空间不够,而且这些标记也许不再要,就可用中部分勾。

 
 最好的主意就是是优先正常的变动你要的object文件,然后debug和测试你得的一些东西。一旦你完全测试结束了,就可以据此strip去删
除部分无欲的号子了。Strip命令可以要你怪便利的支配删除什么符号,而保留什么符号。Strip的切实用法可以参见其帮助文件。

  另外的方就是是运GNU
ld的选择项“-S”和“-s”;“-S”会去除一些debugger的号,而“-s”则是以有着的符号信息还勾。通常我们可以gcc中加这样的参数“-Wl,-S”和“-Wl,-s”来达成这目的。

摘要


面是部分事例,例子中我们会以三种植函数库(静态的、共享的同动态加载的函数库)。文件libhello.c是一个函数库,libhello.h
是其的峰文件;demo_use.c则是一个下了libhello函数库底。Script_static和script_dynamic分别演示如何以
静态和共享方法使用函数库,而背后的demo_dynamic.c和script_dynamic则意味着演示如何以动态加载函数仓库的法门来利用她。

(2002-08-25 17:38:37)

By Wing

  6. 更多之例证

 
 下面是一对例子,例子中我们会动三种函数库(静态的、共享的以及动态加载的函数库)。文件libhello.c是一个函数库,
libhello.h是它们的头文件;demo_use.c则是一个施用了libhello函数库底。Script_static和
script_dynamic分别演示如何以静态和共享方法利用函数库,而背后的demo_dynamic.c和script_dynamic则表示演示
如何以动态加载函数仓房的不二法门来采取它们。

  6.1. File libhello.c

#include

void hello(void)

{

printf(“Hello, library world.

“);

}

  6.2. File libhello.h

void hello(void);

  6.3. File demo_use.c

#include “libhello.h”

int main(void)

{

hello();

return 0;

}

  6.4. File script_static

#!/bin/sh

# Static library demo

# Create static library’s object file, libhello-static.o.

# I’m using the name libhello-static to clearly

# differentiate the static library from the

# dynamic library examples, but you don’t need to use

# “-static” in the names of your

# object files or static libraries.gcc -Wall -g -c -o libhello-static.o

libhello.c

# Create static library.ar rcs libhello-static.a libhello-static.o

# At this point we could just copy libhello-static.a

# somewhere else to use it.

# For demo purposes, we’ll just keep the library

# in the current directory.

# Compile demo_use program file.gcc -Wall -g -c demo_use.c -o
demo_use.o

# Create demo_use program; -L. causes “.” to be searched during

# creation of the program. Note that this command causes

# the relevant object file in libhello-static.a to be

# incorporated into file demo_use_static.gcc -g -o demo_use_static

demo_use.o -L. -lhello-static

# Execute the program../demo_use_static

  6.5. File script_shared

#!/bin/sh

# Shared library demo

# Create shared library’s object file, libhello.o.gcc -fPIC -Wall

-g -c libhello.c

# Create shared library.

# Use -lc to link it against C library, since libhello

# depends on the C library.gcc -g -shared -Wl,-soname,libhello.so.0 -o

libhello.so.0.0 libhello.o -lc# At this point we could just copy

libhello.so.0.0 into

# some directory, say /usr/local/lib.

# Now we need to call ldconfig to fix up the symbolic links.

# Set up the soname. We could just execute:

# ln -sf libhello.so.0.0 libhello.so.0

# but let’s let ldconfig figure it out./sbin/ldconfig -n .

# Set up the linker name.

# In a more sophisticated setting, we’d need to make

# sure that if there was an existing linker name,

# and if so, check if it should stay or not.ln -sf libhello.so.0

libhello.so

# Compile demo_use program file.gcc -Wall -g -c demo_use.c -o

demo_use.o

# Create program demo_use.

# The -L. causes “.” to be searched during creation

# of the program; note that this does NOT mean that “.”

# will be searched when the program is executed.gcc -g -o demo_use

demo_use.o -L. -lhello

# Execute the program. Note that we need to tell the program

# where the shared library is,

using LD_LIBRARY_PATH.LD_LIBRARY_PATH=”.” ./demo_use

  6.6. File demo_dynamic.c

#include

#include

#include

typedef void (*simple_demo_function)(void);

int main(void)

{

const char *error;

void *module;

simple_demo_function demo_function;

module = dlopen(“libhello.so”, RTLD_LAZY);

if (!module)

{

  fprintf(stderr, “Couldn’t open libhello.so: %s

“,dlerror());

  exit(1);

}

dlerror();

demo_function = dlsym(module, “hello”);

if ((error = dlerror()))

{

  fprintf(stderr, “Couldn’t find hello: %s

“, error);

  exit(1);

}

(*demo_function)();

dlclose(module);

return 0;

}

  6.7. File script_dynamic

#!/bin/sh

# Dynamically loaded library demo

# Presume that libhello.so and friends have

# been created (see dynamic example).

# Compile demo_dynamic program file into an object file.gcc

-Wall -g -c demo_dynamic.c

# Create program demo_use.

# Note that we don’t have to tell it where to search

for DL libraries,

# since the only special library this program uses won’t be

# loaded until after the program starts up.

# However, we DO need the option -ldl to include the library

# that loads the DL libraries.gcc -g -o demo_dynamic

demo_dynamic.o -ldl

# Execute the program. Note that we need to tell the

# program where get the dynamically loaded library,

# using LD_LIBRARY_PATH.LD_LIBRARY_PATH=”.” ./demo_dynamic

 

转 http://blog.sina.com.cn/s/blog_4b9b714a0100ieam.html