起首要知道,CUP 中有一个指令寄存器,当 CUP 需要实行指令时,只需要把正文部分的代码直接读到指令寄存器,然后让 CUP 实行指令。
我们也能从上面的引入概念中知道,程序没有被加载的时间,程序内部就已经有地址了,即在磁盘的时间就已经有虚拟地址了,已经被编译好了。也就是说在磁盘的时间,可实行程序已经将代码、数据编址好了,暂时不考虑动态库,因为牵扯动态链接。
假设我们的可实行程序中 main 函数的起始地址为 0x11111111;然后我们的代码中还调用了别的方法,假设有两个方法,地址分别为 0x2222 和 0x3333,如下图:
此时加载到内存之后,物理地址有了,那么页表的右侧就可以填上了。更重要的是,ELF 可实行程序会在特定的位置,记载下来自己程序的入口地址 entry;也就是,编译器在编译的时间,可实行程序在符号表中有专门的字段记载 main 函数的地址,供操作系统读取!
那么在程序加载进内存后,首个虚拟地址就有了,就是 main 函数的地址,那么,程序在加载进来的时间又有了物理地址,所以在最开始时,在页表中就可以构建最简单的 k-v 的映射关系。所以当 CUP 实行这个程序的时间,操作系统只需要将 main 函数的地址加载到指令寄存器中,指令寄存器拿到最开始的程序入口地址,它是虚拟地址 0x11111111,然后找到进程,找到进程地址空间,找到页表,进行虚拟到物理的转化,而在上面已经建立好了虚拟地址到物理地址的 k-v 映射关系,所以此时 CUP 就能读取第一条指令了。