欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

汇编语言学习(五)

程序员文章站 2022-03-13 10:46:53
...
本部分为王爽《汇编语言》第10章的三个实验。

主要内容为:

1.实现对存储的字符串或二进制数据的屏幕显示
2.理解并改进div存在的溢出问题

1.实验一 显示字符串

子程序描述:

名称:show_str

功能:在指定的位置,用指定的颜色,显示一个用0结束的字符串。

参数:dh行号,取值0~24,dl列号,取值0~79,cl颜色

重要思路:

子程序可以分为定位坐标复制粘贴数据两部分。

1.根据第9章的实验可知,如果要显示字符串,需要从B8000开始。所以首先计算dh、dl对应行、列的实际坐标。尤其注意列是从0开始的

2.用jcxz 标号实现读到data段为0,即跳转。​

3.为简化程序,多用其它寄存器。比如用al存储颜色,所以cx就可以用来从data段中取数了。

assume cs:code
data segment
    db 'Welcome to masm',0
data ends

code segment
start:      mov dh,14
            mov dl,15
            mov cl,2
            mov ax,data
            mov ds,ax
            mov si,0
            call show_str

            mov ax,4C00h
            int 21h

show_str:   mov ax,0
            mov al,dh
            mov bl,0Ah
            mul bl
            add ax,0B800h
            mov bx,0
            mov bl,dl
            sub bl,1
            add bl,bl       ;列从0开始
            mov es,ax
            mov al,cl
            mov ch,0
s:          mov cl,[si]
            jcxz ok         ;实现读到0跳转
            mov es:[bx],cl
            mov es:[bx+1],al
            add bx,2
            add si,1
            jmp short s
ok:         ret
code ends
end start

此处应该有图片显示实验结果:(为使显示不受干扰,把前面多行的第3列空出来了)

汇编语言学习(五)

2.实验二 解决除法溢出的问题

问题:当进行8位除法的时候,al存储结果的商,ah存储结果的余数。当进行16位除法的时候,ax存储结果的商,dx存储结果的余数。如果商比al或者ax大,会发生什么呢?

比如:

mov bh,1
mov ax,1000
div bh

进行的8位的除法,但是结果为1000大于255,al里面放不下,就会发生除法溢出

这个问题通过下面的子程序解决:

子程序描述:

名称:divdw

功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果为dword型。

参数:(ax)=dword型数据低16位,(dx)=dword型数据高16位,(cx)等于除数。

返回:(ax)=结果的低16位,(dx)=结果的高16位,(cx)等于余数。

对于该计算给出公式:

X:被除数

N:除数

H:X高16位

L:X低16位

int():描述性运算符,取商

rem():描述性运算符,取余数

公式:X/N = int(H/N)*65536 + int(rem(H/N)*65536+L)/N)

重要思路:

将一次除法转换为两次除法。

0000H 除以 cx一次,得到商A,余数B

BL除以cx一次,得到商C,余数D

AC就是最终的商,D为最终的余数。

assume cs:code
code segment
start:      mov ax,4240h
            mov dx,000Fh
            mov cx,0Ah
            call divdw
            mov ax,4C00h
            int 21h
divdw:      mov bx,ax      ;bx=L,dx=H,ax=L,cx=N
            mov ax,dx
            mov dx,0       ;bx=L,dx=0,ax=H,cx=N
            div cx         ;bx=L,dx=rem(H/N),ax=int(H/N),cx=N
            mov si,ax
            mov ax,bx       ;dx=rem(H/N),ax=L,cx=N,si=int(H/N)
            div cx          ;dx=rem(X/N),ax=int((rem(H/N)*65536+L)/N),cx=N,si=int(H/N)
            mov cx,dx
            mov dx,si       ;dx=int(H/N),ax=int((rem(H/N)*65536+L)/N),cx=rem(X/N)
            ret 

code ends
end start

3.实验三 数据显示

将数据以十进制的形式显示出来。

子程序描述:

名称:dtoc

功能:将word型数据转变为表示十进制数的字符串。

参数:(ax)等于word型数据

子程序主要可以分为三部分:

1.将二进制转化为十进制,每次除法的余数放入栈中。
2.从栈中取出数据,写入data段中。
3.用实验一编写的子程序显示字符串。

需要注意的几点:

1.栈的使用

由于余数是倒着取出来,但是需要正着放入data段,所以需要用到栈。

为在从栈中取出数据时,便于判断放入的数据是否已经取完,可以提前在栈中放一个0作为结束标记。这样用jcxz判断是否循环结束,也会非常方便。

如下面程序中的push si就是为实现这个小功能。

2.除法

如果只是用一个div dl,存在溢出的可能性。所以这里用到了实验二中防溢出的思路。

但下面的程序用上了dx将10视作16位数据,防溢出会比实验二的方法要简便。

另外,先放余数,再检验商是否为0比较方便。

还需要注意的是,需要在放入栈中时,就将数字加上30h。因为可能余数会为0,如果不加上30h,会被误判为结束标记。

而且,s0循环必须用jmp不能用loop因为loop的原理是,每执行一次cx的值减一,cx减为0向下执行。这种性质会干扰程序的执行。

3.调试时遇到的问题

开始,我的栈设的16个字节大小,ax的值为12666。每当到把’2’放进去,执行jmp时,就会强制退出,并弹出如下界面:

汇编语言学习(五)

我就很迷茫,改了一些地方,调试了很多次也没有改善。后来查到:

汇编语言学习(五)

我一想,我设了8个字型大小的栈。call指令用去1个,接着又放进去3个,第4个时就崩了。很有可能就是这个问题。于是把栈开成16个字型大小,问题解决。

这告诉我们:栈还是开大一点好啊~

下面是程序:

assume cs:code,ds:data,ss:stack
data segment
    db 10 dup (0)
data ends
stack segment
    db 32 dup (0)
stack ends
code segment
start:      mov ax,data
            mov ds,ax
            mov ax,stack
            mov ss,ax
            mov sp,32
            mov ax,17800
            call dtoc   
            mov dh,8
            mov dl,3
            mov cl,2
            call show_str
            mov ax,4C00h
            int 21h

dtoc:       mov bx,10
            mov si,0
            push si
s0:         mov dx,0
            div bx
            mov cx,dx
            add cx,30h
            push cx
            mov cx,ax
            jcxz s1
            jmp short s0
s1:         pop cx
            jcxz ok
            mov [si],cl
            inc si
            jmp short s1

show_str:   mov ax,0
            mov al,dh
            mov bl,0Ah
            mul bl
            add ax,0B800h
            mov bx,0
            mov bl,dl
            sub bl,1
            add bl,bl
            mov es,ax
            mov al,cl
            mov ch,0
            mov si,0
s:          mov cl,[si]
            jcxz ok
            mov es:[bx],cl
            mov es:[bx+1],al
            add bx,2
            add si,1
            jmp short s
ok:         ret
code ends
end start

麻烦一点的程序当然要放一下实验结果啦,挑了两个特殊一点的数:

汇编语言学习(五)

汇编语言学习(五)