1、创建函数库
分类:
静态库: 在编译过程中将库函数代码直接加入到生成的可执行程序中,程序运行过程中不需要利用库函数。
共享库: 编译时,只是在生成的可执行程序中简单指定需要使用的库函数信息,程序运行过程中需要利用库函数。
动态库: 共享库的一种变化形式,目前大都采用共享库的方式。
命名:
静态库: 前缀lib+库名+.a (libm.a, libstdc++.a等)
共享库: 前缀lib+库名+.so+版本号 (libm.so.6, libc.so.6)
2、静态函数库是一组目标文件(*.o)的集合
创建步骤:
gcc -c test1.c test2.c (生成test1.o, test2.o)
ar -cr libtest.a test1.o test2.o (生成函数库libtest.a)
ar函数说明:
用途:创建和修改库函数,或从库函数提取目标文件
举例:
ar –rs lib-name list-of-files (将列表中的目标文件加入到库中,并产生索引文件)
ar –ds lib-name list-of-files (将列表中列出的目标文件从库中删除,并产生索引文件)
ar –x lib-name list-of-files (不修改库文件,从库中提取列表中列出的目标文件)
3、创建静态库示例--源码
caculation.c
#include <stdio.h>
int main(void)
{
int x = 5 ;
int y = 3 ;
printf (“x + y = %3d\n”, add(x, y) );
printf (“x – y = %3d\n”, minus(x, y) );
printf (“x * y = %3d\n”, multiply(x, y) );
printf (“x % y = %3d\n”, mod(x, y) );
return 1;
}
add_minus.c
int add(int x, int y)
{
int result;
result = x + y;
return result;
}
int minus(int x, int y)
{
int result;
result = x – y;
return result;
}
multiply_mod.c
int multiply(int x, int y)
{
int result;
result = x * y;
return result;
}
int mod(int x, int y)
{
int result;
result = x % y;
return result;
}
创建过程:
trevor@TREVOR:~/GCC/0407$ gcc -o add_minus.o -c add_minus.c
trevor@TREVOR:~/GCC/0407$ gcc -o multiply_mod.o -c multiply_mod.c
trevor@TREVOR:~/GCC/0407$ gc -o caculation.o -c caculation.c
trevor@TREVOR:~/GCC/0407$ ar -r libalgorithm.a add_minus.o multiply_mod.o
ar: creating libalgorithm.a
trevor@TREVOR:~/GCC/0407$ gcc caculation.o -L. -lalgorithm -o caculate /*L表示路径*/
或者:gcc caculation.o -o caculate ./libalgorithm.a
trevor@TREVOR:~/GCC/0407$ ./caculate
x + y = 8
x – y = 2
x * y = 15
x % y = 2
4、一个容易忽略的顺序问题
静态库不能先于原程序链接,这是因为开始时还没有任何
未定义的符号,库中的内容不会被链入,所以应该注意将静态库的使用(-l选项)都写在最后。
gcc -L. -lalgorithm caculation.o -o caculate则错了
二、创建共享库
1、步骤
• 创建共享库
gcc -c -fPIC test1.c
gcc -c -fPIC test2.c
gcc -shared -fPIC -o libtest.so test1.o test2.o
• 编译使用了共享库的程序
gcc -o test –Ldir -ltest test.c
2、共享库系统自动动态加载问题
• 1.拷贝动态库文件到/lib或/usr/lib去
$ cp libalg.so /usr/lib or $cp libalg.so /lib
• 2.改变环境变量LD_LIBRARY_PATH
$ LD_LIBRARY_PATH=$PWD
$ export LD_LIBRARY_PATH
3、应用程序自身完成动态加载
可以在自己的程序中使用 dlopen()。该函数将打开一个新库,并把它装入内存。 dlopen() 在 dlfcn.h 中定义,并在 dl 库中实现。
• ldd的使用:用于查看库函数之间的依赖性
[vick@nec gcc-lab]$ cd /usr/lib
[vick@nec lib]$ ldd libtiff.so
libjpeg.so.62 => /usr/lib/libjpeg.so.62 (0x4004c000)
libz.so.1 => /usr/lib/libz.so.1 (0x4006b000)
libc.so.6 => /lib/i686/libc.so.6 (0x40079000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x80000000)
4、应用程序自身完成动态加载示例
test.c
#include <stdio.h>
#include <dlfcn.h>
int main(void)
{
int x = 5 ;
int y = 3 ;
void * handle;
int ( *dl_add )( int, int );
int ( *dl_mod )( int, int );
handle = dlopen( “/lib/libtaozhen.so“, RTLD_LAZY );
dl_add = dlsym( handle, “add” );
dl_mod = dlsym( handle, “mod” );
printf (“x + y = %3d\n”, dl_add(x,y));
printf (“x % y = %3d\n”, dl_mod(x,y));
dlclose( handle );
return 1;
}
终端输入:
trevor@TREVOR:~/GCC/0407$ gcc -o test test.c –ldl
trevor@TREVOR:~/GCC/0407$ ./test
x + y = 8
x % y = 2
三、其他
1、objdump与readelf的区别
objdump和readelf功能相似,都可以从二进制文件中读取相应的信息并显示。
第一个区别,objdump使用了bfd库进行文件读取,而readelf则没有,另外写的一套代码,且对一些条件的判断并不是很严格。比如对于没有指定处理方式的CPU类型,BFD库将拒绝往下执行,readelf还是可以显示其内容。
第二个区别,readelf可以显示调试信息,而objdump则没有。但是实际上bfd库支持DWARF的处理,通过简单处理objdump。
objdump和readelf都可以用来查看二进制文件的一些内部信息. 区别在于objdump
借助BFD而更加通用一些, 可以应付不同文件格式, readelf则并不借助BFD,
而是直接读取ELF格式文件的信息, 按readelf手册页上所说, 得到的信息也略细致一些.
几个功能对比.
1. 反汇编代码
查看源代码被翻译成的汇编代码, 大概有3种方法,
1) 通过编译器直接从源文件生成, 如gcc -S
2) 对目标代码反汇编, 一种是静态反汇编, 就是使用objdump
3) 另外一种就是对运行时的代码反汇编, 一般通过gdb
readelf并不提供反汇编功能.
objdump可以指定反汇编哪个节, 一般只有对包含指令的节反汇编才有意义. 而对于一些
其他的类型的节, objdump也可以将特殊节的数据以解析后的形式呈现出来,
2. 显示relocation节的条目
-r参数显示elf文件的类型为REL的节的信息, 使用-S参数可以列出elf文件的
所有节的信息, 其中也就包括了REL节.
对于可重定位文件两者显示条目一致, 最重要的offset和type以及Sym.Name都有.
下面是两者输出的对比.
3. 显示动态重定位条目(或者可以认为是动态链接相关的重定位条目)
(按objdump的man page说明, 只对dynamic object有效, 如某些类型的共享库)
readelf和objdump等价的命令为readelf -D -r file和objdump -R file.
对readelf使用-r和-D -r的区别, 对于共享库在于数据的呈现方式略有不同. 这两种
都将数据解析后呈现出来. 前者显示的是相对于基地址的偏移, 后者则显示绝对偏移量.
前者显示条目数, 后者显示字节数.
4. 显示节信息: readelf -S和objdump -h
对于可重定位文件, objdump -h不能显示.rel开头的节和.shstrtab, .symtab, .strtab.
而readelf的显示有一个.group节, 其内容为节的group, 可以用-g参数查看.
除非注明,文章均为CppLive 编程在线原创,转载请注明出处,谢谢。