注:本文档为《从0学x86操作系统》课程配套的学习文档,提供相应的辅助学习资料和答疑勘误。 有关该课程的信息,请点击这里访问:https://study.163.com/provider/1017884735/index.htm 在阅读本文档时,如有疑问和建议,欢迎在下方留言或者直接联系我。

本课时主要介绍如何利用C结构体的内存布局特性来解析异常时压入的栈内容,从而能够在异常处理函数中方便地解析压入的栈中内容。
主要难点有两点:结构体中各字段与内存元素之间的映射、发生异常时压入栈中的数据元素有哪些。

异常发生时压入栈中的内容

根据Intel编程文档卷3中的内容可知,发生异常时,硬件会自动压入一部分数据到栈中,如下图所示。根据是否有特权级变化,有两种不同类型的压栈方法。本课时仅讨论无特权级变化的压栈方法,即图中上半部分。
image.png
此外,在异常处理函数中,还使用了pusha指令压入了各种寄存器的值,压入的顺序为: AX, CX, DX, BX, original SP, BP, SI, and DI,以及通过push es等指令压入了其它段寄存器的值。因此,当异常发生后到进入异常处理函数的这个过程中,压入的栈如下:
image.png

参数的映射

结合以前的课时,我们知道从do_handler_unknown()看来,压入栈中的这些寄存器,相当于是传递给它的参数。难点在于压入栈中的寄存器数量太多,如果简单地将这些寄存器值全部映射到do_handler_unknown()的参数中,则该函数的参数数量将很多。
image.png
于是,课程中使用了一个结构体exception_frame_t映射栈中这些寄存器的值,然后在栈中压入所有寄存器值存储的起始位置,相当于是给do_handler_unknown()传递了一个指向所有压入的数据的exception_frame_t类型的指针,从而能方便地直接从结构体中读取所有这些寄存器的值。
image.png

参考资料

  • 课程附带的intel编程文档卷3:Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3 (3A, 3B, 3C & 3D): System Programming Guide