i386asm学习笔记
tag: asm
0x01 段式寻址
段式寻址涉及到以下数据结构:选择子、描述符表、段描述符、伪描述符。处了段寄存器外,还涉及到GDTR、LDTR。
描述符表是一个线性表,元素为段描述符。段描述符中保存有段的基址、范围和属性。而选择子分为两部分:描述符索引和属性。属性中有一位决定使用GDT还是LDT。
下面简单描述一下段式寻址的过程,在此不涉及各种权限和属性的检查:
1. 通过选择子属性中的TI位决定使用GDT还是LDT。
2. 决定后,从GDTR/LDTR寄存器中获取描述符表的基址和大小。
3. 根据选择子中的索引值,获取对应的段描述符。
4. 根据段描述符,获得段基址、长度和属性。
5. 段基址与偏移量相加,获得线性地址。
GDTR与LDTR的区别是:前者使用伪描述符,没有属性。后者使用段描述符,寄存器中只保存选择子。任务切换时LDT可能会改变。
涉及到的指令:
LGDT SRC
把存储器内的内容装入GDTR寄存器。
0x02 实模式、保护模式切换
实模式和保护模式的区别:CR0寄存器的0位,置1时为保护模式,置0时为实模式。
但是因为实模式和保护模式下寻址方式的区别,进入保护模式前需要初始化一些数据结构,具体包括:段描述符、GDT。之后将GDT的伪描述符装入GDTR。便可进入保护模式。
打开A20地址线是为了能访问4G地址空间。没打开时只有部分地址线有效。
0x03 特权级改变
特权级共有四个:R0~R3。R0特权级最大,R3最小。进行权限控制时涉及三个特权级:CPL,RPL和DPL。
- CPL:当前特权级。CS的RPL字段为CPL。因为SS的RPL字段要求必须与CS一致,所以SS的RPL也可认为是CPL。
- RPL:使用的特权级。当执行
mov ds, ax
这样的指令时,会将ax内的值当做选择子装入DS段寄存器。RPL即该选择子的RPL。 - DPL:访问目标特权级。通过上面的选择子中的索引可以定位一个段描述符,其中有该段的特权级DPL。
特权级检查发生在将段的信息载入段寄存器高速缓冲区之前。
对于段描述符为门的情况,特权级检查发生在通过门进行转移之前。
特权级比较规则
需要比较的特权级共三个CPL、RPL和DPL。
CPL和RPL的关系可以类比Windows的UAC。CPL为当前的特权级,RPL为使用的特权级。当RPL较低时,则只使用部分权限;CPL较低时,表示使用了未被授予的权限,所以实际上只能使用CPL级别的特权级。在于DPL比较时,一般取特权级较低的用于比较。
在此用PL抽象表示CPL和RPL。
通过数值的大小关系,可以很自然地将PL和DPL的关系分为以下三种。
1. PL >= DPL
2. PL == DPL
3. PL <= DPL
第三种PL<=DPL
为数据段规则。大部分段寄存器(ds、es、gs、fs)使用此规则,此时DPL为最低特权级。对于门的访问(中断门、陷阱门、调用门)也使用这种规则。
第二种PL==DPL
为非一致代码段规则,当利用jmp
call
指令进行流程转移时,若目标代码段为非一致代码段,则需要CPL==DPL RPL<=DPL
。
第一种PL>=DPL
为一致代码段规则。此时DPL为最高特权级。
流程转移即装载cs段寄存器。ss段寄存器装载时要求CPL==DPL RPL==DPL
。
使用门进行流程转移时,对CPL和RPL会进行调整。
调用门:使用CALL
访问调用门时,将RPL置0。若CPL>DPL,则将DPL赋给CPL。
中断/陷阱门:进行流程转移时,将RPL置0。若CPL>DPL,则将DPL赋给CPL。
以上“赋值”指在比较特权级时临时改变。成功转移后需要将CS,EIP压栈,此时压栈的是原始值。新装入CS的是目标代码段的选择子。选择子的RPL被忽略,用当前特权级代替。
最后,流程转移除了使用call
jmp
int
外,还可使用ret
iret
。返回指令只能从内层返回至外层。若选择子特权级低于当前特权级,则进行堆栈切换。使用的ESP,SS保存在栈中。
补充:
从外层进入内层时涉及堆栈切换,此时需要提前设置TS。
在此并未涉及关于任务切换的内容。
0x04 中断
中断使用主要涉及:
1. 中断描述符表的设置
2. 8259A中断控制器的设置
通过对8259A中断控制器进行设置,能够更改中断号,屏蔽中断。此处不详述。
中断描述符表类似全局描述符表。但其中只能保存中断门、陷阱门和任务门。
0x05 页式寻址
开启页式寻址后,CR3中的页目录地址及其中的页表地址为物理地址,其他的为线性地址。
是否启用页式寻址通过CR0的最高位设置。
在页式寻址中,将内存以4KB为粒度划分,单位为页。i386可寻址4G,所以最多有4G/4K==1M页。
对于一个线性地址,将其划分为三部分:低12位为页内偏移,高10位和中间10位用于定位页的物理地址。
在CR3中存有页目录的物理地址。页目录大小为1页,页目录项为4B,共有1024个页目录项。页目录项的高20位为对应页表的物理地址,低12位为属性。用线性地址的高10位(10位最大1023)作为索引,找到对应的页目录项,获取页表地址。
页表大小为1页,页表项为4B,同样有1024个页表项。页表项的高20位保存有对应页的物理地址,低12位为属性。利用线性地址的中间10位作为索引,找到对应页的物理地址。
之后将页的物理地址与线性地址的低12位相加,作为物理地址访问内存。
页目录(获取页表物理地址)->页表(获取页物理地址)->与偏移相加->物理地址
0x05 之后还需要了解的。
段访问异常时触发何种异常,如何处理。
特权级检查失败时触发何种异常,如何处理。
页式寻址中涉及到的异常及处理方法。
页目录项页表项的属性。
8259A如何设置。