📄 80386asm程序设计基础(八).htm
字号:
dx,dl<BR> imul
dx,7<BR> add
al,dl<BR> toasc1:ret<BR> toasc endp</P>
<P> ;sub-function newline<BR> newline proc
near<BR> push dx<BR> push
ax<BR> mov dl,0dh<BR> mov
ah,2<BR> int 21<BR> mov
dl,0ah<BR> int 21<BR> pop
ax<BR> pop dx<BR> ret<BR>
newline endp</P>
<P> echo proc near<BR> push
ax<BR> push dx <BR> mov
dl,al<BR> mov ah,2<BR> int
21h<BR> pop dx<BR> pop
ax<BR> echo endp
<BR> 剖析:<BR> 先来看主程序框架,下面就是MAIN
PROC:<BR> |------------------MAIN
PROC-------------------------------|<BR>
|.386;定义处理器的类型为386表示可以使用所有80386指令
|<BR> | code segment para public 'code'
use16
|<BR> | assume
cs:code
|<BR> |
begin:
|<BR> | mov
ax,0f000h
|<BR> | mov
fs,ax;将f000h装入段寄存器fs
|<BR> | mov
eax,fs:[1234H];将1234H内存单元中的双字送给寄存器EAX|<BR> |
call
todec;调用子过程todec
|<BR> | call
newline;调用子过程newline进行回车换行
|<BR> | mov
eax,fs:[1234h];
|<BR> | call
tohex;调用子过程tohex
|<BR> | mov
al,'H'
|<BR> | call
echo;显示字符H
|<BR> | call
newline;
|<BR> | mov
eax,fs:[1234H]
|<BR> | call
tobin;调用子过程tobin
|<BR> | mov
al,'B'
|<BR> | call
echo </P>
<P> <BR> | call
newline
| <BR> | mov
ah,4ch
|<BR> | int
21h
|<BR>
|----------------------------------------------------------|<BR>
主程序中的内容一目了然,很简单。和8086下唯一不同的是就是要用伪指令定义CPU的类型,并且段寄存器的定义多了一个属性类型USE16,再就是32位操作,使用80386的指令,其它的和8086下没有什么区别。<BR>
重点是要分析几个过程,从网上down下来时,过程newline和toasc没有实现代码,因为这很简单,所以上述toasc,newline,echo的过程体是由我写进去的,这两个过程体代码不多而且非常简单,就不作介绍了。重点介绍todec,tobin,tohex。<BR>
a.子过程todec,这个子过程的主要功能是将f000:1234双字单元的内容用十进制显示,下面就来看每一行代码:
<BR>
|-----------------------------------------------------------|<BR>
|todec proc
near
|<BR> |
pushad
|<BR> | mov
ebx,10
|<BR> | xor
cx,cx
|<BR> |
dec1:
|<BR> | xor
edx,edx
|<BR> | div
ebx
|<BR> | push
dx
|<BR> | inc
cx
|<BR> | or
eax,eax
|<BR> | jnz
dec1
|<BR> |
dec2:
|<BR> | pop
ax
|<BR> | call
toasc
|<BR> | call
echo
|<BR> | loop
dec2
|<BR> |
popad
|<BR> |
ret
|<BR> |todec
endp
| <BR>
|-----------------------------------------------------------|<BR>
分析:将一个数用十进制数来表示,要它对它进行除以10的运算,得到商和余数。再将商除以10,如此循环直到商为0为止,在这个过程中得到的一系列的模(余数)就是十进制数系列。在主程序中,已经将f000:1234双字单元的内容放到EAX寄存器中,由于后来要用十六进制数,二进制数显示,所以EAX寄存器的内容不允许改变,因此在子过程的一开始,要将EAX的内容先入栈,所以子过程的一开始就用PUSHAD将8个32位通用寄存器的内容全部入栈。在标号dec1不断地进行除以10运算,将所得到的余数全部入栈,同时用cx进行计数。在标号dec2中,逐个弹出在标号dec1中得到的余数,然后分别将它们显示出来,这样就可以将该存储单元中的内容用十进数表示,下面解释每一条指令的功能:<BR>
a1.pushad;将8个32位通用寄存器全部入栈<BR> a2.xor
cx,cx;cx清0<BR> a3.mov ebx,10;10=>ebx<BR>
a4.xor edx,edx;edx清0<BR> a5.div
ebx;edx存放高32位,不过是0,EAX中存放低32位,即ffff:[1234]双字的内容;除法得到的商放在EAX,余数放在EDX
<BR> a6.push dx;将edx的低16位dx入栈<BR> a7.inc
cx;cx+1=>cx<BR> a8.or
eax,eax;对eax进行或操作,主要是用来判断eax是否为0,即判断商是否为0,从而判断是否应该结束标号为dec1的循环。<BR>
a9.jnz dec1<BR> a10.pop
ax;将放在堆栈中的余数逐个弹出到ax中<BR> a11.call
toasc;显示ax的内容<BR> a12.call echo<BR> a13.loop
dec2;将所有的余数显示完毕<BR>
a14.popad;8个32位通用寄存器全部出栈<BR> a15.ret</P>
<P> b.子过程tohex<BR> PUSH
BP<BR> SP=>BP<BR>
SP<=SP-CNT1<BR>
|------------------------------------------------------------|<BR>
|tohex proc
near
|<BR> |
countb=8
|<BR> | enter
countb,0
|<BR> | movzx
ebp,bp
|<BR> | mov
ecx,countb
|<BR> | mov
edx,eax
|<BR>
|hex1:
|<BR> | mov
al,dl
|<BR> | and
al,0fh
|<BR> | mov
[ebp-countb+ecx-1],al
|<BR> | ror
edx,4
|<BR> | loop
hex1
|<BR> | mov
cx,countb
|<BR> | xor
ebx,ebx
|<BR>
|hex2:
|<BR> | cmp byte ptr
[ebp-countb+ebx],0
|<BR> | jnz
hex3
|<BR> | inc
ebx
|<BR> | loop
hex2
|<BR> | dec
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -