assume cs:codesg
datasg segment
db '1975','1976','1977','1978','1979','1980','1981','1982','1983'
db '1984','1985','1986','1987','1988','1989','1990','1991','1992'
db '1993','1994','1995'
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
dw 11524,14430,15257,17800
datasg ends
tadlesg segment
dd 21 dup (0,0,0,0,0,0,0,0)设定21个32字节的内存空间,每8个字节用来
tadlesg ends 存放一组字符串,使每个字符串后面都剩一个
codesg segment 零。因为最大的字符串是7位。
start: mov ax,datasg
mov ds,ax
mov ax,tadlesg
mov es,ax
mov bx,0
mov di,0
mov si,0
mov bp,0
mov cx,21
s: mov ax,[bp]
mov es:[bx],ax
mov ax,[bp+2]
mov es:[bx+2],ax
mov ax,[bp+84] 用BP+84定位DD型数据低8位的取数地址
mov dx,[bp+86] 用BP+86定位DD型数据高8位的取数地址
call dtoc 跳转到子程序,由子程序执行字符串转换和写入
mov ax,[di+168] 用DI+168定位DW型数据的取数地址
mov dx,0 把DW型数据定型成一个DD型数据,
call dtoc
mov ax,[bp+84] 指定除数的位置
mov dx,[bp+86]
div word ptr [di+168] 指定除数的位置
mov dx,0 把求出的商定型为DD型的数据
call dtoc 由子程序处理
add di,2
add bp,4
add si,8 3次循环后SI=24加8=32,定义下一行写入的地址。
add bx,32 定位每次循环后,下一次要写入的地址
loop s
mov ax,tadlesg
mov ds,ax
mov dh,2 定位显示的 行。
mov bh,11001010b 定义成红底黄字
mov si,0
mov cx,21
s2: mov dl,2 定义显示的 列。
call show_str
mov dl,14
add si,8
call show_str
mov dl,24
add si,8
call show_str
mov dl,35
add si,8
call show_str
add si,8
inc dh
loop s2
mov ax,4c00h
int 21h
dtoc: push di 字符转换的子程序。
push bp
push cx
push bx
mov bx,10
mov cx,0
push cx 先入栈一个零,以后用JCXZ将字符串出栈的时候,
s0: mov di,ax 出栈零时,表示字符串已经全部出栈。
mov ax,dx
mov dx,0
div bx
mov bp,ax
mov ax,di
div bx 除法溢出运算。
add dx,30h 将余数加30H,转换成字符串。
push dx 将字符入栈。
mov dx,bp
mov cx,ax 商为零的时候,循环结束,所有字符入栈。
jcxz ok
jmp s0
ok: add si,8 定位字符串要写入的地址。
mov bx,0
s1: mov cx,0
pop cx 将字符串出栈。
jcxz ok0 遇到零时,出栈结束,字符串出栈完毕。
mov es:[bx+si],cx 把逆序求出的字符串,掉转顺序,写入指定位置。
inc bx
jmp s1
ok0: pop bx
pop cx
pop bp
pop di
ret
show_str: push cx 以下是把数据写入显存的的子程序。
push di
push dx
push bx
mov ax,47104
mov es,ax
mov bl,160
mov ax,0
mov al,dh
mul bl
mov bp,ax
mov dh,0
add dl,dl
mov di,dx
mov ah,bh
mov bx,0
mov cx,0
s4: mov cl,[bx+si]
jcxz ok1
mov es:[di+bp],cl
mov es:[di+bp+1],ah
add di,2
inc bx
jmp s4
ok1: pop bx
pop dx
pop di
pop cx
ret
codesg ends
end start
这是我的第一个程序, 当然不能把 Hello World 算在内。这是王爽老师的《王爽汇编》中的一个测试题目。当时我正在大连金石滩的一家网吧做网管。那时我在网上认识了一个网名叫做“猪头三”的汇编高手,他向我推荐了这本书。趁着春节期间学生放假,网吧不忙的时候,我开始了学习汇编。我大概用了差不多一个月的时间,学习了这本书四分之三的内容,然后就开始做这个题目。我用了差不多一周的时间做这个题目,在做这个题目的过程中,我收获了很多感悟。第一点是我理解了汇编中子程序的意义,它把一个特定的功能模块化,主程序可以在需要的时候随时调用,它使程序有了架构和清晰的流程。现在想想,汇编中的子程序就是C语言中的函数。第二点是我在做这个题目的过程中遇到了一个难题,就是除法溢出。我用两个16位的寄存器组成一个32位的被除数,除法运算之后会把商储存在一个特定的16位的寄存器中,这样当除数过小时,储存商的寄存器就溢出了,当时我毫无办法。后来我在网上找到了解决的方法,当时我感觉这个方法极其巧妙。那时的我认为一些打破常理但又能解决问题的巧妙方法完全是出于偶然,所以我更加感到这些方法的美妙。但是我现在有了新的看法,当一个人所寻求的答案在这个人的知识面以外的时候,问题在这个人眼里是无解的,但是,在他还没有透彻理解原理的情况下,让他偶然遇到了解决问题的答案,这个人就会觉得解决问题的方法妙不可言~~ 最终,我完成了这个题目,上面的代码可以在debug中运行,可以看到几行几列闪闪发光的字符,从应用的角度看,这个程序没有一点实用价值,但是,却给了我坚定的信心。
下面是我当时的笔记,重绘了我当时兴奋和喜悦的心情。当然也能看出当时的我有点故做谦虚~~
可能还有许多要优化的地方,可我现在只能做成这样了。不怕大家笑话~我用了3天的时间,可能是我太苯了~呵呵~但没有关系,只要努力我还是可以做到的。想想程序好象比爱情简单多了~毕竟我可以通过努力来实现它,扯远了~呵呵。真的感谢这道题,要是没有它的陪伴,这几天我真的不知道该怎么过,现在看着DEBUG里闪闪发亮的字符,我真的很开心,因为我终于迈出了一步,我又可以向前进了~~~~!!!