1、预备知识

1.1、地址概念

连接地址<>运行地址
存储地址<>加载地址

加载时地址就是程序放置的地址
运行地址就是程序定位的绝对地址,也即在编译连接时定位的地址。
first 0x30000000 : AT(0){main.o},表示运行地址为0x30000000,加载地址为0

如果程序是在flash里运行,则运行地址和加载地址是相同的。
如果程序是在ram里运行,但程序是存储在flash里,则运行地址指向ram,而加载地址是指向flash

1.2、位置代码

位置无关码:指令只使用相对地址
位置有关码:指令使用过一次或多次绝对地址

在程序运行初期,只有小部分内存初始化完成,因此只会加载程序的一部分执行,之一部分代码一定需要为
位置无关码,因为加入指使用较大的绝对地址,会越界到不可访问内存。

2、库

2.1、静态库

1、静态库是由编译中间产物.O文件,通过AR命令打包而成的。
1、gcc st_lib.c -o st_lib.o -c
2、ar -rc st_lib.a st_lib.o

     arm-linux-ar –t st_lib.a 该命令可以看看libgcc.a中有多少个.o文件arm-linux-nm –a st_lib.a该命令可以看看libgcc.a中定义的符号情况
2、使用1、静态连接静态库gcc main.c  -o main -lst_lib -L./st_lib -static2、动态链接静态库(实际静态库已复制到main中,即静态库无法动态链接)gcc main.c  -o main -lst_lib -L./st_lib3、重定位(静态链接)使用静态库的代码实际是把整个静态库复制到自己的代码段,因此需要对静态库内容做重定位,同时说明静态库是Relocatable的

objdump -d st_lib.a会发现里面定义的函数的起始地址是0,说明静态库内的函数没有实际地址(就连调用printf的call也是用的相对地址)
再看看main可执行文件objdump -d main:

此时的main函数以及test函数都有了明确的运行地址(实际是链接器根据链接脚本的链接地址指定的)
可以验证下是否真的是运行地址
gdb main b test
可以看到地址相同
也可以在函数中打印出__executable_start的地址来确认,之所以运行地址在400000附近,是由于默认链接脚本这样指定的
ld -verbose来查看链接脚本中指定的运行地址:

2.2、动态库

1、制作1、gcc dt_lib.c -o dt_lib.o –fPIC实际也是生成可重定位文件,但是加上fPIC后加了fPIC实现真正意义上的多个进程共享so文件。因为fPIC可以生成位置无关码,即so内的所有跳转全部是基于GOT+偏移实现,没有绝对地址的参与。这样多个进程引用同一个 PIC 动态库时,可以共用内存。这一个库在不同进程中的虚拟地址不同,但操作系统显然会把它们映射到同一块物理内存上。

对于不加-fPIC的,不加fPIC,则加载so文件时,需要对代码段引用的数据对象需要重定位,重定位会修改代码段的内容,这就造成每个使用这个.so文件代码段的进程在内核里都会生成这个.so文件代码段的copy.每个copy都不一样,取决于这个.so文件代码段和数据段内存映射的位置。
可见,这种方式更消耗内存。但是不加fPIC编译的 so文件的优点是加载速度比较快,但是实测,不加fPIC生成的o文件根本无法生成so
2、gcc -shared -o libtest.so dt_lib.o

2、使用
gcc main.c -L lib -l test
动态库只能默认动态链接,无法静态链接

3、链接

3.1、静态链接

1、段合并各个o文件、a文件相同段合并
2、重定位.a文件中的函数地址都是0,说明此时并未确定地址,等到与其他c文件、so文件等链接成可执行文件后便有了地址,那么链接器如何知道哪些符号需要重定位,又是怎么重定位的呢?首先只编译不链接可执行文件,得到中间文件并查看其符号表


其中有一个函数func1为定义,而这个函数就是a文件中定义的,因此编译器就是将符号表中未定义的函数进行重定位
再看重定位过程,首先依次读取链接与未链接的可执行文件
objdump -d main.o
objdump -d main.out
得到如下结果:

在main.o中,main函数没有地址,而func1与其偏移为0x18
链接完成的main.out中,由于main函数由链接脚本指定了运行基地址,因此自己的运行的地址也可确定为0x400526,而此时func1的函数运行地址为0x40053b,相差为0x15。

3.2、动态链接

既然动态链接去链接动态库并不是拷贝,那么各个进程使用动态库的进程是如何确定动态库函数的运行地址呢?这就是动态链接要做的事

使用上面编译出的main可执行文件
objdump -d main

代码段并没有libtest.so中的test函数,但是main函数调用了test@plt,去这个函数的地址看一下:

先跳转到0x601030,然后跳到0x40050,使用objdump –h main看一下地址分布:


这个貌似都是符号表存放地址
使用gdb调试查看
gdb main
disass main

在跳转到test@plt函数时打断点
b 0x400580
run
si
p/x $pc //每执行一步,打印一次pc,可以发现最后跑到了
0x400540
si

