1.代码间的跳转(段间跳转,非调用门之类的)
段间跳转有2 种情况,即要跳转的段是一致代码段还是非一致代码段。
同时修改CS与EIP的指令
JMP FAR/CALL FAR /RETF /INT /ITETED
注意:
只改变EIP的指令
JMP /CALL /JCC /RET
2. 代码间的跳转执行流程
JMP 0x20 : 0x00412345 CPU 如何执行这行代码呢 ?
(1).段选择子拆分
0x20 对应的二进制形式 0000 0000 0010 0000
RPL=00
TI =0
Index =4
(2).查表得到段描述符
TI = 0 所以查GDT表
Index = 4 找到对应的段描述符
四种情况可以跳转:代码段、调用门、TSS任务段、任务门
根据段选择子拆得的下标,找到GDT表第5项。如果P=1,S=1,TYPE高1位=1,则表明这是一个代码段,就可以进行下一步。
(3).权限检查
TYPE域高2位是C属性,C=0表示非一致代码段,C=1表示一致代码段。
如果是非一致代码段,要求:CPL == DPL 并且RPL<=DPL
如果是一致代码段,要求:CPL>=DPL
(4).加载段描述符
通过上面的权限检查后,CPU会将段描述符加载到CS段寄存器中。
(5).代码执行
CPU将CS.base + Offset 的值写入EIP,然后执行CS:EIP处的代码,段间跳转结束。
3. 总结:
对于一致代码段:也就是共享的段
a.特权级高的程序不允许访问特权级低的数据:核心态不允许访问用户态的数据
b.特权级低的程序可以访问到特权级高的数据,但特权级不会改变:用户态还是用户态
对于普通代码段:也就是非一致代码段
a.只允许同级访问
b.绝对禁止不同级别的访问:核心态不是用户态,用户态也不是核心态.
直接对代码段进行JMP 或者 CALL的操作,无论目标是一致代码段还是非一致代码段,CPL都不会发生改变.如果要提升CPL的权限,只能通过调用门.
代码跨段本质就是修改CS段寄存器
段寄存器读写:
除CS外,其他的段寄存器都可以通过MOV,LES,LSS,LDS,LFS,LGS指令进行修改
CS为什么不可以直接修改呢?
CS的改变意味着EIP的改变,改变CS的同时必须修改EIP,所以我们无法使用上面的指令来进行修改.