作业要求:
请编写一个汇编程序, 实现与以下C程序一样的效果:
hexfile.c
hexfile.c源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
/* 请用主页dosboxtc编译. 编译及运行步骤: 把本程序文件拖给dosboxtc\dosboxtc.exe Alt+C 选 Compile to OBJ Alt+C 选 Link EXE file Alt+R 选 Run */ #include <stdio.h> #include <stdlib.h> #include <bios.h> #include <io.h> #define PageUp 0x4900 #define PageDown 0x5100 #define Home 0x4700 #define End 0x4F00 #define Esc 0x011B void char2hex(char xx, char s[]) /* 把8位数转化成16进制格式 */ { char t[] = "0123456789ABCDEF"; s[0] = t[(xx >> 4) & 0x0F]; /* 高4位 */ s[1] = t[xx & 0x0F]; /* 低4位 */ } void long2hex(long offset, char s[]) /* 把32位数转化成16进制格式 */ { int i; char xx; for(i=0; i<4; i++) { offset = _lrotl(offset, 8); /* 循环左移8位, 把高8位移到低8位 */ xx = offset & 0xFF; /* 高24位置0, 保留低8位 */ char2hex(xx, &s[i*2]); /* 把8位数转化成16进制格式 */ } } void show_this_row(int row, long offset, char buf[], int bytes_on_row) { /* 显示当前一行: 行号 偏移 数组首地址 当前行字节数 */ char far *vp = (char far *)0xB8000000; char s[]= "00000000: xx xx xx xx|xx xx xx xx|xx xx xx xx|xx xx xx xx ................"; /* | | | | | | 00 10 59 上述3个数字是竖线对应位置元素的下标; 数组s的内容就是每行的输出格式: 其中左侧8个0表示当前偏移地址; 其中xx代表16进制格式的一个字节; 其中s[59]开始共16个点代表数组buf各个元素对应的ASCII字符。 */ char pattern[] = "00000000: | | | "; int i; strcpy(s, pattern); long2hex(offset, s); /* 把32位偏移地址转化成16进制格式填入s左侧8个'0'处 */ for(i=0; i<bytes_on_row; i++) /* 把buf中各个字节转化成16进制格式填入s中的xx处 */ { char2hex(buf[i], s+10+i*3); } for(i=0; i<bytes_on_row; i++) /* 把buf中各个字节填入s右侧小数点处 */ { s[59+i] = buf[i]; } vp = vp + row*80*2; /* 计算row行对应的视频地址 */ for(i=0; i<sizeof(s)-1; i++) /* 输出s */ { vp[i*2] = s[i]; if(i<59 && s[i] == '|') /* 把竖线的前景色设为高亮度白色 */ vp[i*2+1] = 0x0F; else /* 其它字符的前景色设为白色 */ vp[i*2+1] = 0x07; } } void clear_this_page(void) /* 清除屏幕0~15行 */ { char far *vp = (char far *)0xB8000000; int i, j; for(i=0; i<16; i++) /* 汇编中可以使用rep stosw填入80*16个0020h */ { for(j=0; j<80; j++) { *(vp+(i*80+j)*2) = ' '; *(vp+(i*80+j)*2+1) = 0; } } } void show_this_page(char buf[], long offset, int bytes_in_buf) { /* 显示当前页: 数组首地址 偏移 当前页字节数 */ int i, rows, bytes_on_row; clear_this_page(); rows = (bytes_in_buf + 15) / 16; /* 计算当前页的行数 */ for(i=0; i< rows; i++) { bytes_on_row = (i == rows-1) ? (bytes_in_buf - i*16) : 16; /* 当前行的字节数 */ show_this_row(i, offset+i*16, &buf[i*16], bytes_on_row); /* 显示这一行 */ } } main() { char filename[100]; char buf[256]; int handle, key, bytes_in_buf; long file_size, offset, n; puts("Please input filename:"); gets(filename); /* 输入文件名; 汇编中可以调用int 21h的0Ah功能 */ handle = _open(filename, 0); /* 打开文件, 返回句柄; 汇编对应调用: mov ah, 3Dh mov al, 0; 对应_open()的第2个参数, 表示只读方式 mov dx, offset filename int 21h mov handle, ax */ if(handle == -1) { puts("Cannot open file!"); exit(0); /* 汇编对应调用: mov ah, 4Ch mov al, 0; 对应exit()中的参数 int 21h */ } file_size = lseek(handle, 0, 2); /* 移动文件指针; 汇编对应调用: mov ah, 42h mov al, 2; 对应lseek()的第3个参数, ; 表示以EOF为参照点进行移动 mov bx, handle mov cx, 0; \ 对应lseek()的第2个参数 mov dx, 0; / int 21h mov word ptr file_size[2], dx mov word ptr file_size[0], ax */ offset = 0; do { n = file_size - offset; if(n >= 256) bytes_in_buf = 256; else bytes_in_buf = n; lseek(handle, offset, 0); /* 移动文件指针; 汇编对应调用: mov ah, 42h mov al, 0; 对应lseek()的第3个参数, ; 表示以偏移0作为参照点进行移动 mov bx, handle mov cx, word ptr offset[2]; \cx:dx合一起构成 mov dx, word ptr offset[0]; /32位值=offset int 21h */ _read(handle, buf, bytes_in_buf); /* 读取文件中的bytes_in_buf个字节到buf中 汇编对应调用: mov ah, 3Fh mov bx, handle mov cx, bytes_in_buf mov dx, data mov ds, dx mov dx, offset buf int 21h */ show_this_page(buf, offset, bytes_in_buf); key = bioskey(0); /* 键盘输入; 汇编对应调用: mov ah, 0 int 16h */ switch(key) { case PageUp: offset = offset - 256; if(offset < 0) offset = 0; break; case PageDown: if(offset + 256 < file_size) offset = offset + 256; break; case Home: offset = 0; break; case End: offset = file_size - file_size % 256; if(offset == file_size) offset = file_size - 256; break; } } while(key != Esc); _close(handle); /* 关闭文件; 汇编对应调用: mov ah, 3Eh mov bx, handle int 21h */ } |
总体还是比较简单的,除了几个中断有点坑……
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 |
comment # Date: 2015/12/18 Nickname: Death Site: www.llonely.com ======================================== 修正了最后一行的显示 # data segment filename db 100,?,101 dup(0) filesize db 4 dup(0) offsets db 4 dup(0) offsets_num db 8 dup(0) buf db 257 dup("$") handle dw 0 lines db 0,0 hex db "0123456789ABCDEF" message_input db "Please input filename:",0Dh,0Ah,"$" message_error db "Cannot open file!$" data ends code segment assume cs:code,ds:data gets: push dx mov dx,ax mov ah,0Ah int 21h pop dx ret puts: push dx mov dx,ax mov ah,09h int 21h pop dx ret show:;ax Buf长度 push bx push cx push dx push di xor bx,bx xor cx,cx xor dx,dx xor di,di;初始化 push ax mov ax,0B800h mov es,ax xor di,di clear: mov cx,80*16 mov ax,0020h cld rep stosw;清屏 calculate: pop ax;the length mov dx,ax add ax,15 mov cl,4 shr ax,cl mov cx,ax;显示行数 push cx sub ax,1 mov cl,4 shl ax,cl sub dx,ax;最后一行字节数 pop cx;行数 mov word ptr lines[0],cx xor di,di show_page: mov ax,cx;剩余行数 cmp cx,16 ja exit_step;检查错误 call show_row dec cx jnz show_page pop di pop dx pop cx pop bx ret exit_step: jmp exit show_row: push cx;剩余行数 xor di,di sub ax,1 push ax mov cl,160 mul cl add di,ax pop ax mov cl,4 shl ax,cl xor si,si add si,offset buf add si,ax push di push si push dx mov cx,word ptr offsets[0] mov dx,word ptr offsets[2] add cx,ax adc dx,0 mov word ptr offsets_num[0],cx mov word ptr offsets_num[2],dx pop dx add di,16 std mov ax,073Ah stosw mov bx,0 fill_address: xor ax,ax mov al,byte ptr offsets_num[bx] and al,0Fh push bx mov bx,offset hex xlat mov ah,07h stosw pop bx xor ax,ax mov al,byte ptr offsets_num[bx] mov cl,4 ror al,cl and al,0Fh push bx mov bx,offset hex xlat mov ah,07h stosw pop bx inc bx cmp bx,4 jb fill_address pop si pop di pop cx cld push cx push di push si cmp cx,word ptr lines[0] je is_the_last_line mov dx,16 is_the_last_line: mov cx,dx add di,59*2 fill_ascii: movsb mov al,07h stosb loop fill_ascii pop si pop di mov cx,dx add di,18 cld push di fill_hex: push cx mov ax,0720h stosw xor ax,ax lodsb push ax mov cl,4 ror al,cl and al,0Fh mov bx,offset hex xlat mov ah,07h stosw pop ax and al,0Fh mov bx,offset hex xlat mov ah,07h stosw pop cx loop fill_hex pop di mov cx,3 add di,2 fill_line: add di,22 mov ax,0F7Ch stosw dec cx jnz fill_line pop cx ret main: mov ax,data mov ds,ax mov es,ax mov ax,offset message_input call puts mov ax,offset filename call gets trim: mov dx,offset filename add dx,2 mov di,dx mov cx,100 mov al,0Dh cld repne scasb mov ax,100 sub ax,cx dec ax add bx,ax add bx,2 mov al,0 mov filename[bx],al fopen: mov dx,offset filename add dx,2 mov ah,3Dh mov al,0 int 21h;open file and get handle jnc open_success;check errors mov ax,offset message_error call puts jmp exit open_success: mov handle,ax mov ah,42h mov al,2 mov bx,handle mov cx,0 mov dx,0 int 21h;lseek(handle,0,2) jnc lseek_success jmp exit lseek_success: mov word ptr filesize[2],dx mov word ptr filesize[0],ax work: mov ax,word ptr filesize[0] mov dx,word ptr filesize[2] sub ax,word ptr offsets[0] sbb dx,word ptr offsets[2] sub ax,256 sbb dx,0 jc rest_is_less xor ax,ax rest_is_less: add ax,256 mov cx,ax push cx lseek_in_loop: mov ah,42h mov al,0 mov bx,handle mov cx,word ptr offsets[2] mov dx,word ptr offsets[0] int 21h read: mov ah,3Fh mov bx,handle pop cx mov dx,data mov ds,dx mov dx,offset buf int 21h mov ax,cx call show press_key: xor ax,ax mov ah,0 int 16h cmp ax,4900h je pageup cmp ax,5100h je pagedown cmp ax,4700h je home_step cmp ax,4F00h je end_step cmp ax,011Bh je fclose_step jmp work pageup: mov ax,word ptr offsets[0] mov dx,word ptr offsets[2] sub ax,256 sbb dx,0 jc home_step mov word ptr offsets[0],ax mov word ptr offsets[2],dx jmp work end_step: jmp endk fclose_step: jmp fclose home_step: jmp home pagedown: mov ax,word ptr offsets[0] mov dx,word ptr offsets[2] add ax,256 adc dx,0 push ax push dx sub ax,word ptr filesize[0] sbb dx,word ptr filesize[2] jnc endk pop dx pop ax mov word ptr offsets[0],ax mov word ptr offsets[2],dx jmp work home: xor ax,ax xor dx,dx mov word ptr offsets[0],ax mov word ptr offsets[2],dx jmp work endk: mov ax,word ptr filesize[0] and ax,0FFh jnz one_line_end mov ax,256 one_line_end: push cx mov cx,ax mov ax,word ptr filesize[0] mov dx,word ptr filesize[2] sub ax,cx sbb dx,0 pop cx mov word ptr offsets[0],ax mov word ptr offsets[2],dx jmp work fclose: mov ah,3Eh mov bx,handle int 21h;fclose(handle) waitfor: ;mov ah,1 ;int 21h;press any key to continue exit: mov ah,4Ch int 21h;exit code ends end main |