返回> 网站首页 

[转载]Linux动态库静态库说明

yoours2015-05-09 21:57:16 阅读 1599

简介一边听听音乐,一边写写文章。

一、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/lib/* /usr/lib/*/* /usr/local/lib/* 2> /dev/null
| grep 'cos$'
关于nm的更详细的用法我们可以参考info文档,位置是info:binutils#nm。
二、特殊函数_init和_fini
函数库里面有两个特殊的函数,_init和_fini,这个我们在前面已经说过了。主要是分别用来初始化函数库和关闭的时候做一些必要的处理, 我们可以把自己认为需要的代码放到这两个函数里面,它们分别在函数库被加载和释放的时候被执行。具体说,如果一个函数库里面有一个名字为“_init”的 函数输出,那么在第一次通过dlopen()函数打开这个函数库,或者只是简单的作为共享函数库被打开的时候,_init函数被自动调用执行。与之相对应 的就是_fini函数,当一个程序调用dlclose()去释放对这个函数库的引用的时候,如果该函数库的被引用计数器为0了,或者这个函数库是作为一般 的共享函数库被使用而使用它的程序正常退出的时候,_fini就会被调用执行。C语言定义它们的原型如下:
void _init(void);
void _fini(void);
当用gcc编译源程序为“.o”文件的时候,需要加一个“-nostartfiles”选项。这个选项使得C编译器不链接系统的启动函数库里面的启动函数。否则,就会得到一个“multiple-definition”的错误。
三、共享函数库也可以使脚本(Scripts)
GNU的loader允许使用特殊格式的脚本语言来写一个函数库。这对于那些需要间接包含其他函数库的情况还是有用的。例如,下面是一个/usr/lib/libc.so的例子:
/* GNU ld script Use the shared library, but some functions are only in
the static library, so try that secondarily. */GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a )
更多的信息可以参考texinfo文档中关于ld链接的脚本部分。一般的信息还可以参考: info:ld#Options 和info:ld#Commands,也可以参考info:ld#Option Commands。
四、GNU libtool
如果你正在编译的系统相很方便的移植到其他操作系统下,你可以使用GNU libtool来创建和安装这个函数库。GNU libtool是一个函数库支持的典型的脚本。Libtool隐藏了使用一个可移植的函数库的负责性。Libtool提供了一个可以移植的界面来创建 object文件,链接函数库(静态或者共享的),并且安装这些库。它还包含了libltdl,一个可移植的动态函数库调入程序的wrapper。更多的 详细讨论,可以在http://www.gnu.org/software/libtool/manual.html看到。
五、删除一些符号
在一个生产的文件中很多符号都是为了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则表示演示 如何以动态加载函数库的方式来使用它。
1. File libhello.c
/* libhello.c - demonstrate library use. */
void hello(void)
{
printf("Hello, library world.
");
}

2. File libhello.h
/* libhello.h - demonstrate library use. */
void hello(void);

3. File demo_use.c
/* demo_use.c -- demonstrate direct use of the "hello" routine */
#include "libhello.h"
int main(void)
{
hello();
return 0;
}

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

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. File demo_dynamic.c
/* demo_dynamic.c -- demonstrate dynamic loading and use of the "hello" routine */
/* Need dlfcn.h for the routines to dynamically load libraries */
/* Note that we don't have to include "libhello.h".
However, we do need to specify something related;
we need to specify a type that will hold the value we're going to get from dlsym(). */
/* The type "simple_demo_function" describes a function that takes no arguments, and returns no value: */
typedef void (*simple_demo_function)(void);
int main(void)
{
const char *error;
void *module;
simple_demo_function demo_function;
/* Load dynamically loaded library */
module = dlopen("libhello.so", RTLD_LAZY);
if (!module)
{
fprintf(stderr, "Couldn't open libhello.so: %s",dlerror());
exit(1);
}

/* Get symbol */
dlerror();
demo_function = dlsym(module, "hello");
if ((error = dlerror()))
{
fprintf(stderr, "Couldn't find hello: %s", error);
exit(1);
}

/* Now call the function in the DL library */
(*demo_function)();
/* All done, close things cleanly */
dlclose(module);
return 0;
}

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_dynamicv

微信小程序扫码登陆

文章评论

1599人参与,0条评论