程序链接和加载

ELF和静态链接
1,程序编绎、汇编成多个目标文件、链接器链接多个目标文件及调用的库文件生成可执行文件,加载器加载可执行文件到内存中,CPU从内存读取指令和数据执行程序。
2,在Linux下可执行文件和目标文件使用ELF(Executable and Linkable File Format可执行与可链接文件格式)的文件格式,不仅存储编绎的汇编指令,还存储了符号表,将全局变量和函数名称与地址关联起来。
1)ELF文件格式将信息分成Section保存,File Header文件头保存文件的属性、CPU硬件平台、操作系统等。
2).text Section代码段保存程序代码和编绎指令。
3).data Section数据段保存程序全局变量和局部静态信息。
4).rel.text.Section重定位表保存当前文件中不确定的函数调用跳转地址(不同文件间函数调用),在链接前不确定跳转地址的信息保存在重定位表里。
5).symtab Section符号表保存当前文件中函数名称和变量的地址。
3,链接器扫描汇编后的目标文件,收集符号表的信息构成全局的符号表,再将重定位表中不确定的跳转地址根据符号表存储的地址进行修正,最后将所有目标文件对应段合并成最终的可执行文件。
4,加载器执行程序不需要考虑地址跳转的问题,只需要解析ELF文件,把对应的指令和数据,加载到内存里CPU执行就可以了。
5,Windows的可执行文件格式为PE(Portable Executable Format),Linux下开源的Wine即通过兼容PE格式的加载器运行Windows程序,Windows也提供了WSL(Windows Subsystem for Linux)解析和加载ELF格式文件。

程序加载
1,加载器加载可执行文件到内存时必须是连续内存空间,且不能指定程序加载的地址,因计算机通常运行多个程序,指定地址可能已经被其他程序占用。
1)代码编绎后的指令地址为虚拟内存地址,程序加载在内存中分配一块连续内存空间,并与程序指令的地址做一个映射,实际内存硬件的空间地址为物理内存地址。
2)维护好虚拟内存到物理内存的映射表,实际程序指令执行时会通过虚拟内存地址找到对应物理内存地址,因是连续内存空间,只需要维护映射关系的起始地址和空间大小即可。
2,内存分段,将连续物理内存和虚拟内存地址映射,造成内存碎片的问题可通过内存交换解决,将某一段内存写入到硬盘,内存碎片合并,再从硬盘读回数据到内存。但硬盘的访问速度较内存慢,内存交换时将一大段连续内存数据写到硬盘再读回到内存,如果交换的内存很大,会导致计算机卡顿。
3,内存分页,在现在的计算机内存管理里,内存分页将物理内存空间切成一段段固定尺寸的大小,通常为4KB,虚拟内存到物理内存的映射是按照一页一页来的,加载程序时不需要一次性把程序都加载到物理内存中,虚拟内存与物理内存页映射,当读取特定页数据没有加载到物理内存时,触发CPU缺页错误,操作系统捕捉到错误后将虚拟内存的数据写入到对应的页,可运行远大于物理内存的程序。内存分页后没有了不能使用的碎片,只有被释放出来的内存页,可直接与其他程序虚拟内存映射。

动态链接
1,合并代码段的方法为静态链接,如果多个程序调用执行,链接好的功能代码会多次加载到内存里。
2,动态链接链接的的不是目标文件代码而是加载到内存中的共享库,可被多个程序指令调用,在Windows下共享库文件为.dll文件,在Linux下共享库文件为.so文件。
1)共享库文件的指令代码必须是地址无关码,无论加载到哪块内存地址都能正常执行。
2)常见地址相关代码如绝对地址代码、利用重定位表的代码等,在程序链接的时候重定位表就确定了函数调用跳转的地址,如果库函数加载到不同的内存地址,跳转就会失败。
3)对于所有动态链接共享库的程序来说,共享库的物理内存地址固定,但在不同的程序中共享库所在的虚拟内存地址是不同的。所以动态代码库内部的变量和函数使用相对地址,指令中内存地址不是绝对空间地址,而是当前指令的偏移量。整个共享库放在一段连续的虚拟内存中,无论加载到哪一段地址,不同指令间的相对地址不变。
4)程序在动态链接共享库的data section里保存了一张全局偏移表(GOT,Global Offset Table),虽然共享库代码部分的物理内存是共享的,但数据部分在每个程序里各加载一份,共享库代码中变量和函数调用指令的偏移量是相对于GOT表的偏移量,通过查询GOT表找到相应的数据或跳转地址,GOT表里的数据是在加载共享库时写入的,不同进程调用相同动态库函数在各自GOT里指向的虚拟内存是不同的。这样虽然不同的程序调用相同的动态库,数据的内存地址是独立的,类似使用函数指针来调用相应的函数,而函数指针指向GOT表。
5,静态链接仅保证代码在开发阶段的复用,而动态链接还可保证代码在运行阶段的复用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值