汇编语言关于程序的模块化编写

模块化程序设计

mul乘法指令

  • 要么都是8位,要么都是16位
  • 8位:一个数放在AL中,另一个数放在8位reg寄存器或内存单元中
  • 16位:一个数放在AX中,另一个数放在16位reg寄存器或内存单元中
  • 结果:8位乘法:放在AX中;16位乘法:低位放在AX中,高位放在DX中

8位乘8位:

assume cs:code
code segment
start:  mov al,100
        mov bl,10
        mul bl 
code ends
end start

100和10 都是8位(小于256),所以一个数放在al中,另一个数放在另一个8位reg寄存器中,结果放在ax中。 执行结果:ax=03e8h

16位乘16位:

assume cs:code
code segment
start:  mov ax,100
        mov bx,10000
        mul bl 
code ends
end start

由于bx为16位,所以另一个数一定为16位,16位对16位,ax存放一个树,16位reg寄存器存放另一个数。结果结果:ax=4240(低16位) dx=0001(高16位)

模块化程序设计

三个示例来解决模块化程序设计需要注意的三个问题

参数传递的问题

示例:使用子程序的思想,计算N的3次方

可以使用mul指令,进行三次ax与reg寄存器相乘。将结果存放在dx或ax中

; 计算N的3次方
assume cs:code
data segment
    dw 1,2,3,4,5,6,7,8  ;存放原始数据
    dd 0,0,0,0,0,0,0,0  ;存放相乘结果
data ends
code segment
start:  mov ax,data
        mov ds,ax
        mov di,0        ;原始数据的起始地址
        mov si,16       ;结果存储的起始地址

        mov cx,8
    s:  mov bx,[di] 
        call go
        
        ;返回到这里
        mov [si],ax     ;ax存放低16位
        mov [si+2],dx   ;dx存放高16位
        add di,2        ;数据移动
        add si,4        ;目标位置移动
        loop s  

        ;结束程序
        mov ax,4c00h
        int 21h

    go: mov ax,bx       
        mul bx
        mul bx
        ret             ;返回主程序
code ends
end start

分别计算每一个数字的3次方,将结果存储到dd的双字型内存单元中,从主程序传递ds数据到子程序,计算后返回结果送到目的地,同时注意原始数据和目标数据的偏移地址的移动

批量数据传递

示例:将一个字符串全部转换为大写

批量的将字符串长度和地址传递给子程序,进行转换后再回到主程序

提示:

  • 将小写字母转换为大写字母: 与运算: and al,11011111B
  • 将大写字母转换为小写字母: 或运算: or al,00100000B
;转大写
assume cs:code
data segment 
    db 'woshixiaoxiehhhh'
data ends
code segment
start:  mov ax,data
        mov ds,ax
        mov bx,0

        mov si,0        ;字符串的偏移地址
        mov cx,16       ;字符串长度
        call go

        ;程序结束
        mov ax,4c00h
        int 21h

    go: and byte ptr [si],11011111B     ;指明接受的是byte型字节数据
        inc si          ;偏移地址移动定位每个字符
        loop go         ;循环处理每个字符
        ret             ;返回主程序
code ends
end s

传递给子程序长度,即cx,来在子程序中对每个字母进行与运算,处理完毕后在统一回到主程序

寄存器冲突问题

示例:将多个字符串转换为大写

和上一题基本一致,但是要处理多行,用一个si或者di记录位置,这样能解决吗?

提示:没必要传给子程序cx来记录字符串的长度,直接用jcxz(如果cx为0,则执行跳转)来检测结束

;jcxz检测零实现
assume cs:code
data segment 
    db 'woshixiaoxie',0,0,0,0
    db 'woshixiaoxie',0,0,0,0
    db 'woshixiaoxie',0,0,0,0
    db 'woshixiaoxie',0,0,0,0
    db 'woshixiaoxie',0,0,0,0
data ends
code segment
start:  mov ax,data
        mov ds,ax

        mov bx,0
        mov cx,5
s1:     mov si,bx        ;字符串的偏移地址
        push cx          ;临时保存主程序CX

        call go

        ;CX出栈,保持主程序和子程序的cx不一样
        pop cx           ;临时保存cx
        add bx,16        ;换行
        loop s1          ;循环

        mov ax,4c00h
        int 21h
        
go:     mov cl,[si]
        mov ch,0             ;判断cx是否为零
        jcxz over            ;使用jcxz则无需直到字符串的长度,只要cx为零,则终止
        and byte ptr [si],11011111B
        inc si               ;偏移地址移动定位每个字符
        loop go              ;循环处理每个字符

over:   ret                  ;返回主程序
code ends
end start

注意:此题用jcxz over表示遇到零则结束,在子程序中将按照ds数据段的数据来判断CX,进而判断字符除按是否到达末尾,最后利用jcxz返回主程序。注意!!!!!!
在返回主程序后!!子程序的cx也会返回,进而覆盖了主程序的cx(原本外层的cx用来换行每一个字符串),因此需要利用在进入子程序之前或者进入子程序马上push cx来保存外层的cx,在结束到over或者处理结束进入主程序之后再pop cx得到原来外层的cx,进而进行下一行字符串的处理

posted @ 2022-09-10 23:12  hugeYlh  阅读(22)  评论(0编辑  收藏  举报  来源