从此往后,建立映射,我们执行的任何代码,都是在我们的进程地址空间中进行执行
例如:将动态库映射到共享区,进程在CPU调度时,是在进程的进程地址空间处运行
程序在编译好之后,在加载到内存之前,程序内部是有逻辑地址(虚拟地址)
可执行程序在最开始有表头,可执行程序的入口地址就在表中,这个入口地址是虚拟地址
程序加载到内存中,CPU内读取到的指令,内部可能有数据,可能也有地址(虚拟地址)
静态库不需要加载,在加载程序也就是编译链接时,系统就会将静态库的代码拷贝到可执行程序的代码段里面
程序加载到内存之前:
此时页表没有建立与物理内存的映射,发生缺页中断,缺页中断后 ,程序就被加载到物理内存中,一旦程序加载到物理内存之后,就天然的具备了物理地址
程序加载到内存后:
动态库只将可执行程序用到的库函数的偏移地址拷贝到可执行程序里面,动态库中所有库函数的编址方案都采用start:偏移地址的方式来进行相对编址
CPU执行代码时,发现物理内存中有外部地址,这个外部地址就是编译链接阶段动态库中函数的偏移地址,此时操作系统先将这个外部地址对应的动态库加载到物理内存中,再执行相关代码,然后通过页表将物理内存中动态库的位置映射到虚拟地址空间中的共享区,一旦动态库被映射到共享区,此时这个库的起始地址立马被确定,完成映射之后
利用虚拟地址空间的库函数的偏移量 ,在虚拟地址空间的上下文中进行跳转,跳转到共享区中,利用库的起始地址和具体库函数的偏移量,在共享区中找到库函数的二进制代码并将其执行,执行完毕之后,再跳转到代相对地址码段中,继续向后执行剩余的代码
共享库是一个非常大的空间,具体映射到哪里?
动态库被加载到固定地址空间中的位置是不可能的,但是需要保证库在虚拟内存中,是任意位置加载的
让库的内部函数不要采用绝对编址,编址方案都采用start:直接用偏移量进行对库中函数进行编址,将每个函数的start地址记录,通过start地址加上偏移量,操作系统就能找到具体地址,找到地址,通过地址,进过映射,找到对应的代码
这也就能解释,在动态生成.o文件时,gcc编译加 -fPIC 选项(产生位置无关码),
位置无关码可以理解为,编址时,库可以在虚拟内存的任意位置加载