《80x86汇编语言程序设计》保护模式第一个例题的一些个人理解和注视
- ; 16位偏移的段间直接转移指令的宏定义
- jump macro selector, offsetv
- db 0eah ; jmp far 的操作码
- dw offsetv
- dw selector
- endm
- ; 字符显示宏指令定义
- echoch macro ascii
- mov ah, 2
- mov dl, ascii
- int 21h
- endm
- ; 存储段描述符结构类型的定义
- descriptor struc
- limitl dw 0 ; 段界限低16位
- basel dw 0 ; 基地址低16位
- basem db 0 ; 基地址中8位
- attributes dw 0 ; 段属性,包含段界限高4位
- baseh db 0 ; 基地址高8位
- descriptor ends
- ; 伪描述符结构类型的定义
- pdesc struc
- limit dw 0 ; 16位段界限
- base dd 0 ; 32位基地址
- pdesc ends
- ; 常量定义
- atdw = 92h ; 存在的可读写数据段属性值
- atce = 98h ; 存在的只执行代码段属性值
- .386p
- ; 数据段
- dseg segment use16
- gdt label byte ; 全局描述符表GDT
- dummy descriptor <> ; 空描述符
- code descriptor <0ffffh, , , atce, >
- code_sel = code - gdt ; 代码段描述的选择子
- datas descriptor <0ffffh, 0h, 11h, atdw, 0>
- datas_sel = datas - gdt ; 源数据段描述符的选择子
- datad descriptor <0ffffh, , , atdw, >
- datad_sel = datad - gdt ; 目标数据段描述符的选择子
- gdtlen = $ - gdt
- vgdtr pdesc <gdtlen - 1, > ; 伪描述符
- bufferlen = 256 ; 缓冲区字节长度
- buffer db bufferlen dup (0) ; 缓冲区
- dseg ends
- ; 代码段
- cseg segment use16
- assume cs:cseg, ds:dseg
- start:
- mov ax, dseg
- mov ds, ax
- ; 准备要加载到gdtr的伪描述符
- mov bx, 16
- mul bx
- add ax, offset gdt
- adc dx, 0
- mov word ptr vgdtr.base, ax
- mov word ptr vgdtr.base + 2, dx
- ; 设置代码段描述符
- mov ax, cs
- mul bx
- mov code.basel, ax
- mov code.basem, dl
- mov code.baseh, dh
- ; 设置目标数据段描述符
- mov ax, ds
- mul bx
- add ax, offset buffer
- adc dx, 0
- mov datad.basel, ax
- mov datad.basem, dl
- mov datad.baseh, dh
- ; 加载gdtr
- lgdt fword ptr vgdtr
- cli
- call enablea20
- ; 切换到保护方式
- xchg bx, bx
- mov eax, cr0
- or eax, 1
- mov cr0, eax
- ; 清指令欲取队列,并真正进入保护方式
- jump <code_sel>, <offset virtual>
- virtual:
- mov ax, datas_sel
- mov ds, ax
- mov ax, datad_sel
- mov es, ax
- cld
- xor si, si
- xor di, di
- mov cx, bufferlen / 4
- repz movsd
- ; 切换回实方式
- mov eax, cr0
- and eax, 0fffffffeh
- mov cr0, eax
- ; 清指令预取队列,进入实方式
- jump <seg real>, <offset real>
- real:
- call disablea20
- sti
- mov ax, dseg
- mov ds, ax
- mov si, offset buffer
- cld
- mov bp, bufferlen / 16
- nextline:
- mov cx, 16
- nextch:
- lodsb
- push ax
- shr al, 4
- call toascii
- xchg bx, bx
- echoch al
- xchg bx, bx
- pop ax
- call toascii
- echoch al
- echoch ' '
- loop nextch
- echoch 0dh
- echoch 0ah
- dec bp
- jnz nextline
- mov ax, 4c00h
- int 21h
- toascii proc
- and al, 0fh
- add al, 30h
- cmp al, '9'
- jbe quit
- add al, 7
- quit:
- ret
- toascii endp
- enablea20 proc
- push ax
- in al, 92h
- or al, 2
- out 92h, al
- pop ax
- ret
- enablea20 endp
- disablea20 proc
- push ax
- in al, 92h
- and al, 0fdh
- out 92h, al
- pop ax
- ret
- disablea20 endp
- cseg ends
- end 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位来定位在描述符表中的描述符,然后获得基地址、界限、属性
http://blog.csdn.net/programmingring/article/details/7385140