📄 汇编005.txt
字号:
80386实模式下编程
80386在实模式下是一个更快的8086,它不但可以进行32位操作,而且还可以进32位寻址,并且还可以使用80386的扩展指令。不过,由于是在实模下,寻址的最大空间为1M。在一个段内,段的最大长度不超过64K,否则就会发生异常。
在8086下定义一个段的完整格式是:
段名 [定位类型] [组合类型] [‘类别’]
80386下定义一个段的完整格式是:
段名 [定位类型] [组合类型] [‘类别’] [属性类型]
说明:属性类型有两种:USE32和USE16,USE32表示32位段,USE16表示16位段。如果你在程序中用到伪指令.386,那么默认的属性类型就是USE32(32位段),如果没有用伪指令指定CPU的类型,那么默认的属性类型就是USE16,在实方式下只能使用16位段,即用USE16。
eg:
CSEG PARA PUBLIC USE32;定义一个32位的段
AA DW ?
BB DD ?
CC DB ?
DD DW ?
EE DW 0,0,0.....
CSEG ENDS
由于在80386中用到了66H操作前缀和67H地址前缀,因此尽管在实式模式下,只要设定的CPU类型是80386,仍然可以进行32位操作,可以进行32位寻址,66H,67H这两个前缀无需程序员在程序中书写,汇编程序会自动加上的。只要在程序中对32位操作数进行访问,或进行32位寻址,那么就会加上操作数前缀66H和地址前缀67H。相反,如果在32位段中对16位或8位的访问,汇编程序中也会加上这两个前缀。
下面将给出一个例子程序,演示一下在80386的实模式下编程的方法与技巧(这是从网上down的一个程序,不是我写的,但我会作详细的解剖,并与8086下的程序设计作出比较):
用十进制,十六进制,二进制三种形式显示双字存储单元F000:1234中的内容
|------------------MAIN PROC------------|
| .386 |
| code segment para public 'code' use16 |
| assume cs:code |
| begin: |
| mov ax,0f000h |
| mov fs,ax |
| mov eax,fs:[1234H] |
| call todec |
| call newline |
| call tohex |
| mov al,'H' |
| call echo |
| call newline |
| call tobin |
| mov al,'B' |
| call echo |
| call newline |
| mov ah,4ch |
| int 21h |
|---------------------------------------|
;sub-function todec
todec proc near
pushad
mov ebx,10
xor cx,cx
dec1:
xor edx,edx
div ebx
push dx
inc cx
or eax,eax
jnz dec1
dec2:
pop ax
call toasc
call echo
loop dec2
popad
ret
todec endp
;sub-function tobin
tobin proc near
push eax
push ecx
push edx
bsr edx,eax
jnz bin1
xor dx,dx
bin1:
mov cl,31
sub cl,dl
shl eax,cl
mov cx,dx
inc cx
mov edx,eax
bin2:
rol edx,1
mov al,'0'
adc al,0
call echo
loop bin2
pop edx
pop ecx
pop eax
ret
tobin endp
;sub-function tohex
tohex proc near
countb=8
enter countb,0
movzx ebp,bp
mov ecx,countb
mov edx,eax
hex1:
mov al,dl
and al,0fh
mov [ebp-countb+ecx-1],al
ror edx,4
loop hex1
mov cx,countb
xor ebx,ebx
hex2:
cmp byte ptr [ebp-countb+ebx],0
jnz hex3
inc ebx
loop hex2
dec ebx
mov cx,1
hex3:
mov al,[ebp-countb+ebx]
inc ebx
call toasc
call echo
loop hex3
leave
ret
tohex endp
;sub-function toasc
toasc proc near
and al,0fh
cmp al,'0'
cmp al,'9'
seta dl
movzx dx,dl
imul dx,7
add al,dl
toasc1:ret
toasc endp
;sub-function newline
newline proc near
push dx
push ax
mov dl,0dh
mov ah,2
int 21
mov dl,0ah
int 21
pop ax
pop dx
ret
newline endp
echo proc near
push ax
push dx
mov dl,al
mov ah,2
int 21h
pop dx
pop ax
echo endp
剖析:
先来看主程序框架,下面就是MAIN PROC:
|------------------MAIN PROC-------------------------------|
|.386;定义处理器的类型为386表示可以使用所有80386指令 |
| code segment para public 'code' use16 |
| assume cs:code |
| begin: |
| mov ax,0f000h |
| mov fs,ax;将f000h装入段寄存器fs |
| mov eax,fs:[1234H];将1234H内存单元中的双字送给寄存器EAX|
| call todec;调用子过程todec |
| call newline;调用子过程newline进行回车换行 |
| mov eax,fs:[1234h]; |
| call tohex;调用子过程tohex |
| mov al,'H' |
| call echo;显示字符H |
| call newline; |
| mov eax,fs:[1234H] |
| call tobin;调用子过程tobin |
| mov al,'B' |
| call echo
| call newline |
| mov ah,4ch |
| int 21h |
|----------------------------------------------------------|
主程序中的内容一目了然,很简单。和8086下唯一不同的是就是要用伪指令定义CPU的类型,并且段寄存器的定义多了一个属性类型USE16,再就是32位操作,使用80386的指令,其它的和8086下没有什么区别。
重点是要分析几个过程,从网上down下来时,过程newline和toasc没有实现代码,因为这很简单,所以上述toasc,newline,echo的过程体是由我写进去的,这两个过程体代码不多而且非常简单,就不作介绍了。重点介绍todec,tobin,tohex。
a.子过程todec,这个子过程的主要功能是将f000:1234双字单元的内容用十进制显示,下面就来看每一行代码:
|-----------------------------------------------------------|
|todec proc near |
| pushad |
| mov ebx,10 |
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -