【Linux】21.底子IO(3)

[复制链接]
发表于 2025-11-3 17:57:21 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

3. 动态库和静态库

3.1 静态库与动态库

   

  • 静态库(.a):步调在编译链接的时间把库的代码链接到可实行文件中。步调运行的时间将不再须要静态库
  • 动态库(.so):步调在运行的时间才去链接动态库的代码,多个步调共享使用库的代码。
  • 一个与动态库链接的可实行文件仅仅包罗它用到的函数入口地点的一个表,而不是外部函数所在目标文件的整个呆板码
  • 在可实行文件开始运行从前,外部函数的呆板码由操纵体系从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking)
  • 动态库可以在多个步调间共享,以是动态链接使得可实行文件更小,节省了磁盘空间。操纵体系采取假造内存机制允许物理内存中的一份动态库被要用到该库的全部历程共用,节省了内存和磁盘空间。
  
3.2 静态库的制作和使用原理

mymath.h
  1. #pragma once
  2. #include <stdio.h>
  3. int add(int x, int y);//加
  4. int sub(int x, int y);//减
  5. int mul(int x, int y);//乘
  6. int div(int x, int y);//除
复制代码
mymath.c
  1. #include "mymath.h"
  2. int myerrno = 0;
  3. int add(int x, int y){
  4.     return x + y;
  5. }
  6. int sub(int x, int y){
  7.     return x - y;
  8. }
  9. int mul(int x, int y){
  10.     return x * y;
  11. }
  12. int div(int x, int y){
  13.     if(y == 0){
  14.         myerrno = 1;
  15.         return -1;
  16.     }
  17.     return x / y;
  18. }
复制代码
makefile
  1. lib=libmymath.a
  2. $(lib):mymath.o
  3.         ar -rc $@ $^
  4. mymath.o:mymath.c
  5.         gcc -c $^
  6. .PHONY:clean
  7. clean:
  8.         rm -rf *.o *.a lib
  9. .PHONY:output
  10. output:
  11.         mkdir -p lib/include
  12.         mkdir -p lib/mymathlib
  13.         cp *.h lib/include
  14.         cp *.a lib/mymathlib
复制代码
make后:
  1. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson23$ ll
  2. total 28
  3. drwxrwxr-x  2 ydk_108 ydk_108 4096 Jan 24 22:18 ./
  4. drwxrwxr-x 17 ydk_108 ydk_108 4096 Jan 24 22:07 ../
  5. -rw-rw-r--  1 ydk_108 ydk_108 2024 Jan 24 22:18 libmymath.a
  6. -rw-rw-r--  1 ydk_108 ydk_108  229 Jan 24 22:18 makefile
  7. -rw-rw-r--  1 ydk_108 ydk_108  276 Jan 24 22:13 mymath.c
  8. -rw-rw-r--  1 ydk_108 ydk_108  147 Jan 24 22:12 mymath.h
  9. -rw-rw-r--  1 ydk_108 ydk_108 1848 Jan 24 22:18 mymath.o
  10. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson23$
复制代码
make output后:
  1. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson23$ make output
  2. mkdir -p lib/include
  3. mkdir -p lib/mymathlib
  4. cp *.h lib/include
  5. cp *.a lib/mymathlib
  6. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson23$ ll
  7. total 32
  8. drwxrwxr-x  3 ydk_108 ydk_108 4096 Jan 24 22:22 ./
  9. drwxrwxr-x 17 ydk_108 ydk_108 4096 Jan 24 22:07 ../
  10. drwxrwxr-x  4 ydk_108 ydk_108 4096 Jan 24 22:22 lib/
  11. -rw-rw-r--  1 ydk_108 ydk_108 2024 Jan 24 22:18 libmymath.a
  12. -rw-rw-r--  1 ydk_108 ydk_108  229 Jan 24 22:18 makefile
  13. -rw-rw-r--  1 ydk_108 ydk_108  276 Jan 24 22:13 mymath.c
  14. -rw-rw-r--  1 ydk_108 ydk_108  147 Jan 24 22:12 mymath.h
  15. -rw-rw-r--  1 ydk_108 ydk_108 1848 Jan 24 22:18 mymath.o
  16. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson23$ tree lib
  17. lib
  18. ├── include
  19. │   └── mymath.h
  20. └── mymathlib
  21.     └── libmymath.a
  22. 2 directories, 2 files
  23. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson23$
