【PM复习】保护模式下的一点迷你应用(上)
来源:互联网 发布:淘宝店铺手机端网址 编辑:程序博客网 时间:2024/05/29 03:32
前一节中我们进入保护模式后就只在显存中写入一个字符后就退出,还没有体验到保护模式下的种种强大的功能。那么现在我们就来体验一下保护模式里的一个强大的功能,就是强大的寻址。在这节的任务中是在5M地址处读取8个字节以16进制的方式显示出来,接着换行并在5M地址处连续写入8个字节,分别是从字符A开始的ASCII码,最后再从5M地址处读取8个字节以16进制的方式显示出来。
首先把以16进制显示一个数字的功能写成一个函数,命名为Disp_Al,在调用此函数前把要显示的数字先送到al中,代码如下:
- Disp_Al:
- push ebp
- mov ebp,esp
- push esi
- push ecx
- push eax
- mov ecx,2
- shr al,4
- .loop:
- and al,0fh
- cmp al,9
- jb .1
- add al,7
- .1:
- add al,30h
- mov esi,[d_Disp_Pos]
- mov byte [gs:esi],al
- mov byte [gs:esi + 1],0ch
- add dword [d_Disp_Pos],2
- dec ecx
- cmp ecx,0
- je .2
- pop eax
- jmp .loop
- .2:
- pop ecx
- pop esi
- pop ebp
- ret
2到7行和31到33是一些例行的保护。al是8位,以16进制显示的话是2位16进制位,也就是要显示2个字符,所以用ecx来做计数器,赋2。先要把al的高4位显示出来,所以第9行是先把高4位移到低4位,那低4位不是丢失了吗,没事,第7行先把eax压到栈中保护了起来。接下来把al的高4位清零,跟9比较一下,如果大于9就要以字母显示,需要特殊处理一下,在把al中的数转化成ASCII码之后就要写入显存了,我们看到d_Disp_Pos变量,这是用来标示在显存中要显示的位置,为此我们要建立一个数据段,在GDT添加:
- LABEL_DESC_DATA:
- Descriptor 0,0ffffh,DA_DRW
并添加选择子:
- Selector_Data equ LABEL_DESC_DATA - LABEL_DESC_DUMMY
并在16位段中添加初始化数据段的段基址的宏:
- Fill_Descriptor LABEL_DESC_DATA,LABEL_DATA
并添加一个段,在段中添加d_Disp_Pos的初始化,这里我们想在第5行处开始显示:
- [section .data]
- LABEL_DATA:
- _d_Disp_Pos dd 160 * 5
- d_Disp_Pos equ _d_Disp_Pos - $$
接着看Disp_Al函数,19到22行写入显存,并把d_Disp_Pos变量自增2,以指向下一个显存的位置,接下来ecx自减1,判断ecx是否等于0,等于就退出函数,不等于就把eax弹出,跳回标号loop处执行。这个函数就搞定了。
不知你有没有注意到还有一个问题,在函数的调用和函数内部中都要对栈进行操作,而在GDT中却没有栈段,所以必须设立一个32位的栈段,在GDT中添加:
- LABEL_DESC_STACK32:
- Descriptor 0,Stack_Len - 1,DA_DRW | DA_32
添加选择子:
- Selector_Stack32 equ LABEL_DESC_STACK32 - LABEL_DESC_DUMMY
添加栈段:
- [section .stack32]
- [bits 32]
- LABEL_STACK32:
- times 512 db 0
- Stack_Len equ $ - $$
添加初始化栈段段基址的宏:
- Fill_Descriptor LABEL_DESC_STACK32,LABEL_STACK32
另外,在进入保护模式之前,还要把保护模式下的sp值保存起来,在从保护模式回到实模式恢复,所以在数据段添加一个16位的变量:
- _w_SP_Value_In_Real_Mode dw 0
- w_SP_Value_In_Real_Mode equ _w_SP_Value_In_Real_Mode - $$
在进入保护模式前把sp值存到此变量:
- mov [w_SP_Value_In_Real_Mode],sp
返回实模式后恢复:
- mov ss,ax
- mov sp,[w_SP_Value_In_Real_Mode]
接着是换行显示的功能,命名为Disp_Return,代码如下:
- Disp_Return:
- push ebp
- mov ebp,esp
- push eax
- push ebx
- mov eax,[d_Disp_Pos]
- mov bl,160
- div bl
- and ax,0ffh
- inc ax
- mov bl,160
- mul bl
- mov [d_Disp_Pos],eax
- pop ebx
- pop eax
- pop ebp
- ret
此函数很简单,就是先用d_Disp_Pos的值除以160,160就是每行的字节数,div指令执行后,al保留着当前的行数,al自增1后,再乘以160,把结果赋给d_Disp_Pos,这样就指向下一行的起始处。
OK,先暂停一下,添加一点测试代码来测试下是否实现了功能,在32位代码段中把写入一个字符的代码注释掉,添加以下新的测试代码:
- mov ax,Selector_Stack32
- mov ss,ax
- mov esp,Stack_Len
- mov ax,Selector_Data
- mov ds,ax
- mov ax,Selector_Video
- mov gs,ax
- mov al,4
- call Disp_Al
- call Disp_Return
- mov al,14
- call Disp_Al
1到3行是对保护模式下的栈初始化,5到8行初始化DS和GS,接下来就是函数调用了,打印4换行后打印14。下面是所有代码:
- %include "pm.inc"
- org 0100h
- jmp LABEL_BEGIN
- [section .gdt]
- LABEL_DESC_DUMMY:
- Descriptor 0,0,0
- LABEL_DESC_CODE32:
- Descriptor 0,0ffffh,DA_C | DA_32
- LABEL_DESC_CODE16:
- Descriptor 0,0ffffh,DA_C
- LABEL_DESC_VIDEO:
- Descriptor 0b8000h,0ffffh,DA_DRW
- LABEL_DESC_DATA:
- Descriptor 0,0ffffh,DA_DRW
- LABEL_DESC_STACK32:
- Descriptor 0,Stack_Len - 1,DA_DRW | DA_32
- LABEL_DESC_NORMAL:
- Descriptor 0,0ffffh,DA_DRW
- GDT_Len equ $ - LABEL_DESC_DUMMY
- GDT_Ptr:
- dw GDT_Len - 1
- dd 0
- Selector_Code32 equ LABEL_DESC_CODE32 - LABEL_DESC_DUMMY
- Selector_Code16 equ LABEL_DESC_CODE16 - LABEL_DESC_DUMMY
- Selector_Video equ LABEL_DESC_VIDEO - LABEL_DESC_DUMMY
- Selector_Data equ LABEL_DESC_DATA - LABEL_DESC_DUMMY
- Selector_Stack32 equ LABEL_DESC_STACK32 - LABEL_DESC_DUMMY
- Selector_Normal equ LABEL_DESC_NORMAL - LABEL_DESC_DUMMY
- [section .stack32]
- [bits 32]
- LABEL_STACK32:
- times 512 db 0
- Stack_Len equ $ - $$
- [section .data]
- LABEL_DATA:
- _d_Disp_Pos dd 160 * 5
- d_Disp_Pos equ _d_Disp_Pos - $$
- _w_SP_Value_In_Real_Mode dw 0
- w_SP_Value_In_Real_Mode equ _w_SP_Value_In_Real_Mode - $$
- [section .s16]
- [bits 16]
- LABEL_BEGIN:
- mov ax,cs
- mov ds,ax
- mov es,ax
- mov ax,ss
- mov sp,0100h
- mov [LABEL_GO_BACK_TO_REAL + 3],ax
- Fill_Descriptor LABEL_DESC_CODE32,LABEL_CODE32
- Fill_Descriptor LABEL_DESC_CODE16,LABEL_BEGIN
- Fill_Descriptor LABEL_DESC_DATA,LABEL_DATA
- Fill_Descriptor LABEL_DESC_STACK32,LABEL_STACK32
- xor eax,eax
- mov ax,ds
- shl eax,4
- add eax,LABEL_DESC_DUMMY
- mov dword [GDT_Ptr + 2],eax
- lgdt [GDT_Ptr]
- mov [w_SP_Value_In_Real_Mode],sp
- cli
- in al,92h
- or al,00000010b
- out 92h,al
- mov eax,cr0
- or al,1
- mov cr0,eax
- jmp Selector_Code32:0
- _LABEL_PREPARE_GO_BACK_TO_REAL:
- LABEL_PREPARE_GO_BACK_TO_REAL equ _LABEL_PREPARE_GO_BACK_TO_REAL - $$
- mov ax,Selector_Normal
- mov ds,ax
- mov es,ax
- mov ss,ax
- mov sp,[w_SP_Value_In_Real_Mode]
- mov gs,ax
- mov fs,ax
- mov eax,cr0
- and al,11111110b
- mov cr0,eax
- LABEL_GO_BACK_TO_REAL:
- jmp 0:LABEL_ALREADY_REAL
- LABEL_ALREADY_REAL:
- in al,92h
- and al,11111101b
- out 92h,al
- sti
- mov ax,4c00h
- int 21h
- [section .s32]
- [bits 32]
- LABEL_CODE32:
- ;mov ax,Selector_Video
- ;mov gs,ax
- ;mov ah,0ch
- ;mov al,'x'
- ;mov [gs:80 * 10],ax
- mov ax,Selector_Stack32
- mov ss,ax
- mov esp,Stack_Len
- mov ax,Selector_Data
- mov ds,ax
- mov ax,Selector_Video
- mov gs,ax
- mov al,4
- call Disp_Al
- call Disp_Return
- mov al,14
- call Disp_Al
- jmp Selector_Code16:LABEL_PREPARE_GO_BACK_TO_REAL
- Disp_Al:
- push ebp
- mov ebp,esp
- push esi
- push ecx
- push eax
- mov ecx,2
- shr al,4
- .loop:
- and al,0fh
- cmp al,9
- jb .1
- add al,7
- .1:
- add al,30h
- mov esi,[d_Disp_Pos]
- mov byte [gs:esi],al
- mov byte [gs:esi + 1],0ch
- add dword [d_Disp_Pos],2
- dec ecx
- cmp ecx,0
- je .2
- pop eax
- jmp .loop
- .2:
- pop ecx
- pop esi
- pop ebp
- ret
- Disp_Return:
- push ebp
- mov ebp,esp
- push eax
- push ebx
- mov eax,[d_Disp_Pos]
- mov bl,160
- div bl
- and ax,0ffh
- inc ax
- mov bl,160
- mul bl
- mov [d_Disp_Pos],eax
- pop ebx
- pop eax
- pop ebp
- ret
运行结果如下:
- 【PM复习】保护模式下的一点迷你应用(上)
- 【PM复习】保护模式下的一点迷你应用(下)
- 【PM复习】进入保护模式
- 【PM复习】进入保护模式改进
- 【PM复习】进入保护模式再改进
- 【PM复习】从保护模式切换回实模式
- 保护模式下的应用
- 保护模式下的应用
- 保护模式下的应用1
- 保护模式、实地址模式及V8086模式下的指令格式(上)
- 保护模式、实地址模式及V8086模式下的指令格式(上)
- 特权级在保护模式下的应用
- 特权级在保护模式下的应用
- 特权级在保护模式下的应用
- 特权级在保护模式下的应用
- 保护模式下的RPL(一)
- 3.保护模式1----pm.inc分析
- 【PM复习】分页的好处
- 未来N年的学习计划
- 看郭克华老师的视频教学笔记(序言)
- VC好难学啊!!!
- 看郭克华老师的视频教学笔记(一)
- THU - 清华大学 现代软件工程 成绩统计
- 【PM复习】保护模式下的一点迷你应用(上)
- JMenu
- actionPerformed
- ASP.net
- 方法不是外在的形式
- 【PM复习】保护模式下的一点迷你应用(下)
- smarty模板
- 看郭克华老师的视频教学笔记(二)
- 关于三个概念:ActiveX、OLE和COM