如何构造栈段描述符
本文要讨论的是:对于x86保护模式(32位),已知栈空间的起始地址和结束地址,如何定义栈段描述符?ESP的初始为多少?
为了简化问题,设定约束条件如下:
1. 栈段向下扩展
2. B=1
3. G=1
4. 分页机制关闭
问题分析:数据段描述符的格式如下
如果你不懂各个字段的含义,可以参考我的博文:
数据段描述符和代码段描述符(一)——《x86汇编语言:从实模式到保护模式》读书笔记10
根据约束条件,G=1,B=1,AVL可以设为0,P=1,DPL根据需要来设置,TYPE=0x06(可读可写,向下扩展);所以问题简化为求基地址和段限长,只要算出这两个字段,就可以顺利构造出栈段描述符。
假设我们已经有一片连续的物理内存,要把这段内存作为栈空间。设最低端的物理地址为LA
,最高端的物理地址为HA
,且栈空间大小为SIZE
;如下图所示:
设有效界限(Effect Limit)为EL
;有效偏移(Valid Offset)为VO
;
根据《Intel Architecture Software Developer’s Manual Volume 3:System Programming》第4.3节的说明(请注意黄色的字):
于是,可以知道VO
的范围:
因为基地址加上偏移值才是实际的物理地址,假设描述符中的基地址为BA
,那么可以得出:
(3)式减去(2)式得到:
又根据栈空间的大小为SIZE
,可得出:
把(5)代入(4)式,消去HA-LA
,得到:
也就是说,知道了栈空间的大小SIZE
,就能算出EL
;
把(5)式代入(3)式,消去HA
得到:
因为是32位的处理器,所以
把(8)式代入(7)式得:
也就是说,段描述符中的基地址BA
等于栈空间的最低端地址LA
加上栈空间的大小。
通过上面的推导,我们得出2个重要的公式:
但是,栈段描述符中填写的界限值(这里用limit
表示),并非是(6)式中的EL
;当G=1(粒度为4KB)时,limit
和EL
的关系为:
当栈空间的大小是4KB的整数倍时,我们可以设
把(10)和(11)式代入(6)式,消去EL
和SIZE
,得
于是,我们知道描述符中的界限值该如何计算。
到这里,本文还没有结束,我们还要推导ESP的初始值(用ESP_INIT
表示)。
第一次压栈的时候,比如
push eax
首先,ESP的值减去4,然后把EAX的值写入偏移为[0xFFFF_FFFC,0xFFFF_FFFF]这四个单元。所以:
最后,重复我们的结论:
【end】