复制代码
然后在lesson23这个目次下创建test目次,把lib复制到test目次下
同时在test目次下创建main.c文件
  1. #include "lib/include/mymath.h"
  2. int main(){
  3.         printf("1+1=%d\n",add(1,1));
  4.         
  5.         return 0;
  6. }
复制代码
  假如main.c文件的头文件写的是#include "mymath.h"
  那么直接gcc是无法编译的,可以用gcc main.c -I ./lib/include/
  固然假如头文件是#include "lib/include/mymath.h"就可以直接gcc了。
  gcc编译后:
  1. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson23/test$ gcc main.c
  2. /usr/bin/ld: /tmp/ccErjU5m.o: in function `main':
  3. main.c:(.text+0x13): undefined reference to `add'
  4. collect2: error: ld returned 1 exit status
  5. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson23/test$
复制代码
由于gcc默认去体系的默认库内里找的,以是我们要加点东西:
gcc main.c -L ./lib/mymathlib/ -lmymath
这里的-L表现的是在lib库内里,
-lmymath表现是在./lib/mymathlib/库内里的libmymath.a库文件,这里要去掉lib前缀和.a后缀。-l表现库名称。
  1. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson23/test$ gcc main.c -L ./lib/mymathlib/ -lmymath
  2. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson23/test$ ll
  3. total 36
  4. drwxrwxr-x 3 ydk_108 ydk_108  4096 Jan 24 22:40 ./
  5. drwxrwxr-x 3 ydk_108 ydk_108  4096 Jan 24 22:24 ../
  6. -rwxrwxr-x 1 ydk_108 ydk_108 16872 Jan 24 22:40 a.out*
  7. drwxrwxr-x 4 ydk_108 ydk_108  4096 Jan 24 22:22 lib/
  8. -rw-rw-r-- 1 ydk_108 ydk_108    90 Jan 24 22:26 main.c
  9. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson23/test$
复制代码
但是gcc main.c -L ./lib/mymathlib/ -lmymath这个东西太长了,我们可不可以不写这么长的呢?
我们可以把mymath.h和libmymath.a放到体系默认路径下,这个操纵也叫库的安装。
如许只须要gcc main.c -lmymath就可以了。
  1. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ ll
  2. total 36
  3. drwxrwxr-x 3 ydk_108 ydk_108  4096 Jan 25 10:26 ./
  4. drwxrwxr-x 3 ydk_108 ydk_108  4096 Jan 25 10:27 ../
  5. -rwxrwxr-x 1 ydk_108 ydk_108 16872 Jan 25 10:26 a.out*
  6. drwxrwxr-x 4 ydk_108 ydk_108  4096 Jan 25 10:26 lib/
  7. -rw-rw-r-- 1 ydk_108 ydk_108    90 Jan 25 10:26 main.c
  8. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ sudo cp lib/include/mymath.h /usr/include/
  9. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ ls /usr/include/mymath.h
  10. /usr/include/mymath.h
  11. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ sudo cp lib/mymathlib/libmymath.a /lib64/
  12. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ ls /lib64/libmymath.a
  13. /lib64/libmymath.a
  14. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ gcc main.c
  15. /usr/bin/ld: /tmp/ccDIK8p6.o: in function `main':
  16. main.c:(.text+0x13): undefined reference to `add'
  17. collect2: error: ld returned 1 exit status
  18. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ gcc main.c -lmymath
  19. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ ll
  20. total 36
  21. drwxrwxr-x 3 ydk_108 ydk_108  4096 Jan 25 10:52 ./
  22. drwxrwxr-x 3 ydk_108 ydk_108  4096 Jan 25 10:27 ../
  23. -rwxrwxr-x 1 ydk_108 ydk_108 16872 Jan 25 10:52 a.out*
  24. drwxrwxr-x 4 ydk_108 ydk_108  4096 Jan 25 10:26 lib/
  25. -rw-rw-r-- 1 ydk_108 ydk_108    90 Jan 25 10:26 main.c
  26. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$
