区分一组概念:逻辑地址,虚拟地址,物理地址。
逻辑地址:是我们的代码在编译过程,编译器帮对每一条代码所生成的指令所编写的地址。
物理地址:当程序被放入到内存中时,内存与每一条指令所对应的地址就是物理地址。
虚拟地址:当程序被放入内存以后,之前的编译生成的逻辑地址就是虚拟地址,逻辑地址跟虚拟地址可以等同。
动态库的加载过程
首先一个进程有自己的进程地址空间,进程地址空间中的正文代码段是程序加载的地方。因为我们的程序文件在磁盘当中,当加载程序时,先要把程序加载到内存中,也就是说程序被加载到内存所放的地方就是在进程地址空间的正文代码段。
我们加载一个程序时,会通过文件路径和文件名,找到所需要加载的程序的入口地址,这个地址是逻辑地址。cpu首先会通过入口地址去查找相应的指令,这时的程序还没有加载到内存,所以在完成页表虚拟地址到物理地址的映射时发生缺页中断,然后程序就会正常的放入内存中,接着cpu按顺序执行每一条指令,(cpu每次执行指令前拿到该指令的虚拟地址,然后找到对应的物理地址,再找到相应的指令),当执行到相应的库函数时,假如是printf,这个函数的虚拟地址为0x1122,操作系统会触发缺页中断,将相应的库函数加载到进程地址空间的共享区当中。动态库被加载以后,操作系统会为他分配相应的基地址,程序可以使用这个基地址加上相对偏移量来计算出库函数实际的物理地址。(基地址加上0x1122,就是prinf的实际物理地址)。
动态库的编址方式:相对编址,用相对于基地址的偏移量编址的,所以库可以加载到动态库的任意位置,如果采用绝对编址,当调用printf时,需要用0x1122,那么这个这个动态库的printf函数必须再共享区的0x1122的位置。