网站功能模块 分析,百度申诉网站,中国移动网络优化做什么的,网站建设步骤 文档目录
静态库
动态库
目标文件
ELF文件
ELF形成可执行
ELF可执行加载 ELF加载
全局偏移量表GOT(global offset table) 库是写好的#xff0c;成熟的#xff0c;可以复用的代码
现实中每个程序都要依赖很多的基础的底层库#xff0c;不可能都是从零开始的
库有两种…目录
静态库
动态库
目标文件
ELF文件
ELF形成可执行
ELF可执行加载 ELF加载
全局偏移量表GOT(global offset table) 库是写好的成熟的可以复用的代码
现实中每个程序都要依赖很多的基础的底层库不可能都是从零开始的
库有两种
静态库 .a[Linux]、.lib[windows]动态库 .so[Linux]、.dll[windows]
静态库
程序在编译链接的时候把库的代码链接到可执行文件中程序运行的时候将不再需要静态库 一个可执行程序可能用到多个库这些库可能有的是静态库有的是动态库而我们编译默认链接为动态库只有在该库下找不到动态.so的时候才会采用同名静态库。 若是想使用静态库我们可以使用gcc的 -static 强转设置链接静态库 静态库的生成
ar -rc libmylib.a mylib.o 若我们有一个自己写的库叫mylib那么我们该如何使用它呢 若头文件和库文件都被我们安装到系统的路径下 /usr/lib、/usr/lib64、/usr/local/lib等等 gcc main.c -lmystdio 头文件和库文件和我们自己的源文件在同一个路径下
gcc main.c -L. -lmylib
头文件和库文件都有自己独立的路径
gcc main.c -I头⽂件路径 -L库⽂件路径 -lmylib -L指定库路径-I指定头文件搜索路径-l指定库名
动态库
程序在运行的时候才去链接动态库多个程序可以共享使用库的代码
一个与动态库链接的可执行程序仅仅包含它用到的函数入口地址的一个表而不是外部函数所在目标文件的整个机器码
在可执行文件开始运行以前外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中这个过程称为动态链接
动态库可以在多个程序间共享所以动态链接使得可执行文件更小节省了磁盘的空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用节省了内存和磁盘空间
动态库的生成
gcc -fPIC -c main.c -o mylib.o
gcc -o libmylib.so mylib.o -shared
动态库需要使用位置无关码PIC因此需要加上 -fPIC选项
动态库的命名约定通常以lib开头后缀为.so
shared表示生成共享库格式fPIC产生位置无关码库名规则libxxx.so
动态库使用
若头文件和库文件都被我们安装到系统的路径下
gcc main.c -lmylib
头文件和库文件和我们自己的源文件在同一个路径下
gcc main.c -L. -lmylib
头文件和库文件都有自己独立的路径
gcc main.c -I头⽂件路径 -L库⽂件路径 -lmylib
我们可以使用ldd命令来查看库或者可执行程序的依赖
ldd libmylib.so
目标文件
在编译之后会产生扩展名为.o的文件它们被称作目标文件
若是我们有多个源文件需要修改其中一个那么我们只需要编译这一个为目标文件再一起链接这样就不需要浪费时间重新编译整个工程
目标文件是一个二进制文件文件的格式是ELF是对二进制代码的一种封装
ELF文件
以下四种都是ELF文件
可重定位文件即xxx.o文件。包含适合于与其他⽬标⽂件链接来创建可执⾏⽂件或者共享⽬标⽂件的代码和数据可执行文件即可执行程序共享目标文件即 xxx.so⽂件内核转储存放当前进程的执⾏上下⽂⽤于dump信号触发
一个ELF文件由四个部分组成
ELF头ELF header描述⽂件的主要特性。其位于⽂件的开始位置它的主要⽬的是定位⽂件的其他部分程序头表Program header table列举了所有有效的段(segments)和他们的属性。表⾥ 记着每个段的开始的位置和位移offset、⻓度毕竟这些段都是紧密的放在⼆进制⽂件中需要段表的描述信息才能把他们每个段分割开 节头表Section header table包含对节(sections)的描述节SectionELF⽂件中的基本组成单位包含了特定类型的数据。ELF⽂件的各种信息和数据都存储在不同的节中如代码节存储了可执⾏代码数据节存储了全局变量和静态数据等
常见的节有
代码节.text⽤于保存机器指令是程序的主要执⾏部分数据节.data保存已初始化的全局变量和局部静态变量 ELF形成可执行
1. 首先将多份C/C源代码翻译称为目标.o文件
2. 将多份.o文件Section进行合并 ELF可执行加载
⼀个ELF会有多种不同的Section在加载到内存的时候也会进⾏Section合并形成segment
合并原则相同属性⽐如可读可写可执⾏需要加载时申请空间等。这样即便是不同的Section在加载到内存中可能会以segment的形式加载到⼀起 很显然这个合并⼯作也已经在形成ELF的时候合并⽅式已经确定了具体合并原则被记录在了 ELF的 程序头表 (Program header table) 中 Section合并的主要原因是为了减少⻚⾯碎⽚提⾼内存使⽤效率 ELF加载 ⼀个ELF程序在没有被加载到内存的时候,本来就有地址当代计算机⼯作的时候都采⽤平坦 模式进⾏⼯作。 用来初始化的数据也是从ELF的各个segment来每个segment有自己的起始地址和长度用来初始化内核结构中[start, end]等范围的数据 程序调用库方法只需要知道库的起始虚拟地址方法偏移量即可定位库中的⽅法 我们的程序运⾏之前先把所有库加载并映射所有库的起始虚拟地址都应该提前知道 对我们加载到内存中的程序的库函数调⽤进⾏地址修改在内存中⼆次完成地址设置(这个叫做加载地址重定位) 但是代码区是可读的怎么能修改呢 全局偏移量表GOT(global offset table) 动态链接采⽤的做法是在 .data 可执⾏程序或者库⾃⼰中专⻔预留⼀⽚区域⽤来存放函数的跳转地址它也被叫做全局偏移表GOT表中每⼀项都是本运⾏模块要引⽤的⼀个全局变量或函数的地址 因为.data区域是可读写的所以可以⽀持动态进⾏修改 有了GOT表代码便可以被所有进程共享。但在不同进程的地址空间中各动态库的绝对地址、相对位置都不同。每个动态库都有独⽴的GOT表所以进程间不能共享GOT表 完