因此可推断,在plt表内存储了dl可执行文件的加载地址,程序运行到这才真正调用ld可执行文件去查找、重定位具体的so.所以动态链接在编译时,并没有确定so的运行地址,而是通过其他方法在运行时动态重定位的,因此才称起为动态链接。
另外,动态库的数据段是可读写的,多个进程同时使用是不行的,因此对于数据段(全局、局部静态变量),是采取COW(copy on write)方式来进行隔离。代码段是只读的,但是对于同一函数同时被不同进程调用,同样会出现重入问题,此时可考虑使用进程共享的互斥锁进行锁定。

动态库静态库的链接过程相关推荐

  1. VS2015编译32位Opencv310(动态库+静态库,文末有下载链接)

    VS2015编译32位Opencv310(动态库+静态库 编译过得,可以直接用的: http://download.csdn.net/download/longzaihuaxia/9802510 之前 ...

  2. CMake 添加头文件目录,链接动态、静态库(添加子文件夹)

    CMake支持大写.小写.混合大小写的命令. 当编译一个需要第三方库的项目时,需要知道: 去哪找头文件(.h),-I(GCC) INCLUDE_DIRECTORIES() 去哪找库文件(.so/.dl ...

  3. cmake中添加引用动态链接_CMake 添加头文件目录,链接动态、静态库(添加子文件夹)...

    CMake支持大写.小写.混合大小写的命令. 当编译一个需要第三方库的项目时,需要知道: 去哪找头文件(.h),-I(GCC) INCLUDE_DIRECTORIES() 去哪找库文件(.so/.dl ...

  4. c语言makecode头文件,cmake 添加头文件目录,链接动态、静态库

    罗列一下cmake常用的命令. CMake支持大写.小写.混合大小写的命令. 1. 添加头文件目录INCLUDE_DIRECTORIES 语法: include_directories([AFTER| ...

  5. 硬核拆解动态库静态库

    [Github pages] 动态库与静态库是编程中十分常见的玩意儿,但是如此常见的东西在我真正用心去了解梳理过一遍之后才发现原来这里面有这么多的门道.本文就介绍一波 Linux 平台下,特指 GCC ...

  6. linux库引入之动态库静态库(生成和使用)

    库: 库是一种可执行代码的二进制形式,可以被操作系统载入内存执行.就是将源代码转化为二进制格式的源代码,相当于进行了加密,别人可以使用库,但是看不到库中的内容. 如何使用 用户需要同时具有头文件和库. ...

  7. linux系统应用学习(三)--- 动态库静态库

    动态库静态库 库文件:一般指第三方提供的可调用的库函数文件,库文件封存的是函数体,即.c文件里面的内容. 动态库      静态库 Windows下:        xx.dll            ...

  8. linux库--静态库、动态库

    文章目录 一.分文件编程思想 二.动态库静态库 1.概念介绍 2.静态库的制作和使用 3.动态库的制作和使用 一.分文件编程思想 好处: 分模块的编程思想 例如: 网络 a 超声波b 电机c a.功能 ...

  9. cmake 添加头文件目录,链接动态、静态库

    罗列一下cmake常用的命令. CMake支持大写.小写.混合大小写的命令. 1. 添加头文件目录INCLUDE_DIRECTORIES 语法: include_directories([AFTER| ...

  10. linux gcc 包含头文件 动态库 静态库 链接路径问题

    C/C++程序在linux下被编译和连接时,GCC/G++会查找系统默认的include和link的路径,以及自己在编译命令中指定的路径.自己指定的路径就不说了,这里说明一下系统自动搜索的路径. [1 ...

最新文章

  1. HTML基础部分(2)表格
  2. 深职院计算机学院教室,机电学院计算机专业赴深职院为国赛训练取经
  3. 图解全球无人驾驶产业链:这些公司在主宰人类出行的未来
  4. 网站SEO优化中长尾关键词的特征有哪些?
  5. jquery可见性选择器(匹配匹配所有显示的元素)
  6. 留下方便自己找,,,求导
  7. OpenGL延迟着色之一
  8. 加速Javascript:DOM操作优化
  9. OpenCV3.0或OpenCV3.1的SVM操作
  10. ssh key加密解密原理
  11. c 语言 realloc 源码,C语言,realloc
  12. vsftpd出现500 OOPS: cannot change directory的解决办法
  13. 虚拟化安全:瑞星的下一个战场
  14. python3 ImageTk 安装方法
  15. 介绍一篇路端传感器的cooperative perception(3D目标检测)论文
  16. 读博天赋更重要还是努力更重要?
  17. paip.若只如初见——WEB或BS开发必备基础知识
  18. 随机过程之平稳过程与各态历经过程
  19. 计算机有网络却不能上网,电脑有网络,但是浏览器不能上网怎么办
  20. Mac下的常用快捷键操作

热门文章

  1. Windows 2003声卡驱动的安装.
  2. php jquery alert 美化,jquery插件hiAlert实现网页对话框美化_jquery
  3. mkv格式提取文件方法
  4. C#.NET彩票数据分析
  5. C++之STL-vector-string-list-deque-queue-map-文件操作
  6. 视频教程-VB程序设计入门基础-其他
  7. 小米 线刷 android,小米10 Android 11 Beta 1线刷包已放出,安卓11/MIUI 12二选一
  8. 网络空间安全态势感知技术
  9. 17.敏捷项目管理流程实例 - 整体流程框架
  10. Linux 终端快捷键