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