流风逸雪 发表于 2020-4-11 16:05:58

实验10 编写子程序

本帖最后由 流风逸雪 于 2020-4-11 16:14 编辑

1.显示字符串
assume cs:code
data segment
db 'Welcome to masm!',0
data ends

code segment

start:       
        mov dh,8
        mov dl,3
        mov cl,2
        mov ax,data
        mov ds,ax
        call show_str
        mov si,0
        mov ax,4c00H
        int 21h

show_str:;借用实验9的代码
        mov al,dh
        mov bl,160
        mul bl
        add dl,dl;显存的奇数字节为字的内容,偶数为字的外观属性,所以要列地址*2作为显存地址
        add al,dl
        mov di,ax
        mov bx,0
        mov ax,0B800H;显存位置
        mov es,ax
       
        mov ah,cl
        mov cx,16
s:        mov al,
        mov es:,al
        inc bx
        inc di
        mov es:,ah
       
        inc di
        loop s
        ret
       
code ends
end start
这里显存的数据结构卡了我一下,导致我一开始老是输出微笑和奇怪的颜色,后来及时想起
果然ctrl+c大法在发功之前还是得仔细研究一下原理,复制不规范,代码两行泪

流风逸雪 发表于 2020-4-11 17:16:35

2.解决除法溢出的问题
assume cs:code


code segment

start:       
        mov ax,4240H;(ax)=L
        mov dx,000FH;(dx)=H
        mov cx,0AH;(cx)=N
        call divdw
       
        mov ax,4c00H
        int 21H
       
divdw:
        push ax;暂时存放一下
        mov ax,dx
        div cl;此时(al)=int(H/N),ah=rem(H/N)
       
        mov bl,al
        mov bh,0;构造int(H/N)*65536
       
        mov di,bx;存放一下
        mov bl,ah
        pop ax;需要的时候再拿出来
        mov bh,0;构造rem(H/N)*65536
        mov dx,bx;构造rem(H/N)*65536+L
        div cx;构造/N=(ax)
        mov cx,dx;使(cx)=余数
        add dx,di;构造int(H/N)*65536+/N
        ret
       
code ends
end start
寄存器不够用是真的麻烦,也许这题还用不着堆栈,可以后更多参数和中间变量了怎么办

流风逸雪 发表于 2020-4-11 18:55:26

3.数值显示
assume cs:code
data segment
db 10 dup (0)
data ends

code segment

start:       
        mov ax,12666
        mov bx,data
        mov ds,bx
        call dtoc
        mov dh,8
        mov dl,3
        mov cl,2

        call show_str
       
        mov ax,4c00H
        int 21h

dtoc:
        mov di,0
        mov bx,10
        mov cx,5
        s0:
                div bx;
                add dl,30H
                mov ,dl
                mov dx,0
                inc di
        loop s0
        ret

show_str:;借用实验9的代码
        mov al,dh
        mov bl,160
        mul bl
        add dl,dl;显存的奇数字节为字的内容,偶数为字的外观属性,所以要列地址*2作为显存地址
        add al,dl
        mov di,ax
        mov bx,5
        mov ax,0B800H;显存位置
        mov es,ax
       
        mov ah,cl
        mov cx,5
s:        dec bx
        mov al,
        mov es:,al
       
        inc di
        mov es:,ah
       
        inc di
        loop s
        ret

       
code ends
end start
这里令我百思不得其解的是为何debug运行得很成功,但直接运行exe会卡住,希望有大大解答

人造人 发表于 2020-4-11 21:46:07

流风逸雪 发表于 2020-4-11 18:55
3.数值显示

这里令我百思不得其解的是为何debug运行得很成功,但直接运行exe会卡住,希望有大大解答

首先,如果有问题,请写在问题贴中
你写在作业贴中很少有人看到你的问题,我看到这个问题纯属巧合

然后是你的问题
div bx
这条指令的含义是
dx:ax / bx
是32位 / 16位

请问执行这条指令之前dx的值是多少?
这就是C语言中的 “使用了未初始化的变量”
出现什么结果都是可能的,程序有时候正常,有时候异常,因为 “使用了未初始化的变量”