复制代码
不外不发起我们自己乱加文件,如许大概会在以后背刺自己,造成辩说。

留意:假如我们把main.c写成如许
  1. #include "lib/include/mymath.h"
  2. int main(){
  3.     printf("10/0=%d, error=%d\n",div(10,0),myerrno);
  4.     return 0;
  5. }      
复制代码
那么运行结果就是
  1. 10/0=-1, error=0
复制代码
为什么会如许呢?这里的运算一看就堕落了,为什么error不是1呢?
由于C语言默认是从右向左运算的,这里先把myerrno的值传进来才传div(10,0)的值。
我们可以修改一下代码:
  1. #include "lib/include/mymath.h"
  2. int main(){
  3.     int n = div(10,0);
  4.     printf("10/0=%d, error=%d\n",n,myerrno);
  5.     return 0;
  6. }      
复制代码
打印:
  1. 10/0=-1, error=1
复制代码
  把我们提供的方法,给别人用有两个方法:
  

  • 我把源文件直接给他
  • 把我们的源代码想办法打包成库 =库+.h
   

  • 第三方库,今后使用的时间,肯定要是用gcc-l
  • 深刻明白errno的本质
  • 假如体系中只提供静态链接,gcc则只能对该库举行静态链接
  • 假如体系中须要链接多个库,则gcc可以链接多个库
  • 不带static有动态库就动态编译,只有静态库才静态编译。带static只静态编译。
  
3.3 动态库的制作和使用原理

makefile
  1. # 定义动态库名称
  2. dy-lib=libmymethod.so
  3. # 定义静态库名称
  4. static-lib=libmymath.a
  5. # 声明all为伪目标(不是实际文件)
  6. .PHONY:all
  7. # 默认目标 - 构建动态库和静态库
  8. all: $(dy-lib) $(static-lib)
  9. # 从mymath.o创建静态库的规则
  10. $(static-lib):mymath.o
  11.         ar -rc $@ $^     # 创建归档文件,如存在则替换,创建索引
  12. mymath.o:mymath.c
  13.         gcc -c $^        # 将C文件编译为目标文件
  14. # 从mylog.o和myprint.o创建动态库的规则
  15. $(dy-lib):mylog.o myprint.o
  16.         gcc -shared -o $@ $^    # 将目标文件链接成共享库
  17. mylog.o:mylog.c
  18.         gcc -fPIC -c $^         # 使用位置无关代码编译
  19. myprint.o:myprint.c
  20.         gcc -fPIC -c $^         # 使用位置无关代码编译
  21. # 清理目标 - 删除所有生成的文件
  22. .PHONY:clean
  23. clean:
  24.         rm -rf *.o *.a *.so mylib
  25. # 输出目标 - 创建发布目录结构
  26. .PHONY:output
  27. output:
  28.         mkdir -p mylib/include  # 创建头文件目录
  29.         mkdir -p mylib/lib      # 创建库文件目录
  30.         cp *.h mylib/include    # 复制头文件
  31.         cp *.a mylib/lib        # 复制静态库
  32.         cp *.so mylib/lib       # 复制动态库
复制代码
myprint.h
  1. #pragma once
  2. #include <stdio.h>
  3. void Print();
复制代码
myprint.c
  1. #include "myprint.h"
  2. void Print()
  3. {
  4.     printf("hello new world!\n");
  5.     printf("hello new world!\n");
  6.     printf("hello new world!\n");
  7.     printf("hello new world!\n");
  8. }
复制代码
mylog.h
  1. #pragma once
  2. #include <stdio.h>
  3. void Log(const char*);
复制代码
mylog.c
  1. #include "mylog.h"
  2. void Log(const char*info)
  3. {
  4.     printf("Warning: %s\n", info);
  5. }
