连接器
库查询
重定位
重定向就是重新绑定地址,
重定向的发展
操作系统出现前,程序独占内存,运行前能确定运行地址。重定向在连接时确定。
操作系统出现后,程序共用内存。运行时确定运行地址。重定向在加载时确定。这时覆盖技术出现。
虚拟内存出现后,程序独占内存,连接时确定地址。覆盖技术淘汰。
静态库动态库与重定位
静态库
静态库在生成时完成一次地址绑定,连接时被调用的例程引入程序,并重定位。
动态库
程序运行前不会绑定地址
符号解析
程序互相运用通过符号进行,如主程序调用库函数sqrt,连接器通过表明分配给sqrt的地址来解析这个符号,并且修改代码使call命令能调用该地址。
连接器的两遍链接
(1)输入连接器
目标文件和库文件等,作为连接器的输入,他们有两个内容,一系列段的集合,符号表,
符号表有导入符号,导出符号,导入符号为文件引用,但未定义,导出符号,文件定义,并被其它文件引用。
(2)第一次扫描
扫描所有输入的段信息和符号表,根据段信息得到输出程序的内存分布,并制作段表和包含所有符号的符号表。
(3)第二次扫描
利用第一次扫描控制连接过程,进行重定位,包括,将符号替换成地址,调整代码和数据分布以反应重定位段地址。将结果写入目标文件,并添加文件头信息,和段信息,和符号表
静态数据 地址表
大端小端
内存地址
内存表现为一篇连续的存储空间,从0开始增长到一个较大的值,具体由地址的位数决定。
内存单元
一个内存单元由多个位组成,现在由8个位组成。称为1个字节。
将连续的多个字节组合,构成16位,32位,64位。
字节以上就是字,字代表计算机一次运算处理的位,32位机上,一个字是32位,64位就是双字,64位机上,一个字是64位。
大端小端
由多个字节表示信息时,由两种方式,
大端
简明区分
下面以unsigned int value = 0x12345678为例,分别看看在两种字节序下其存储情况,我们可以用unsigned char buf[4]来表示value
Big-Endian: 低地址存放高位,如下:
高地址 这和阅读习惯一致
---------------
buf[3] (0x78) -- 低位
buf[2] (0x56)
buf[1] (0x34)
buf[0] (0x12) -- 高位
---------------
低地址
Little-Endian: 低地址存放低位,如下:
高地址
---------------
buf[3] (0x12) -- 高位
buf[2] (0x34)
buf[1] (0x56)
buf[0] (0x78) -- 低位
--------------
内存对齐
指令格式
一般格式
操作码 + 操作数
操作码 表示操作的类型,如内存/寄存器读/写,
操作数 可能是 地址 也可能是 字面值
寻址方式
最早内存小任何一个内存单元都能存下地址,现在内存大,为了节省空间,使用间接寻址,分为索引寻址,基质寻址,两者区别是寄存器中放基质还是偏移量。
调用过程
调用过程涉及 本地变量,静态变量,返回地址,调用者传参。
函数调用时必须要记录返回地址,两种记录方法,记录在寄存器,或栈空间。
本地变量和调用者传参,通常的解决方法是每调用一个函数分配一个栈框架,使用一个栈帧指针指向栈框架,另外用一个寄存器存放偏移量,访问栈数据,栈框架一方为本地变量,一方为传参。
静态变量,存储在数据段,为了方便使用,编译器会制作一个静态变量的地址表,用一个指针指向这个地址表,作为基址,另一个寄存器做偏移。
虚拟内存
将虚拟内存分为相同大小的页,物理内存也分为该大小页框。
页表记录页对应的实际页框,若无则标记不存在。
虚拟内存是对应用程序透明的,如发生缺页,操作系统暂停进程,将代码从磁盘交换到内存,再继续进程运行。
缺页因为涉及磁盘读写,会将一条指令的执行效率拉低一个数量级。
解决缺页的方法。
将有关联的例程放到一个页中。
设置只读页。
虚拟内存的另一个问题是减去内存占用。
方法是多级页表。
映射文件
将文件系统和换页系统统一,
将程序将文件映射到换页系统,并将对应的页设置为不存在,程序读该页时,文件会交换到内存。
这种映射有3种 只读 读写 写复制
共享库
共享的意思是 多个地址空间共享程序或程序库的单一副本。
共享库的原理
实现共享库需要 很多程序的合作
操作系统 将可执行程序文件映射到每个程序的地址空间。对于程序部分用 只读 映射,对于全局数据使用写复制映射,全局数据使用指针表管理。
编译器 制作地址无关码的程序,即如跳转指令使用相对跳转,对于本地变量使用栈帧指针做基址,所以不需要重定位,需要管理的就是静态数据。
库查询
重定位
重定向就是重新绑定地址,
重定向的发展
操作系统出现前,程序独占内存,运行前能确定运行地址。重定向在连接时确定。
操作系统出现后,程序共用内存。运行时确定运行地址。重定向在加载时确定。这时覆盖技术出现。
虚拟内存出现后,程序独占内存,连接时确定地址。覆盖技术淘汰。
静态库动态库与重定位
静态库
静态库在生成时完成一次地址绑定,连接时被调用的例程引入程序,并重定位。
动态库
程序运行前不会绑定地址
符号解析
程序互相运用通过符号进行,如主程序调用库函数sqrt,连接器通过表明分配给sqrt的地址来解析这个符号,并且修改代码使call命令能调用该地址。
连接器的两遍链接
(1)输入连接器
目标文件和库文件等,作为连接器的输入,他们有两个内容,一系列段的集合,符号表,
符号表有导入符号,导出符号,导入符号为文件引用,但未定义,导出符号,文件定义,并被其它文件引用。
(2)第一次扫描
扫描所有输入的段信息和符号表,根据段信息得到输出程序的内存分布,并制作段表和包含所有符号的符号表。
(3)第二次扫描
利用第一次扫描控制连接过程,进行重定位,包括,将符号替换成地址,调整代码和数据分布以反应重定位段地址。将结果写入目标文件,并添加文件头信息,和段信息,和符号表
静态数据 地址表
大端小端
内存地址
内存表现为一篇连续的存储空间,从0开始增长到一个较大的值,具体由地址的位数决定。
内存单元
一个内存单元由多个位组成,现在由8个位组成。称为1个字节。
将连续的多个字节组合,构成16位,32位,64位。
字节以上就是字,字代表计算机一次运算处理的位,32位机上,一个字是32位,64位就是双字,64位机上,一个字是64位。
大端小端
由多个字节表示信息时,由两种方式,
大端
简明区分
下面以unsigned int value = 0x12345678为例,分别看看在两种字节序下其存储情况,我们可以用unsigned char buf[4]来表示value
Big-Endian: 低地址存放高位,如下:
高地址 这和阅读习惯一致
---------------
buf[3] (0x78) -- 低位
buf[2] (0x56)
buf[1] (0x34)
buf[0] (0x12) -- 高位
---------------
低地址
Little-Endian: 低地址存放低位,如下:
高地址
---------------
buf[3] (0x12) -- 高位
buf[2] (0x34)
buf[1] (0x56)
buf[0] (0x78) -- 低位
--------------
内存对齐
指令格式
一般格式
操作码 + 操作数
操作码 表示操作的类型,如内存/寄存器读/写,
操作数 可能是 地址 也可能是 字面值
寻址方式
最早内存小任何一个内存单元都能存下地址,现在内存大,为了节省空间,使用间接寻址,分为索引寻址,基质寻址,两者区别是寄存器中放基质还是偏移量。
调用过程
调用过程涉及 本地变量,静态变量,返回地址,调用者传参。
函数调用时必须要记录返回地址,两种记录方法,记录在寄存器,或栈空间。
本地变量和调用者传参,通常的解决方法是每调用一个函数分配一个栈框架,使用一个栈帧指针指向栈框架,另外用一个寄存器存放偏移量,访问栈数据,栈框架一方为本地变量,一方为传参。
静态变量,存储在数据段,为了方便使用,编译器会制作一个静态变量的地址表,用一个指针指向这个地址表,作为基址,另一个寄存器做偏移。
虚拟内存
将虚拟内存分为相同大小的页,物理内存也分为该大小页框。
页表记录页对应的实际页框,若无则标记不存在。
虚拟内存是对应用程序透明的,如发生缺页,操作系统暂停进程,将代码从磁盘交换到内存,再继续进程运行。
缺页因为涉及磁盘读写,会将一条指令的执行效率拉低一个数量级。
解决缺页的方法。
将有关联的例程放到一个页中。
设置只读页。
虚拟内存的另一个问题是减去内存占用。
方法是多级页表。
映射文件
将文件系统和换页系统统一,
将程序将文件映射到换页系统,并将对应的页设置为不存在,程序读该页时,文件会交换到内存。
这种映射有3种 只读 读写 写复制
共享库
共享的意思是 多个地址空间共享程序或程序库的单一副本。
共享库的原理
实现共享库需要 很多程序的合作
操作系统 将可执行程序文件映射到每个程序的地址空间。对于程序部分用 只读 映射,对于全局数据使用写复制映射,全局数据使用指针表管理。
编译器 制作地址无关码的程序,即如跳转指令使用相对跳转,对于本地变量使用栈帧指针做基址,所以不需要重定位,需要管理的就是静态数据。