流风逸雪 发表于 2020-4-12 14:45:57

人造人 发表于 2020-4-11 21:46
首先,如果有问题,请写在问题贴中
你写在作业贴中很少有人看到你的问题,我看到这个问题纯属巧合



首先谢谢这位大大的回答。
我没写在问题贴的一个原因是我还没看完小甲鱼的关于这一段的课程,先暂时做个记录,看看能不能独立完成。放在作业贴是觉得会来看的应该是同样在做这一道题的童鞋,这样能得到同一层次的思考和反馈,不至于产生依赖。
我是看完小甲鱼视频再回来修改后才看到大大的回答的,我很认同大大的回答。
这里贴一下修改后的代码,修改后能直接运行exe了:assume cs:code
data segment
db 10 dup (0)
data ends

code segment

start:       
        mov ax,12666
        mov bx,data
        mov ds,bx
        mov si,0
        call dtoc
        mov dh,8
        mov dl,3
        mov cl,2

        call show_str
       
        mov ax,4c00H
        int 21h

dtoc:
        push dx
        push cx
        push ax
        push si
        push bx
       
        mov bx,0;bx子程序中存放位数,用栈临时存放修改后的字符
        s0:
                mov cx,10d;d表示十进制
                mov dx,0;这里小甲鱼的视频里确实做了dx的初始化,说明正如@人造人 所说,问题出在这
               
                div cx;
                mov cx,ax;所得商给cx
               
                jcxz s2;当商为0跳到s2
                add dx,30H;余数加上30h得到相应的ASCII码
                push dx
               
               
                inc bx;存储位数
        jmp short s0
s2:
        add dx,30H
        push dx
        inc bx;再进行一次栈操作(补充当“商为零而余数不为零“的情况)
       
        mov cx,bx;总共有bx位进栈了,所以循环次数为bx
        mov si,0
       
s3:       
        pop ax
        mov ,al
        inc si
       
        loop s3
       
okay:
        pop bx
        pop si
        pop ax
        pop cx
        pop dx
        ret

show_str:;借用实验9的代码
        push bx
        push cx
        push si
       
        mov al,160
        dec dh
        mul dh
        add dl,dl;显存的奇数字节为字的内容,偶数为字的外观属性,所以要列地址*2作为显存地址
        add al,dl
        mov bx,ax
        mov ax,0B800H;显存位置
        mov es,ax
        mov di,0
       
        mov al,cl
        mov ch,0
s:        mov cl,
        jcxz ok
        mov es:,cl
       
        mov es:,al
        inc si
        add di,2
        jmp short s
ok:       
        pop si
        pop cx
        pop bx
        ret


       
code ends
end start
最后我想了一下,确实不应该在作业贴里问问题,毕竟鱼c作为一个开放的平台,应该把内容分类好方便更多的鱼油。{:5_105:}

流风逸雪 发表于 2020-4-12 14:57:56

对于第三题,为了让大家看的更清楚
更直观的明白毛病在哪,就把只修改第30行的代码放这以做对比:

这是原来的dtoc子程序:
dtoc:
      mov di,0
      mov bx,10
      mov cx,5
      s0:
                div bx;
                add dl,30H
                mov ,dl
                mov dx,0
                inc di
      loop s0
      ret
这样无法直接运行exe

这是修改后的:
dtoc:
      mov di,0
      mov bx,10
      mov cx,5
      s0:
                mov dx,0;其实就是单纯的把原来放在30行的mov dx,0放在这就行了
                div bx;
                add dl,30H
                mov ,dl
                                ;mov dx,0
                inc di
      loop s0
      ret

这样可以直接运行exe了

人造人 发表于 2020-4-12 15:03:04

流风逸雪 发表于 2020-4-12 14:45
首先谢谢这位大大的回答。
我没写在问题贴的一个原因是我还没看完小甲鱼的关于这一段的课程,先暂时做 ...

嗯,我同意你的观点,遇到问题应该先自己尝试解决,实在解决不了才提问,这样自己能得到更多知识
页: [1]
查看完整版本: 实验10 编写子程序