《80x86汇编语言程序设计》保护模式第一个例题

来源:互联网 发布:php在线支付 编辑:程序博客网 时间:2024/05/20 15:11

《80x86汇编语言程序设计》保护模式第一个例题的一些个人理解和注视

; 16位偏移的段间直接转移指令的宏定义jump macro selector, offsetvdb 0eah; jmp far 的操作码dw offsetvdw selectorendm; 字符显示宏指令定义echoch macro asciimov ah, 2mov dl, asciiint 21hendm; 存储段描述符结构类型的定义descriptor struclimitldw 0; 段界限低16位baseldw 0; 基地址低16位basemdb 0; 基地址中8位attributesdw 0; 段属性,包含段界限高4位basehdb 0; 基地址高8位descriptor ends; 伪描述符结构类型的定义pdesc struclimitdw 0; 16位段界限base dd 0; 32位基地址pdesc ends; 常量定义atdw = 92h; 存在的可读写数据段属性值atce = 98h; 存在的只执行代码段属性值.386p; 数据段dseg segment use16gdtlabel byte; 全局描述符表GDTdummydescriptor <>; 空描述符codedescriptor <0ffffh, , , atce, >code_sel = code - gdt; 代码段描述的选择子datasdescriptor <0ffffh, 0h, 11h, atdw, 0>datas_sel = datas - gdt; 源数据段描述符的选择子dataddescriptor <0ffffh, , , atdw, >datad_sel = datad - gdt; 目标数据段描述符的选择子gdtlen = $ - gdtvgdtrpdesc <gdtlen - 1, >; 伪描述符bufferlen= 256; 缓冲区字节长度bufferdb bufferlen dup (0); 缓冲区dseg ends; 代码段cseg segment use16assume cs:cseg, ds:dsegstart:mov ax, dsegmov ds, ax; 准备要加载到gdtr的伪描述符mov bx, 16mul bxadd ax, offset gdtadc dx, 0mov word ptr vgdtr.base, axmov word ptr vgdtr.base + 2, dx; 设置代码段描述符mov ax, csmul bxmov code.basel, axmov code.basem, dlmov code.baseh, dh; 设置目标数据段描述符mov ax, dsmul bxadd ax, offset bufferadc dx, 0mov datad.basel, axmov datad.basem, dlmov datad.baseh, dh; 加载gdtrlgdt fword ptr vgdtrcli call enablea20; 切换到保护方式xchg bx, bxmov eax, cr0or eax, 1mov cr0, eax; 清指令欲取队列,并真正进入保护方式jump <code_sel>, <offset virtual>virtual:mov ax, datas_selmov ds, axmov ax, datad_selmov es, axcldxor si, sixor di, dimov cx, bufferlen / 4repz movsd; 切换回实方式mov eax, cr0and eax, 0fffffffehmov cr0, eax; 清指令预取队列,进入实方式jump <seg real>, <offset real>real:call disablea20stimov ax, dsegmov ds, axmov si, offset buffercld mov bp, bufferlen / 16nextline:mov cx, 16nextch:lodsbpush axshr al, 4call toasciixchg bx, bxechoch alxchg bx, bxpop axcall toasciiechoch alechoch ' 'loop nextchechoch 0dhechoch 0ahdec bpjnz nextlinemov ax, 4c00hint 21htoascii  procand al, 0fhadd al, 30hcmp al, '9'jbe quitadd al, 7quit:rettoascii endpenablea20 procpush axin al, 92hor al, 2out 92h, alpop axretenablea20 endpdisablea20 procpush axin al, 92hand al, 0fdhout 92h, alpop axretdisablea20 endpcseg endsend start

我自己以前的疑问与我自己的答案:

Q:为什么要设置GDTR?

A:应为需要他来找到GDT

Q:

mul bx
什么意思?

A:转换为物理地址,就是段值*16

Q:

jump <code_sel>, <offset virtual>
什么意思?

A:这条指令是在转换到保护模式之前预取到指令队列的,如果不预取,转换到保护模式后系统会把cs中的值以为是选择子,但其实他是段值,就无法执行下一条指令,也就是jmp,所以要预取这条宏,然后执行时把cs设置为选择子,刷新预取指令队列,引用:

“由此可见,执行这条jmp指令时CPU已经处于“保护方式”了(因为cr0中的PE已经被置成“保护方式”)。如果此条jmp指令如果不是在“实方式”下被预取到指令队列中,就无法执行到它,因为“cr0中的PE被置成保护方式”之后,cs中的值仍为实方式的段值,此时将当前ip加1,然后用cs:ip去取下面的这条jmp指令显然会失败,因为此时处于“保护方式”下的cpu会把cs中的内容理解为“选择子”,所以自然无法取得“紧接着的”jmp指令。”

Q:

shr al, 4
啥意思?

A:是要显示其高4位,然后下面pop后显示低四位

Q:

mov ax, datas_sel

什么意思?

A:datas_sel为选择子,值为8,换为二进制是1000,低三位分别是0位、1位为RPL,2位为TI,3~15位是描述符表索引,也即第一个描述符

>>>>>>>>>>>>>>>琐碎记忆>>>>>>>>>>>>>>>>>

保护方式下通过选择子的3~15位来定位在描述符表中的描述符,然后获得基地址、界限、属性