前篇中的静态库有一个明显的缺点,当多个代码公用的库文件为静态库时,需要进行多次拷贝,造成大量重复的代码。主要需求为:
1、公用一份代码,大大节约执行文件的空间;
2、对于条件执行的代码,有可能出现代码进入可执行文件,但是却得不到运行的情况;
3、需要在启动或运行中需要用到时才实时加载进进程空间,并且能够和其他进程共享动态链接的代码
这都是动态库所具有的特征。动态库中的代码可能被不同的进程引用,库中函数的代码在不同进程中占据的存储空间大小是一样的,但是布局时对应的地址可能是不同的,所以必须要求动态库中的代码不能依赖任何特定布局的元素,这种代码就是位置无关代码(PIC:position independent code)
一、编辑代码如下:
#vector.h 1 #ifndef vector_h 2 #define vector_h 3 4 void addVec(int *xP, int *yP, int *zP, int Num); 5 void mulVec(int *xP, int *yP, int *zP, int Num); 6 7 #endif #addVec.c 1 #include "vector.h" 2 3 void addVec(int *xP, int *yP, int *zP, int Num){ 4 for(int i = 0; i < n; i++){ 5 zP[i] = xP[i] + yP[i]; 6 } 7 8 return; 9 } ~ #mulVec.c 1 #include "vector.h" 2 3 void mulVec(int *xP, int *yP, int *zP, int Num){ 4 for(int i = 0; i < n; i++){ 5 zP[i] = xP[i] * yP[i]; 6 } 7 8 return; 9 } #testVec.c 1 #include <stdio.h> 2 #include "vector.h" 3 4 int x[2] = {1, 2}; 5 int y[2] = {3, 4}; 6 int z[2]; 7 8 int main(int argc, char **argv) 9 { 10 addVec(x, y, z, 2); 11 printf("z = [%d %d] ", z[0], z[1]); 12 13 return 0; 14 }
二、生成动态库文件:
1、gcc -shared -fPIC -o libVector.so addVec.c mulVec.c //生成动态库文件
2、ls *.so 或 ls | grep .so //查看目标文件
3、file libVector.so //查看文件类型
4、ldd libVector.so //查看生成的库文件
5、nm libVector.so //查看生成的库文件包含哪些函数
三、使用动态库文件:
gcc testVec.c libVector.so -o testVec //生成可执行文件,无法执行错误:testVec: error while loading shared libraries: libVector.so: cannot open shared object file: No such file or directory
ldd testVec //查看库引用问题,
… � gnuC � lib � shared � ldd testVec linux-vdso.so.1 (0x00007ffc88c59000) libVector.so => not found libc.so.6 => /usr/lib/libc.so.6 (0x00007ff632961000) /lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007ff632b97000)
就是libVector.so => not found,导致程序无法运行的。
四、gcc的搜索路径
手动指定头文件和库文件路径,编译命令:gcc -g -I./include/ -L ./libso/ -lVector testVec.c -o testVec
1、头文件搜索路径,默认gcc 对#include <*.h>类的头文件主要从/usr/local/include或/usr/include,这两个是系统默认的无需用户配置
gcc对#include "*.h"的默认搜索路径是在当前目录下查找,否则就会到系统默认目录下查找
gcc对#include "*.h"的又是用户自己决定的目录,主要是通过添加编译选项 -I${SELPATH}即可
gcc对#include "${SELPATH}/*.h"的又是用户自己决定的目录,此时无需添加编译选项
头文件搜索路径使用环境变量:C_INCLUDE_PATH,经过如下操作
C_INCLUDE_PATH=$C_INCLUDE_PATH:$PWD/include
echo $C_INCLUDE_PATH 结果:/home/nication/WORKM/studyCode/gnuC/lib/shared/include 验证没错
export C_INCLUDE_PATH
此时编译只需gcc -g -L ./libso/ -lVector testVec.c -o testVec
2、库文件搜索路径,默认gcc 对库文件主要是-l+文件名,文件名=自己作的库文件名-lib
gcc对用户自己决定的库目录,主要是通过添加编译选项 -L${SELPATH}即可
库文件搜索路径使用环境变量:LIBRARY_PATH,经过如下操作
LIBRARY_PATH=$LIBRARY_PATH:$PWD/libso
echo $LIBRARY_PATH 结果:/home/nication/WORKM/studyCode/gnuC/lib/shared/libso 验证没错
export LIBRARY_PATH
此时编译只需gcc -g -I./include/ -lVector testVec.c -o testVec
如果已经设置过头文件和库文件的搜索路径,编译命令:gcc -g -I./include/ -L ./libso/ -lVector testVec.c -o testVec,
也就是说可以:gcc -g -lVector testVec.c -o testVec
五、运行程序:
testVec //运行结果testVec: error while loading shared libraries: libVector.so: cannot open shared object file : No such file or directory
需要设置库的载入路径:修改变量LD_LIBRARY_PATH,方法如下:
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/libso
echo $LD_LIBRARY_PATH 结果:/home/nication/WORKM/studyCode/gnuC/lib/shared/libso 验证没错
export LD_LIBRARY_PATH 导入库载入路径
再运行: testVec //运行结果z = [4 6],终于正确了
六、查看testVec代码
objdump -d testVec,结果:objdump -d testVec
… � gnuC � lib � shared � objdump -d testVec testVec: 文件格式 elf64-x86-64 Disassembly of section .init: 0000000000001000 <_init>: 1000: f3 0f 1e fa endbr64 1004: 48 83 ec 08 sub $0x8,%rsp 1008: 48 8b 05 d9 2f 00 00 mov 0x2fd9(%rip),%rax # 3fe8 <__gmon_start__> 100f: 48 85 c0 test %rax,%rax 1012: 74 02 je 1016 <_init+0x16> 1014: ff d0 callq *%rax 1016: 48 83 c4 08 add $0x8,%rsp 101a: c3 retq Disassembly of section .plt: 0000000000001020 <.plt>: 1020: ff 35 e2 2f 00 00 pushq 0x2fe2(%rip) # 4008 <_GLOBAL_OFFSET_TABLE_+0x8> 1026: ff 25 e4 2f 00 00 jmpq *0x2fe4(%rip) # 4010 <_GLOBAL_OFFSET_TABLE_+0x10> 102c: 0f 1f 40 00 nopl 0x0(%rax) 0000000000001030 <printf@plt>: 1030: ff 25 e2 2f 00 00 jmpq *0x2fe2(%rip) # 4018 <printf@GLIBC_2.2.5> 1036: 68 00 00 00 00 pushq $0x0 103b: e9 e0 ff ff ff jmpq 1020 <.plt> 0000000000001040 <addVec@plt>: 1040: ff 25 da 2f 00 00 jmpq *0x2fda(%rip) # 4020 <addVec> 1046: 68 01 00 00 00 pushq $0x1 104b: e9 d0 ff ff ff jmpq 1020 <.plt> Disassembly of section .text: 0000000000001050 <_start>: 1050: f3 0f 1e fa endbr64 1054: 31 ed xor %ebp,%ebp 1056: 49 89 d1 mov %rdx,%r9 1059: 5e pop %rsi 105a: 48 89 e2 mov %rsp,%rdx 105d: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp 1061: 50 push %rax 1062: 54 push %rsp 1063: 4c 8d 05 a6 01 00 00 lea 0x1a6(%rip),%r8 # 1210 <__libc_csu_fini> 106a: 48 8d 0d 2f 01 00 00 lea 0x12f(%rip),%rcx # 11a0 <__libc_csu_init> 1071: 48 8d 3d d1 00 00 00 lea 0xd1(%rip),%rdi # 1149 <main> 1078: ff 15 62 2f 00 00 callq *0x2f62(%rip) # 3fe0 <__libc_start_main@GLIBC_2.2.5> 107e: f4 hlt 107f: 90 nop 0000000000001080 <deregister_tm_clones>: 1080: 48 8d 3d c1 2f 00 00 lea 0x2fc1(%rip),%rdi # 4048 <__TMC_END__> 1087: 48 8d 05 ba 2f 00 00 lea 0x2fba(%rip),%rax # 4048 <__TMC_END__> 108e: 48 39 f8 cmp %rdi,%rax 1091: 74 15 je 10a8 <deregister_tm_clones+0x28> 1093: 48 8b 05 3e 2f 00 00 mov 0x2f3e(%rip),%rax # 3fd8 <_ITM_deregisterTMCloneTable> 109a: 48 85 c0 test %rax,%rax 109d: 74 09 je 10a8 <deregister_tm_clones+0x28> 109f: ff e0 jmpq *%rax 10a1: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 10a8: c3 retq 10a9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 00000000000010b0 <register_tm_clones>: 10b0: 48 8d 3d 91 2f 00 00 lea 0x2f91(%rip),%rdi # 4048 <__TMC_END__> 10b7: 48 8d 35 8a 2f 00 00 lea 0x2f8a(%rip),%rsi # 4048 <__TMC_END__> 10be: 48 29 fe sub %rdi,%rsi 10c1: 48 89 f0 mov %rsi,%rax 10c4: 48 c1 ee 3f shr $0x3f,%rsi 10c8: 48 c1 f8 03 sar $0x3,%rax 10cc: 48 01 c6 add %rax,%rsi 10cf: 48 d1 fe sar %rsi 10d2: 74 14 je 10e8 <register_tm_clones+0x38> 10d4: 48 8b 05 15 2f 00 00 mov 0x2f15(%rip),%rax # 3ff0 <_ITM_registerTMCloneTable> 10db: 48 85 c0 test %rax,%rax 10de: 74 08 je 10e8 <register_tm_clones+0x38> 10e0: ff e0 jmpq *%rax 10e2: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) 10e8: c3 retq 10e9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 00000000000010f0 <__do_global_dtors_aux>: 10f0: f3 0f 1e fa endbr64 10f4: 80 3d 4d 2f 00 00 00 cmpb $0x0,0x2f4d(%rip) # 4048 <__TMC_END__> 10fb: 75 33 jne 1130 <__do_global_dtors_aux+0x40> 10fd: 55 push %rbp 10fe: 48 83 3d f2 2e 00 00 cmpq $0x0,0x2ef2(%rip) # 3ff8 <__cxa_finalize@GLIBC_2.2.5> 1105: 00 1106: 48 89 e5 mov %rsp,%rbp 1109: 74 0d je 1118 <__do_global_dtors_aux+0x28> 110b: 48 8b 3d 1e 2f 00 00 mov 0x2f1e(%rip),%rdi # 4030 <__dso_handle> 1112: ff 15 e0 2e 00 00 callq *0x2ee0(%rip) # 3ff8 <__cxa_finalize@GLIBC_2.2.5> 1118: e8 63 ff ff ff callq 1080 <deregister_tm_clones> 111d: c6 05 24 2f 00 00 01 movb $0x1,0x2f24(%rip) # 4048 <__TMC_END__> 1124: 5d pop %rbp 1125: c3 retq 1126: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 112d: 00 00 00 1130: c3 retq 1131: 66 66 2e 0f 1f 84 00 data16 nopw %cs:0x0(%rax,%rax,1) 1138: 00 00 00 00 113c: 0f 1f 40 00 nopl 0x0(%rax) 0000000000001140 <frame_dummy>: 1140: f3 0f 1e fa endbr64 1144: e9 67 ff ff ff jmpq 10b0 <register_tm_clones> 0000000000001149 <main>: 1149: 55 push %rbp 114a: 48 89 e5 mov %rsp,%rbp 114d: 48 83 ec 10 sub $0x10,%rsp 1151: 89 7d fc mov %edi,-0x4(%rbp) 1154: 48 89 75 f0 mov %rsi,-0x10(%rbp) 1158: b9 02 00 00 00 mov $0x2,%ecx 115d: 48 8d 15 ec 2e 00 00 lea 0x2eec(%rip),%rdx # 4050 <z> 1164: 48 8d 35 d5 2e 00 00 lea 0x2ed5(%rip),%rsi # 4040 <y> 116b: 48 8d 3d c6 2e 00 00 lea 0x2ec6(%rip),%rdi # 4038 <x> 1172: e8 c9 fe ff ff callq 1040 <addVec@plt> 1177: 8b 15 d7 2e 00 00 mov 0x2ed7(%rip),%edx # 4054 <z+0x4> 117d: 8b 05 cd 2e 00 00 mov 0x2ecd(%rip),%eax # 4050 <z> 1183: 89 c6 mov %eax,%esi 1185: 48 8d 3d 78 0e 00 00 lea 0xe78(%rip),%rdi # 2004 <_IO_stdin_used+0x4> 118c: b8 00 00 00 00 mov $0x0,%eax 1191: e8 9a fe ff ff callq 1030 <printf@plt> 1196: b8 00 00 00 00 mov $0x0,%eax 119b: c9 leaveq 119c: c3 retq 119d: 0f 1f 00 nopl (%rax) 00000000000011a0 <__libc_csu_init>: 11a0: f3 0f 1e fa endbr64 11a4: 41 57 push %r15 11a6: 4c 8d 3d 2b 2c 00 00 lea 0x2c2b(%rip),%r15 # 3dd8 <__frame_dummy_init_array_entry> 11ad: 41 56 push %r14 11af: 49 89 d6 mov %rdx,%r14 11b2: 41 55 push %r13 11b4: 49 89 f5 mov %rsi,%r13 11b7: 41 54 push %r12 11b9: 41 89 fc mov %edi,%r12d 11bc: 55 push %rbp 11bd: 48 8d 2d 1c 2c 00 00 lea 0x2c1c(%rip),%rbp # 3de0 <__do_global_dtors_aux_fini_array_entry> 11c4: 53 push %rbx 11c5: 4c 29 fd sub %r15,%rbp 11c8: 48 83 ec 08 sub $0x8,%rsp 11cc: e8 2f fe ff ff callq 1000 <_init> 11d1: 48 c1 fd 03 sar $0x3,%rbp 11d5: 74 1f je 11f6 <__libc_csu_init+0x56> 11d7: 31 db xor %ebx,%ebx 11d9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 11e0: 4c 89 f2 mov %r14,%rdx 11e3: 4c 89 ee mov %r13,%rsi 11e6: 44 89 e7 mov %r12d,%edi 11e9: 41 ff 14 df callq *(%r15,%rbx,8) 11ed: 48 83 c3 01 add $0x1,%rbx 11f1: 48 39 dd cmp %rbx,%rbp 11f4: 75 ea jne 11e0 <__libc_csu_init+0x40> 11f6: 48 83 c4 08 add $0x8,%rsp 11fa: 5b pop %rbx 11fb: 5d pop %rbp 11fc: 41 5c pop %r12 11fe: 41 5d pop %r13 1200: 41 5e pop %r14 1202: 41 5f pop %r15 1204: c3 retq 1205: 66 66 2e 0f 1f 84 00 data16 nopw %cs:0x0(%rax,%rax,1) 120c: 00 00 00 00 0000000000001210 <__libc_csu_fini>: 1210: f3 0f 1e fa endbr64 1214: c3 retq Disassembly of section .fini: 0000000000001218 <_fini>: 1218: f3 0f 1e fa endbr64 121c: 48 83 ec 08 sub $0x8,%rsp 1220: 48 83 c4 08 add $0x8,%rsp 1224: c3 retq
objdump -d addVec.o结果:
0000000000000000 <addVec>: 0: 49 89 f9 mov %rdi,%r9 3: 49 89 f0 mov %rsi,%r8 6: 48 89 d7 mov %rdx,%rdi 9: 89 ce mov %ecx,%esi b: b8 00 00 00 00 mov $0x0,%eax 10: eb 11 jmp 23 <addVec+0x23> 12: 48 63 d0 movslq %eax,%rdx 15: 41 8b 0c 90 mov (%r8,%rdx,4),%ecx 19: 41 03 0c 91 add (%r9,%rdx,4),%ecx 1d: 89 0c 97 mov %ecx,(%rdi,%rdx,4) 20: 83 c0 01 add $0x1,%eax 23: 39 f0 cmp %esi,%eax 25: 7c eb jl 12 <addVec+0x12> 27: c3 retq
发现addVec.o没完全进入了可执行文件中,只是做好了被调用的准备而以。
七、动态库工具ldconfig
该工具主要用来建立动态库的搜索路径的缓存,具有以下几个特征:
1、默认搜索目录为/usr/lib或/lib
2、