当我们的程序中有经常使用的模块,而且这种模块在其他程序中也会用到,这时按照软件重用的思想,我们应该将它们生成库,使得以后编程可以减少开发代
码量。这里介绍两个命令ar和nm,用来对库操作。
1、ar基本用法
ar命令可以用来创建、修改库,也可以从库中提出单个模块。库是一单独的文
件,里面包含了按照特定的结构组织起来的其它的一些文件(称做此库文件的member)。原始文件的内容、模式、时间戳、属主、组等属性都保留在库文件
中。
下面是ar命令的格式:
ar [-]{dmpqrtx}[abcfilNoPsSuvV] [membername]
[count] archive files...
例如我们可以用ar rv libtest.a hello.o
hello1.o来生成一个库,库名字是test,链接时可以用-ltest链接。该库中存放了两个模块hello.o和hello1.o。选项前可以有
‘-’字符,也可以没有。下面我们来看看命令的操作选项和任选项。现在我们把{dmpqrtx}部分称为操作选项,而[abcfilNoPsSuvV]部
分称为任选项。
{dmpqrtx}中的操作选项在命令中只能并且必须使用其中一个,它们的含义如下:
d:从库中删除模块。按模块
原来的文件名指定要删除的模块。如果使用了任选项v则列出被删除的每个模块。
m:该操作是在一个库中移动成员。当库中如果有若干模块有相同的
符号定义(如函数定义),则成员的位置顺序很重要。如果没有指定任选项,任何指定的成员将移到库的最后。也可以使用’a’,’b’,或’I’任选项移动到
指定的位置。
p:显示库中指定的成员到标准输出。如果指定任选项v,则在输出成员的内容前,将显示成员的名字。如果没有指定成员的名字,所
有库中的文件将显示出来。
q:快速追加。增加新模块到库的结尾处。并不检查是否需要替换。’a’,’b’,或’I’任选项对此操作没有影
响,模块总是追加的库的结尾处。如果使用了任选项v则列出每个模块。 这时,库的符号表没有更新,可以用’ar
s’或ranlib来更新库的符号表索引。
r:在库中插入模块(替换)。当插入的模块名已经在库中存在,则替换同名的模块。如果若干模块中
有一个模块在库中不存在,ar显示一个错误消息,并不替换其他同名模块。默认的情况下,新的成员增加在库的结尾处,可以使用其他任选项来改变增加的位置。
t:显示库的模块表清单。一般只显示模块名。
x:从库中提取一个成员。如果不指定要提取的模块,则提取库中所有的模块。
下面在看看可与操作选项结合使用的任选项:
a:在库的一个已经存在的成员后面增加一个新的文件。如果使用任选项a,则应该为命
令行中membername参数指定一个已经存在的成员名。
b:在库的一个已经存在的成员前面增加一个新的文件。如果使用任选项b,则应该
为命令行中membername参数指定一个已经存在的成员名。
c:创建一个库。不管库是否存在,都将创建。
f:在库中截短指
定的名字。缺省情况下,文件名的长度是不受限制的,可以使用此参数将文件名截短,以保证与其它系统的兼容。
i:在库的一个已经存在的成员前
面增加一个新的文件。如果使用任选项i,则应该为命令行中membername参数指定一个已经存在的成员名(类似任选项b)。
l:暂未使
用
N:与count参数一起使用,在库中有多个相同的文件名时指定提取或输出的个数。
o:当提取成员时,保留成员的原始数
据。如果不指定该任选项,则提取出的模块的时间将标为提取出的时间。
P:进行文件名匹配时使用全路径名。ar在创建库时不能使用全路径名
(这样的库文件不符合POSIX标准),但是有些工具可以。
s:写入一个目标文件索引到库中,或者更新一个存在的目标文件索引。甚至对于没
有任何变化的库也作该动作。对一个库做ar s等同于对该库做ranlib。
S:不创建目标文件索引,这在创建较大的库时能加快时间。
u:一般说来,命令ar
r…插入所有列出的文件到库中,如果你只想插入列出文件中那些比库中同名文件新的文件,就可以使用该任选项。该任选项只用于r操作选项。
v:该选项用来显示执行操作选项的附加信息。
V:显示ar的版本。
2、nm基本用法命令
nm用来列出目标文件的符号清单。下面是nm命令的格式:
nm [-a|--debug-syms]
[-g|--extern-only] [-B][-C|--demangle] [-D|--dynamic]
[-s|--print-armap][-o|--print-file-name]
[-n|--numeric-sort][-p|--no-sort] [-r|--reverse-sort]
[--size-sort][-u|--undefined-only] [-l|--line-numbers]
[--help][--version] [-t radix|--radix=radix][-P|--portability] [-f
format|--format=format][--target=bfdname] [objfile...]
如果没有为nm命令指出目
标文件,则nm假定目标文件是a.out。下面列出该命令的任选项,大部分支持“-”开头的短格式和“—“开头的长格式。
-A、-o或
--print-file-name:在找到的各个符号的名字前加上文件名,而不是在此文件的所有符号前只出现文件名一次。
例如nm
libtest.a的输出如下:
CPThread.o:
00000068 T Main__8CPThreadPv
00000038 T Start__8CPThread
00000014 T _._8CPThread
00000000 T
__8CPThread
00000000 ? __FRAME_BEGIN__
…………………………………
则nm
–A 的输出如下:
libtest.a:CPThread.o:00000068 T Main__8CPThreadPv
libtest.a:CPThread.o:00000038 T Start__8CPThread
libtest.a:CPThread.o:00000014 T _._8CPThread
libtest.a:CPThread.o:00000000 T __8CPThread
libtest.a:CPThread.o:00000000 ? __FRAME_BEGIN__
…………………………………………………………
-a或--debug-syms:显示调试符号。
-B:等同于
--format=bsd,用来兼容MIPS的nm。
-C或--demangle:将低级符号名解码(demangle)成用户级名字。这
样可以使得C++函数名具有可读性。
-D或--dynamic:显示动态符号。该任选项仅对于动态目标(例如特定类型的共享库)有意义。
-f format:使用format格式输出。format可以选取bsd、sysv或posix,该选项在GNU的nm中有用。默认为bsd。
-g或--extern-only:仅显示外部符号。
-n、-v或--numeric-sort:按符号对应地址的顺序排序,而非按符号
名的字符顺序。
-p或--no-sort:按目标文件中遇到的符号顺序显示,不排序。
-P或--portability:使
用POSIX.2标准输出格式代替默认的输出格式。等同于使用任选项-f posix。
-s或--print-armap:当列出库中成员的
符号时,包含索引。索引的内容包含:哪些模块包含哪些名字的映射。
-r或--reverse-sort:反转排序的顺序(例如,升序变为降
序)。
--size-sort:按大小排列符号顺序。该大小是按照一个符号的值与它下一个符号的值进行计算的。
-t
radix或--radix=radix:使用radix进制显示符号值。radix只能为“d”表示十进制、“o”表示八进制或“x”表示十六进制。
--target=bfdname:指定一个目标代码的格式,而非使用系统的默认格式。
-u或--undefined-only:仅显示
没有定义的符号(那些外部符号)。
-l或--line-numbers:对每个符号,使用调试信息来试图找到文件名和行号。对于已定义的符
号,查找符号地址的行号。对于未定义符号,查找指向符号重定位入口的行号。如果可以找到行号信息,显示在符号信息之后。
-V或
--version:显示nm的版本号。
--help:显示nm的任选项。
3、示例
1)、创建静态库:
gcc -c hello.c -o hello.o
ar rcs libhello.a hello.o
2)、使用静态库:
gcc -o test test.c
-static -L. -lhello
3)、共享库版本: version.minor.release
4)、构建动态共享库:
gcc/g++下加 -fPIC -shared 参数即可
其中 -fPIC
作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent
Code),则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意位置,都可以正确的执行。这正是共享库所要求的,共
享库被加载时,在内存的位置不是固定的。
可以export LD_DEBUG=files,查看每次加载共享库的实际地址。
其中
-shared 作用于链接阶段,实际传递给链接器ld,让其添加作为共享库所需要的额外描述信息,去除共享库所不需的信息。
可以分解为如
下步骤:
I. gcc -c err.c -fPIC -o err.o
II. gcc -shared -o
liberr.so.0.0 err.o
II <==> ld -Bshareable -o liberr.so.0.0
err.o
III. ln -s liberr.so.0.0 liberr.so
5)、动态共享库的使用:
由共享库加载器自动加载
gcc -o test test.c -lerr -L. -Wl,-rpath=./
-Wl,option
Pass option as an option to the linker. If option
contains commas, it is split into multiple options at the commas.
-rpath: 指定运行时搜索动态库的路径,可以用环境变量LD_LIBRARY_PATH指定。
程序自己控制加载、符号解析(使
用libc6之dl库)
gcc cos.c -o cos -ldl
/* cos.c */
#include
<stdio.h>
#include <dlfcn.h>
int main()
{
void *handle;
double (*cosine)(double);
char *error;
double rev;
handle = dlopen("libm.so", RTLD_LAZY); // 加载动态库
if(!handle)
{
fprintf(stderr, "%s\n", dlerror());
exit(1);
}
dlerror();
cosine = dlsym(handle, "cos"); // 解析符号cos
if((error =
dlerror()) != NULL)
{
fprintf(stderr, "%s\n", error);
exit(1);
}
rev = cosine(3.1415926); // 使用cos函数
printf("The cos result
is: %f\n", rev);
dlclose(handle);
return 0;
}
6)、GNU/Linux下动态库之加载器为/lib/ld-linux.so,
可执行的。
/lib/ld-linux.so ./cos <===> ./cos
7)、有用的环境变
量
LD_LIBRARY_PATH
指定运行时动态库的搜索路径
LD_DEBUG
调试用,其值
可为:
libs display library search paths
reloc display
relocation processing
files display progress for input file
symbols display symbol table processing
bindings display
information about symbol binding
versions display version
dependencies
all all previous options combined
statistics display relocation statistics
unused determined
unused DSOs
help display this help message and exit
8)、搜索含有cos函数的共享库名
nm -AD /lib/* /usr/lib/* 2>/dev/null | grep
"cos$"
nm -- 从对象文件中列出符号。
9)、读取ELF文件格式信息
readelf -Ds
./libfoo.so #读出共享库的符号
from:
http://fnstudio.blog.sohu.com/74541293.html
posted on 2010-05-06 22:32
chatler 阅读(799)
评论(0) 编辑 收藏 引用 所属分类:
Linux_Coding