汇编学习笔记(8)子程序
说的多不如做的多,子程序的功能十分重要,这篇笔记用来记录书上练习题的代码,加强对子程序的应用。
在屏幕上指定位置显示字符串
在转移指令那一章有个联系是要求在屏幕中间显示不同颜色的字体,当时我写的代码是这样
1 assume cs:codesg,ds:data 2 3 data segment 4 db 'welcome to masm!' 5 data ends 6 7 codesg segment 8 9 start: mov ax,data 10 mov ds,ax 11 mov bx,0 12 mov ax,0B800h 13 mov es,ax 14 15 ;第10行中间显示绿色字体 16 mov si,10*160+32 17 mov cx,16 18 s: mov al,ds:[bx] 19 mov es:[si+24],al 20 mov byte ptr es:[si+25],02h 21 inc bx 22 inc si 23 inc si 24 loop s 25 26 ;第11行中间显示红底绿色字体 27 mov si,11*160+32 28 mov bx,0 29 mov cx,16 30 s1: mov al,ds:[bx] 31 mov es:[si+24],al 32 mov byte ptr es:[si+25],42h 33 inc bx 34 inc si 35 inc si 36 loop s1 37 38 ;第12行中间显示白底蓝色字体 39 mov si,12*160+32 40 mov bx,0 41 mov cx,16 42 s2: mov al,ds:[bx] 43 mov es:[si+24],al 44 mov byte ptr es:[si+25],71h 45 inc bx 46 inc si 47 inc si 48 loop s2 49 50 mov ax,4c00h 51 int 21h 52 53 codesg ends 54 end start
在学习了子程序之后可以更简洁的代码实现该功能
1 assume cs:codesg,ds:data 2 3 4 data segment 5 db 'welcome to masm!',0 6 data ends 7 8 codesg segment 9 10 start: mov ax,data 11 mov ds,ax 12 mov ax,0B800h 13 mov es,ax 14 ;第10行中间显示绿色字体 15 mov dh,10D 16 mov dl,32D 17 mov bl,02h 18 call print 19 ;第11行中间显示红底绿色字体 20 mov dh,11D 21 mov dl,32D 22 mov bl,42h 23 call print 24 ;第12行中间显示白底蓝色字体 25 mov dh,12D 26 mov dl,32D 27 mov bl,71h 28 call print 29 30 mov ax,4c00h 31 int 21h 32 33 print: push ax 34 push dx 35 push bx 36 mov al,160D 37 mul dh 38 mov cl,dl 39 mov ch,0 40 add ax,cx ;得到开始写入字符串的内存地址 41 mov si,ax 42 mov di,0 43 s: mov cl,ds:[di] 44 mov ch,0 45 jcxz s1 46 mov es:[si],cl 47 mov byte ptr es:[si+1],bl 48 inc di 49 inc si 50 inc si 51 loop s 52 s1: pop bx 53 pop ax 54 pop dx 55 ret 56 57 codesg ends 58 end start
数值转换
1 assume cs:codesg,ds:data 2 3 4 data segment 5 db 10 dup(0) 6 data ends 7 8 codesg segment 9 10 start: mov ax,data 11 mov ds,ax 12 mov si,0 13 mov ax,1266d 14 call doc 15 16 ;第10行中间显示绿色字体 17 mov dh,10D 18 mov dl,32D 19 mov bl,02h 20 call print 21 22 23 mov ax,4c00h 24 int 21h 25 26 doc: push ax 27 push si 28 s0: mov bl,10d 29 div bl 30 add ah,30h 31 mov ds:[si],ah 32 mov ah,0 33 inc si 34 mov cl,al 35 mov ch,0 36 jcxz s2 37 jmp short s0 38 39 s2: mov byte ptr ds:[si],0 40 pop si 41 pop ax 42 ret 43 44 45 print: push ax 46 push dx 47 push bx 48 mov ax,0B800h 49 mov es,ax 50 mov al,160D 51 mul dh 52 mov cl,dl 53 mov ch,0 54 add ax,cx ;得到开始写入字符串的内存地址 55 mov si,ax 56 mov di,0 57 s: mov cl,ds:[di] 58 mov ch,0 59 jcxz s1 60 mov es:[si],cl 61 mov byte ptr es:[si+1],bl 62 inc di 63 inc si 64 inc si 65 loop s 66 s1: pop bx 67 pop ax 68 pop dx 69 ret 70 71 codesg ends 72 end start
课程设计1
1 assume cs:codesg,es:data,ss:stack 2 data segment 3 ;年份 4 db '1975','1976','1977','1978','1979','1980','1981','1982','1983' 5 db '1984','1985','1986','1987','1988','1989','1900','1991','1992' 6 db '1993','1994','1995' 7 ;公司总收入 8 dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514 9 dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000 10 ;雇员 11 dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226 12 dw 11542,14430,45257,17800 13 data ends 14 15 ;栈空间 16 stack segment 17 db 16 dup(0) 18 stack ends 19 20 ;临时内存空间,将字符串后面加0 21 temp segment 22 db 8 dup(0) 23 temp ends 24 25 codesg segment 26 27 start: ;清除屏幕上的原有内容 28 mov ax,0b800h 29 mov es,ax 30 mov si,0 31 mov cx,25*80 32 x: mov byte ptr es:[si],' ' 33 mov byte ptr es:[si+1],0 34 inc si 35 inc si 36 loop x 37 ;分配栈空间 38 mov ax,stack 39 mov ss,ax 40 mov sp,16 41 ;指定数据入口 42 mov ax,data 43 mov es,ax 44 mov ax,temp 45 mov ds,ax 46 mov si,0 47 mov di,0 48 mov bx,0 49 mov dh,4 50 ;循环21次,输出21年数据 51 mov cx,21 52 53 x1: push cx 54 ;显示年份 55 mov ax,es:[di] 56 mov ds:[si],ax 57 mov ax,es:[di+2] 58 mov ds:[si+2],ax 59 mov byte ptr ds:[si+4],0 60 mov dl,10 61 mov cl,02h 62 call print 63 64 ;显示公司收入 65 mov ax,es:[di+84] 66 push dx 67 mov dx,es:[di+84+2] 68 call dword_str 69 pop dx 70 mov dl,20h 71 call print 72 73 ;显示雇员人数 74 mov ax,es:[bx+84+84] 75 call word_str 76 mov dl,40h 77 call print 78 79 ;计算人均收入并显示 80 mov ax,es:[di+84] 81 push dx 82 mov dx,es:[di+84+2] 83 div word ptr es:[bx+84+84] 84 call word_str 85 pop dx 86 mov dl,60h 87 call print 88 add di,4 89 add bx,2 90 inc dh 91 pop cx 92 loop x1 93 94 mov ax,4c00h 95 int 21h 96 97 98 99 100 ;显示ds:[si]开始的字符串 101 print: push es 102 push ax 103 push dx 104 push bx 105 push si 106 push di 107 push cx 108 109 mov ax,0B800h 110 mov es,ax 111 mov al,160D 112 mul dh 113 mov bl,dl 114 mov bh,0 115 add ax,bx ;得到开始写入字符串的内存地址 116 mov di,ax 117 mov si,0 118 mov ah,cl 119 print_s: mov cl,ds:[si] 120 mov ch,0 121 jcxz print_s1 122 mov es:[di],cl 123 mov byte ptr es:[di+1],ah 124 inc si 125 inc di 126 inc di 127 loop print_s 128 print_s1: pop cx 129 pop di 130 pop si 131 pop bx 132 pop dx 133 pop ax 134 pop es 135 ret 136 137 ;不会溢出的除法,参考公式X/N = int(H/N)*65536 + [rem(H/N)*65536 + L]/N 138 ;65536=2^16=10000h 139 ;(dx)被除数高16位 (ax)被除数低16位,(cx)除数 140 ;返回(dx)商高16位 (ax)商低16位 (cx)余数 141 divdw: push bx 142 push ax ;将被除数低16位入栈 143 mov ax,dx 144 mov dx,0 145 div cx ;处理被除数的高16位,商放在ax中,余数放在dx中 146 mov bx,ax;bx存储高16位的商,作为最终结果的高16位int(H/N)*65536 147 pop ax ;低16位出栈,这是(dx)=被除数高16位的余数即上面公式的rem(H/N)*65536 148 div cx ;处理低16位,[rem(H/N)*65536 + L]/N,余数放在dx中 149 mov cx,dx 150 mov dx,bx 151 pop bx 152 ret 153 154 ;dword型数据转化为字符串,ds:[si] 155 ;(dx)高16位,(ax)低16位 156 dword_str: push bx 157 push cx 158 push dx 159 push ax 160 push si 161 mov bx,0 162 163 dword_str_x:mov cx,10;cx存储除数 164 call divdw 165 push cx;将余数入栈,若不用栈操作则显示时是相反的顺序 166 inc bx 167 mov cx,dx 168 jcxz dword_str_a;如果商的高16位等于0则验证低16位是否等于0 169 jmp near ptr dword_str_x 170 dword_str_a:mov cx,ax 171 jcxz dword_str_x1;如果商的低16位也等于0则退出循环 172 jmp near ptr dword_str_x 173 174 175 dword_str_x1:mov cx,bx;循环次数 176 dword_str_x2:pop ds:[si] 177 add byte ptr ds:[si],30h;将数字+30h变成相应的字符串 178 inc si 179 loop dword_str_x2 180 181 pop si 182 pop ax 183 pop dx 184 pop cx 185 pop bx 186 ret 187 188 ;word型数据转化为字符串 189 word_str: push bx 190 push cx 191 push dx 192 push ax 193 push si 194 mov bx,0 195 word_str_s: mov dx,0;防止溢出用16位除法 196 mov cx,10 197 div cx 198 push dx 199 inc bx 200 mov cx,ax 201 jcxz word_str_x 202 jmp short word_str_s 203 204 word_str_x: mov cx,bx 205 word_str_x1:pop ds:[si] 206 add byte ptr ds:[si],30h;将数字+30h变成相应的字符串 207 inc si 208 loop word_str_x1 209 210 pop si 211 pop ax 212 pop dx 213 pop cx 214 pop bx 215 ret 216 217 218 codesg ends 219 220 end start