上一篇文章学习了保户模式下如何进行内存保护 与 别名段的意义与作用:点击链接查看上一篇文章:点击链接

本文接着学习,在保护模式下,内核是如何加载用户程序并运行的。其实这与在实模式下很像,只不过现在保护迷失多了个描述符而已。所以尽量先参考实模式下的加载过程,再来阅读本篇文章或许会更好。点击链接查看实模式的加载过程:实模式下内核加载用户程序到内存

1、用户程序的加载和重定位

1.1 用户程序的结构

所有操作系统的可执行文件都包括文件头(这个文件头其实是由连接器构造的)。然后就是各种段,包括数据段,代码段等。

在用户程序的头部是一些重定位需要的信息。比如段的信息,以及符号的信息。段的信息在之前的实模式中讲的很清楚了。

符号的信息的话,内核要求,用户程序必须在头部偏移量位0x28 的地方构造一个表格,并在表格中列出所有要用到的符号名。内核会分析这个表格,并将这里面的符号全部换成相应的内存地址,即将函数的地址换过来。

这里面当然包括程序中所有的函数,包括系统调用的函数。

程序自己本身定义的函数地址好找,在加载的时候,加载器重定位代码段之后,即得到了所有的函数地址,将符号表里出现的函数全部换成该相应函数代码的地址即可。

但是系统调用函数的话,地址在哪里呢? 其实跟用户程序一样,内核也会在某一个地方定义一个符号表,这个符号表里存放的都是内核的系统函数,专门供用户程序调用的。当用户程序调用系统函数,内核就会对比内核的符号表与用户程序的符号表,将相应的内核函数的地址传送给用户程序的相应符号处。

这其实就是符号重定位的一个过程。当然在这之前已经做好了符号解析。符号解析的意思就是代码中相应的符号的定义与引用处进行一个关联。

1.2 计算用户程序的扇区数

了解了程序的结构,当然就是要从硬盘上读取用户程序。那么首先要计算用户程序的大小,因为读取硬盘是按照扇区为单位的,所以要计算用户程序的扇区数。

这从用户程序头即可得出结果。

1.3 简单的动态内存分配

计算好用户程序的扇区数后,就是将用户程序读取到内存中了。那么就需要进行内存的分配工作。这个具体的流程也参考实模式下的过程。

1.4 段的重定位和描述符的创建

其实到这里才与实模式有一点区别,上述几个步骤与实模式完全一样。

并且段的重定位过程也与实模式相同,只不过加了个描述符。

将用户程序读到内存中后,现在就需要根据用户程序的头部来创建段描述符。

安装完用户程序头部的段描述符后,将该段的选择子写回到用户程序头部。供用户程序在接管处理器控制权后使用。

头部的段安装创建好后。接下来是安装和创建数据段与代码段等的段描述符,然后也将相应的段选择子写回到用户程序头部供后面用户程序使用

唯一不同的是栈段。栈段不需要用户程序自己提供,而是有内核动态分配。内核分配站空间时每次都是以4KB位单位的。同理,栈段描述符创建好之后也需要将段选择子写回到用户程序头部供后面用户程序使用。

1.5 重定位用户程序内的符号地址

符号的重定位,主要包括自己程序定义的函数与变量符号的重定位,以及系统调用函数的重定位。这在1.1节的程序结构中已经说过,比较容易理解。

2 用户程序的执行

在经过上面的:

  • 读取用户程序并分配内存
  • 重定位段并创建段描述符
  • 重定位符号

后,下面就是运行程序了。一般是使用一个段间远转移指令jmp后,跳转到用程序的入口函数地址。

3、总结

本篇文章写的不是很详细,只是说出了大概过程。详细过程参考书籍与实模式的那篇文章。

笔记记得不是很全,如果有不懂的可以加我联系方式一起交流。

学习探讨加个人:
qq:1126137994
微信:liu1126137994