复制代码
然后编译:make ; make output
  1. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24$ make ; make output
  2. gcc -fPIC -c mylog.c
  3. gcc -fPIC -c myprint.c
  4. gcc -shared -o libmymethod.so mylog.o myprint.o
  5. gcc -c mymath.c
  6. ar -rc libmymath.a mymath.o
  7. mkdir -p mylib/include
  8. mkdir -p mylib/lib
  9. cp *.h mylib/include
  10. cp *.a mylib/lib
  11. cp *.so mylib/lib
  12. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24$ ll
  13. total 76
  14. drwxrwxr-x  4 ydk_108 ydk_108  4096 Jan 25 13:50 ./
  15. drwxrwxr-x 18 ydk_108 ydk_108  4096 Jan 25 10:26 ../
  16. -rw-rw-r--  1 ydk_108 ydk_108  2024 Jan 25 13:50 libmymath.a
  17. -rwxrwxr-x  1 ydk_108 ydk_108 16312 Jan 25 13:50 libmymethod.so*
  18. -rw-rw-r--  1 ydk_108 ydk_108   448 Jan 25 13:34 makefile
  19. drwxrwxr-x  4 ydk_108 ydk_108  4096 Jan 25 13:50 mylib/
  20. -rw-rw-r--  1 ydk_108 ydk_108    85 Jan 25 13:34 mylog.c
  21. -rw-rw-r--  1 ydk_108 ydk_108    58 Jan 25 13:34 mylog.h
  22. -rw-rw-r--  1 ydk_108 ydk_108  1704 Jan 25 13:50 mylog.o
  23. -rw-rw-r--  1 ydk_108 ydk_108   276 Jan 25 10:26 mymath.c
  24. -rw-rw-r--  1 ydk_108 ydk_108   147 Jan 25 10:26 mymath.h
  25. -rw-rw-r--  1 ydk_108 ydk_108  1848 Jan 25 13:50 mymath.o
  26. -rw-rw-r--  1 ydk_108 ydk_108   176 Jan 25 13:35 myprint.c
  27. -rw-rw-r--  1 ydk_108 ydk_108    49 Jan 25 13:35 myprint.h
  28. -rw-rw-r--  1 ydk_108 ydk_108  1864 Jan 25 13:50 myprint.o
  29. drwxrwxr-x  3 ydk_108 ydk_108  4096 Jan 25 10:52 test/
  30. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24$ tree mylib
  31. mylib
  32. ├── include
  33. │   ├── mylog.h
  34. │   ├── mymath.h
  35. │   └── myprint.h
  36. └── lib
  37.     ├── libmymath.a
  38.     └── libmymethod.so
  39. 2 directories, 5 files
  40. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24$
复制代码
  这里的实行过程是:
  

  • 起首实行 make,由于没有指定目标,以是默认实行 Makefile 中的第一个目标 all,完玉成部库文件的编译和创建
  • 然后实行 make output,创建目次结构并复制文件
  如许写的缘故起因是:
  

  • 必须先实行 make 天生全部的库文件(.so和.a)
  • 再实行 make output 举行文件整理和复制
  • 假如直接实行 make output,大概会由于库文件还未天生而导致复制失败
  然后我们把库复制进test文件夹内里,而且把main.c文件改一下:
  1. #include "mylog.h"
  2. #include "myprint.h"
  3. int main()
  4. {
  5.     Print();
  6.     Log("hello log function");
  7.     return 0;
  8. }
复制代码
运行
  1. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ ll
  2. total 40
  3. drwxrwxr-x 4 ydk_108 ydk_108  4096 Jan 25 14:00 ./
  4. drwxrwxr-x 4 ydk_108 ydk_108  4096 Jan 25 13:50 ../
  5. -rwxrwxr-x 1 ydk_108 ydk_108 16872 Jan 25 10:52 a.out* # 之前静态编译留下的
  6. drwxrwxr-x 4 ydk_108 ydk_108  4096 Jan 25 10:26 lib/
  7. -rw-rw-r-- 1 ydk_108 ydk_108   116 Jan 25 13:57 main.c
  8. drwxrwxr-x 4 ydk_108 ydk_108  4096 Jan 25 14:00 mylib/
  9. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ gcc main.c -I mylib/include/ -L mylib/lib -lmymethod
  10. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ ll
  11. total 40
  12. drwxrwxr-x 4 ydk_108 ydk_108  4096 Jan 25 14:00 ./
  13. drwxrwxr-x 4 ydk_108 ydk_108  4096 Jan 25 13:50 ../
  14. -rwxrwxr-x 1 ydk_108 ydk_108 16712 Jan 25 14:00 a.out* # 现在动态编译新生成的
  15. drwxrwxr-x 4 ydk_108 ydk_108  4096 Jan 25 10:26 lib/
  16. -rw-rw-r-- 1 ydk_108 ydk_108   116 Jan 25 13:57 main.c
  17. drwxrwxr-x 4 ydk_108 ydk_108  4096 Jan 25 14:00 mylib/
  18. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$
