-
-
[旧帖] [原创]王爽《汇编语言第二版》第10章 课程设计1 0.00雪花
-
2012-6-4 10:26 1899
-
本章还有一个实验10 编写子程序。但是本课程设计包括了写的子程序的所有内容,在代码中也包含所有写的子程序的代码,所以直接看本课程设计的代码就可以了。
在前面的学习中,有一个实验是将poweridea公司的数据按格式写到一个table段中,而本课程设计是要求就数据写到显存以显示在屏幕上,所以我们可以在以前的程序基础上修改,比如可以保留以前的程序,先写到table表,然后从table表读到显存。不过我这里的实现是去掉这些不必要的消耗,也删掉了table表,使程序更高效。另外,在code段里面还有几个子程序,代码的关键部分也都做了注释,实现如下:
运行结果如下:
总结:
1、程序实现中基本都用到了栈,主要用于暂存寄存器数据。不过在子程序dtoc和ddtoc中,我还用栈存放参数%10的值,因为形成字符串时需要逆序写到内存。
2、在dtoc和ddtoc中,为了区分保存的寄存器数据和十进制数的ascii值,特意往栈中压入一个0,作为“桩”。
3、主程序中在循环跳转的loop语句被注释掉:“;loop show ;报错:jump destination too far ,所以自己手动判断cx来跳转。”,原因正如说明,偏移超过了一个字节,所以我自己修改判断cx而利用jmp(jmp near)来实现跳转。因为所有有条件跳转都是短转移,是不是把循环中间的一些内容也写到子程序来减少偏移更好?
4、对显示时的起始行和列偏移的数据,我都统一放在数据段中,可以很方便的修改来查看效果。
在前面的学习中,有一个实验是将poweridea公司的数据按格式写到一个table段中,而本课程设计是要求就数据写到显存以显示在屏幕上,所以我们可以在以前的程序基础上修改,比如可以保留以前的程序,先写到table表,然后从table表读到显存。不过我这里的实现是去掉这些不必要的消耗,也删掉了table表,使程序更高效。另外,在code段里面还有几个子程序,代码的关键部分也都做了注释,实现如下:
DATAS 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 11542,14430,15257,17800 ;起始行:4 db 4 ;各字段的列:year=8;收入=16;雇员=30;平均收入=42 db 8,16,30,42 ;字符缓冲区 db 20 dup (0) DATAS ENDS STACKS SEGMENT ;此处输入堆栈段代码 dw 20 dup (0) STACKS ENDS CODES SEGMENT ASSUME CS:CODES,DS:DATAS,SS:STACKS START: MOV AX,DATAS MOV DS,AX mov ax,STACKS mov ss,ax mov sp,40 mov bp,215 mov si,0 ;for year and summ mov di,0 ;for ne mov cx,21 show: push cx mov cl,0f2h ;颜色 ;year 偏移0 mov ax,[si] mov ds:[bp].0,ax mov ax,[si+2] mov ds:[bp].2,ax mov ds:[bp].4,0 push si push dx mov si,bp mov dh,ds:[210] mov dl,ds:[211] ;列号 call show_str pop dx pop si ;收入summ 偏移5 mov ax,84[si] mov dx,84[si+2] push ax push dx push si mov si,bp call ddtoc mov dh,ds:[210] mov dl,ds:[212] ;列号 call show_str pop si pop dx pop ax add si,4 ;雇员数ne 偏移10 mov bx,168[di] add di,2 push ax push dx push si mov ax,bx mov si,bp call dtoc mov dh,ds:[210] mov dl,ds:[213] ;列号 call show_str pop si pop dx pop ax ;人均收入 偏移13 div bx push ax push dx push si mov si,bp call dtoc mov dh,ds:[210] mov dl,ds:[214] ;列号 call show_str pop si pop dx pop ax mov cl,ds:[210] inc cl mov ds:[210],cl pop cx ;loop show ;报错:jump destination too far ,所以自己手动判断cx来跳转。 dec cx jcxz finish jmp show finish: mov ah,4CH int 21H ;名称:show_str ;功能:在指定位置,用指定的颜色,显示一个用0结束的字符串 ;参数:(dh)=行号,(dl)=列号,(cl)=颜色,ds:si指向字符串的首地址 show_str: push ax push cx push dx push es push si push di ;根据行号设置基址为bp mov ax,160 mul dh mov bp,ax ;根据列号设置基址为di mov dh,0 add dx,dx ;没个字符对应2个字节,所以列号*2 mov di,dx ;显存段地址 mov ax,0b800h mov es,ax ;保存颜色属性到al中 mov al,cl sub cx,cx showstr: mov cl,[si] ;取字符 jcxz ok mov es:[bp+di],cl ;写字符 mov es:[bp+di].1,al ;设置颜色属性 add di,2 inc si loop showstr ok: pop di pop si pop es pop dx pop cx pop ax ret ;divdw ;功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果为dword型 ;参数:ax=dword型数据的低16位,dx=dword型数据的高16位,cx=除数 ;返回:dx=结果的高16位,ax=结果的低16位,cx=余数 divdw: push bx ;以后恢复 push ax mov ax,dx sub dx,dx div cx mov bx,ax ;bx=int(H/N) pop ax div cx mov cx,dx mov dx,bx pop bx ;恢复bx ret ;dtoc ;功能:将word型数据转变为表示十进制的字符串,字符串以0为结束符 ;参数:ax=word型数据;ds:si指向字符串的首地址 ;返回:无 dtoc: push ax push bx push cx push dx push si ;先插入数据结束标记0 sub dx,dx push dx mov bx,10 s1: div bx add dx,30h ;转为ASCII码 push dx mov cx,ax jcxz ok1 sub dx,dx jmp s1 ok1: pop cx jcxz ok2 mov [si],cl inc si jmp ok1 ok2: ;给字符串后面添0 mov [si],cl pop si pop dx pop cx pop bx pop ax ret ;ddtoc ;功能:将dword型数据转变为表示十进制的字符串,字符串以0为结束符 ;参数:ax=dword型数据的低16位;dx=dword型数据的高16位;ds:si指向字符串的首地址 ;返回:无 ddtoc: push ax ;push bx push cx push dx push si ;先插入数据结束标记0 sub cx,cx push cx dd10: mov cx,10 call divdw add cx,30h ;转为ASCII码 push cx mov cx,ax jcxz testhigh jmp dd10 testhigh: mov cx,dx jcxz geascii jmp dd10 geascii: pop cx jcxz win mov [si],cl inc si jmp geascii win: ;给字符串后面添0 mov [si],cl pop si pop dx pop cx ;pop bx pop ax ret CODES ENDS END START
运行结果如下:
总结:
1、程序实现中基本都用到了栈,主要用于暂存寄存器数据。不过在子程序dtoc和ddtoc中,我还用栈存放参数%10的值,因为形成字符串时需要逆序写到内存。
2、在dtoc和ddtoc中,为了区分保存的寄存器数据和十进制数的ascii值,特意往栈中压入一个0,作为“桩”。
3、主程序中在循环跳转的loop语句被注释掉:“;loop show ;报错:jump destination too far ,所以自己手动判断cx来跳转。”,原因正如说明,偏移超过了一个字节,所以我自己修改判断cx而利用jmp(jmp near)来实现跳转。因为所有有条件跳转都是短转移,是不是把循环中间的一些内容也写到子程序来减少偏移更好?
4、对显示时的起始行和列偏移的数据,我都统一放在数据段中,可以很方便的修改来查看效果。
[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界
赞赏
他的文章
看原图