复制代码
固然编译过了,但是一运行就如许了:
  1. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ ./a.out
  2. ./a.out: error while loading shared libraries: libmymethod.so: cannot open shared object file: No such file or directory
复制代码
  为什么呢?
  我们之前编译的时间告诉编译器我们的动态库在那边了,但是我们编译后,并没有告诉体系(即加载器)我们的动态库在那边。
  可以将自己库所在的路径,添加到体系的情况变量LD_LIBRARY_PATH中。
  1. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ ldd a.out
  2.         linux-vdso.so.1 (0x00007ffc9cd79000)
  3.         libmymethod.so => not found
  4.         libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa1947d3000)
  5.         /lib64/ld-linux-x86-64.so.2 (0x00007fa1949d3000)
  6. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/ydk_108/108/lesson24/test/mylib/lib
  7. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ echo $LD_LIBRARY_PATH
  8. ::/home/ydk_108/108/lesson24/test/mylib/lib
  9. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ ldd a.out
  10.         linux-vdso.so.1 (0x00007ffd6835f000)
  11.         libmymethod.so => /home/ydk_108/108/lesson24/test/mylib/lib/libmymethod.so (0x00007f105f59b000)
  12.         libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f105f3a2000)
  13.         /lib64/ld-linux-x86-64.so.2 (0x00007f105f5a7000)
  14. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ ./a.out
  15. hello new world!
  16. hello new world!
  17. hello new world!
  18. hello new world!
  19. Warning: hello log function
  20. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$
复制代码

  1. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ su
  2. Password:
  3. root@iZuf68hz06p6s2809gl3i1Z:/home/ydk_108/108/lesson24/test# cd /etc/ld.so.conf.d
  4. root@iZuf68hz06p6s2809gl3i1Z:/etc/ld.so.conf.d# ll
  5. total 20
  6. drwxr-xr-x  2 root root 4096 Jun  3  2024 ./
  7. drwxr-xr-x 89 root root 4096 Jan 14 19:45 ../
  8. -rw-r--r--  1 root root   38 Sep  7  2019 fakeroot-x86_64-linux-gnu.conf
  9. -rw-r--r--  1 root root   44 Apr 15  2020 libc.conf
  10. -rw-r--r--  1 root root  100 Apr 15  2020 x86_64-linux-gnu.conf
  11. root@iZuf68hz06p6s2809gl3i1Z:/etc/ld.so.conf.d# touch ydk_108.conf
  12. root@iZuf68hz06p6s2809gl3i1Z:/etc/ld.so.conf.d# ll
  13. total 20
  14. drwxr-xr-x  2 root root 4096 Jan 25 14:25 ./
  15. drwxr-xr-x 89 root root 4096 Jan 14 19:45 ../
  16. -rw-r--r--  1 root root   38 Sep  7  2019 fakeroot-x86_64-linux-gnu.conf
  17. -rw-r--r--  1 root root   44 Apr 15  2020 libc.conf
  18. -rw-r--r--  1 root root  100 Apr 15  2020 x86_64-linux-gnu.conf
  19. -rw-r--r--  1 root root    0 Jan 25 14:25 ydk_108.conf
  20. root@iZuf68hz06p6s2809gl3i1Z:/etc/ld.so.conf.d# pwd
  21. /etc/ld.so.conf.d
  22. root@iZuf68hz06p6s2809gl3i1Z:/etc/ld.so.conf.d# vim ydk_108.conf
  23. root@iZuf68hz06p6s2809gl3i1Z:/etc/ld.so.conf.d# ldconfig
  24. root@iZuf68hz06p6s2809gl3i1Z:/etc/ld.so.conf.d#
复制代码
  1. # ldconfig前
  2. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ ldd a.out
  3.         linux-vdso.so.1 (0x00007ffc8e125000)
  4.         libmymethod.so => not found
  5.         libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4e24c2d000)
  6.         /lib64/ld-linux-x86-64.so.2 (0x00007f4e24e2d000)
  7. # ldconfig后
  8. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$ ldd a.out
  9.         linux-vdso.so.1 (0x00007fffa231c000)
  10.         libmymethod.so => /home/ydk_108/108/lesson24/test/mylib/lib/libmymethod.so (0x00007f9b2d7b8000)
  11.         libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9b2d5c6000)
  12.         /lib64/ld-linux-x86-64.so.2 (0x00007f9b2d7cb000)
  13. ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson24/test$
复制代码
  办理加载找不到动态库的方法:
  

  • 拷贝到体系默认的库路径 /ib64 /usr/lib64/
  • 在体系默认的库路径 /ib64 /usr/lib64/下创建软毗连
  • 将自己的库所在的路径,添加到体系的情况变量LD_LIBRARY_PATH中。(重启就消散了)
  • /etc/ld.so.conf.d 创建自己的动态库路径的设置文件(名字任意写,内里路径写对就行),然后重新ldconfig即可。(重启不会消散)
  现实情况,我们用的库都是别人的成熟的库,都采取直接安装到体系的方式。

3.3.1 动态库是怎么被加载的

   动态库(共享库)的共享机制:
  

  • 内存共享机制
  

  • 当第一个历程加载动态库时,动态库的代码段被加载到物理内存中
  • 后续历程再使用这个动态库时,不会重新加载代码段,而是直接映射到已加载的物理内存
  • 多个历程共享同一份物理内存中的代码段,节省内存资源
  • 每个历程有自己的数据段副本,确保数据隔离
  动态库在历程运行的时间,是要被加载的(静态库没有)
  以是,动态库在体系中加载之后,会被全部历程共享。
  

这个共享库一旦被多个历程共享,那么它对应的页就会引入计数2,缺页停止的时间,辨认发现是被多个历程共享的就会写时拷贝。

3.4 关于地点

   步调没有加载前的地点(步调)
  步调编译好之后,内部有地点的概念吗?
  有的。(可以遐想之前C++多态的虚函数表)
    库可以在假造内存中,恣意位置加载。
  怎么做到的呢?
  让自己内部函数不要采取绝对编址,只表现每个函数在库中的偏移量即可。
  比方:printf的地点0x1122,这个0x1122代表printf相对于库的起始地点的偏移量。
  然后加载动态库的时间,在地点空间里任意放。只须要记取这个库在假造地点空间的起始地点就可以了。
  表明:为什么动态库可以被加载到恣意位置,而且多个历程可以共享同一份代码?

  • 假设有一个动态库 libexample.so:
  1. 起始位置: 未知 (加载时才确定)
  2. 函数A: +0x100 (偏移量)
  3. 函数B: +0x200 (偏移量)
  4. 函数C: +0x300 (偏移量)
复制代码

  • 差别历程加载时的情况:
  1. 进程1:
  2. - 库加载到虚拟地址 0x10000000
  3. - 函数A实际地址 = 0x10000000 + 0x100 = 0x10000100
  4. - 函数B实际地址 = 0x10000000 + 0x200 = 0x10000200
  5. 进程2:
  6. - 库加载到虚拟地址 0x20000000
  7. - 函数A实际地址 = 0x20000000 + 0x100 = 0x20000100
  8. - 函数B实际地址 = 0x20000000 + 0x200 = 0x20000200
复制代码

  • 工作原理:


  • 编译时:函数地点全部用偏移量表现
  • 加载时:

    • 动态链接器选择一个可用的假造地点空间
    • 纪录库的基地点
    • 全部函数调用时:现实地点 = 基地点 + 偏移量

这就好比:


  • 一本书的目次不消页码,而用"隔断书开始的页数"
  • 无论这本书放在书架的哪个位置(起始地点)
  • 只要知道书在哪(基地点),就能通过偏移量找到每个章节
这也就是为什么fPIC叫做产生位置无关码。
   

  • 静态库为什么不谈加载呢?
  由于静态库会直接把步调拷贝到可实行步调内里,就谈不上加载了。
  

  • 静态库为什么不说与位置无关呢?
  由于库方法拷贝到可实行步调里后,就不谈偏移量了。他在什么位置就是确定的了。
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表