实验任务1
源程序:
1 assume cs:code, ds:data1 2 data1 segment 3 db 02h,24h,71h 4 data1 ends 5 6 data2 segment 7 db 77h,65h,6ch,63h,6fh,6dh,65h,20h,74h,6fh,20h,6dh,61h,73h,6dh,21h 8 data2 ends 9 10 data3 segment 11 dw 072eh,07ceh,086eh 12 data3 ends 13 14 stack segment 15 dw 0,0 16 stack ends 17 code segment 18 start: 19 mov ax,data2 20 mov ds,ax 21 mov ax,0b800h 22 mov es,ax 23 24 mov cx,16 25 mov bx,0 26 mov si,072eh 27 copy1: 28 29 mov dl,ds:[bx] 30 mov es:[si],dl 31 mov byte ptr es:[si+1],02h 32 inc bx 33 add si,2 34 loop copy1 35 36 mov cx,16 37 mov bx,0 38 mov si,07ceh 39 copy2: 40 41 mov dl,ds:[bx] 42 mov es:[si],dl 43 mov byte ptr es:[si+1],24h 44 inc bx 45 add si,2 46 loop copy2 47 48 49 mov cx,16 50 mov bx,0 51 mov si,086eh 52 copy3: 53 54 mov dl,ds:[bx] 55 mov es:[si],dl 56 mov byte ptr es:[si+1],71h 57 inc bx 58 add si,2 59 loop copy3 60 61 mov ah, 4ch 62 int 21h 63 code ends 64 end start
程序说明:本来想用二重循环直接将三行数据复制到显存区,但是需要用到的段寄存器太多不够用了,保存到栈中又太麻烦,所以直接写了三重循环,将数据的字型信息、颜色信息复制到现存区域。同时显存区域的设置是根据事先选定好的位置设置的。
编译、连接源程序:
程序运行结果:
实验任务2
修改后的源程序:
1 assume cs:code, ds:data 2 data segment 3 str db 'another try', 0 4 data ends 5 6 code segment 7 start: 8 mov ax, data 9 mov ds, ax 10 11 mov si, offset str 12 mov al, 4 13 call printStr 14 15 mov ah, 4ch 16 int 21h 17 18 printStr: 19 push bx 20 push cx 21 push si 22 push di 23 24 mov bx, 0b800H 25 mov es, bx 26 mov di, 0 27 s: mov cl, [si] 28 mov ch, 0 29 jcxz over 30 mov ch, al 31 mov es:[di], cx 32 inc si 33 add di, 2 34 jmp s 35 36 over: pop di 37 pop si 38 pop cx 39 pop bx 40 ret 41 42 code ends 43 end start
程序修改前的运行结果:
程序修改后的运行结果:
问题一:
在调用子程序时将与主程序中的一些寄存器中的数据保存到栈中,在子程序返回前再将这些数据从栈中弹出回到寄存器中,实现数据的保存保护,防止数据丢失。
问题二:
将cx寄存器中保存的数据的颜色信息和字型信息复制到es段寄存器和di偏移地址寄存器所指示的显存地址区域中。
实验任务3
子任务1的编译、连接、运行程序:
子任务1的反汇编和查看数据:
子任务2修改完善后的代码:
1 assume cs:code, ds:data 2 data segment 3 x dw 1999 4 str db 16 dup(0) 5 data ends 6 7 code segment 8 start: 9 mov ax, data 10 mov ds, ax 11 mov ax, x 12 mov di, offset str 13 call num2str 14 15 mov ax, data 16 mov ds, ax 17 mov si, offset str 18 mov al, 2 19 call printStr 20 21 mov ah, 4ch 22 int 21h 23 24 num2str: 25 push ax 26 push bx 27 push cx 28 push dx 29 30 mov cx, 0 31 mov bl, 10 32 s1: 33 div bl 34 inc cx 35 mov dl, ah 36 push dx 37 mov ah, 0 38 cmp al, 0 39 jne s1 40 s2: 41 pop dx 42 or dl, 30h 43 mov [di], dl 44 inc di 45 loop s2 46 47 pop dx 48 pop cx 49 pop bx 50 pop ax 51 52 ret 53 printStr: 54 push bx 55 push cx 56 push si 57 push di 58 59 mov bx, 0b800H 60 mov es, bx 61 mov di, 0 62 s: mov cl, [si] 63 mov ch, 0 64 jcxz over 65 mov ch, al 66 mov es:[di], cx 67 inc si 68 add di, 2 69 jmp s 70 71 over: pop di 72 pop si 73 pop cx 74 pop bx 75 ret 76 code ends 77 end start
子任务2程序的运行测试:
实验任务4
程序源代码:
1 assume cs:code, ds:data 2 data segment 3 str db 80 dup(?) 4 data ends 5 6 code segment 7 start: 8 mov ax, data 9 mov ds, ax 10 mov si, 0 11 12 s1: 13 mov ah, 1 14 int 21h 15 mov [si], al 16 cmp al, '#' 17 je next 18 inc si 19 jmp s1 20 next: 21 mov cx, si 22 mov si, 0 23 s2: mov ah, 2 24 mov dl, [si] 25 int 21h 26 inc si 27 loop s2 28 29 mov ah, 4ch 30 int 21h 31 code ends 32 end start
运行测试截图:
问题一:
从键盘接收字符串,如果接收到字符'#'则跳转到next程序段执行下面的程序,否则继续接收字符并保存到ds:[si]中,si记录了字符串的长度。
问题二:
将si中保存到字符串长度数据传送到寄存器cx中,作为循环的次数。然后依次输出从ds:[0]开始的字符信息,循环次数为字符串的总长度。
实验任务5
反汇编:
任务5总结:
在高级语言中数据a,b是作为实参值传递给sum函数中的x,y形参。在反汇编中看到数据a和b的值先被传送到栈中保存,然后通过call命令调用sum函数,然后先是一般的数据保存,之后通过访问[x]和[y]内存地址中保存的数据来实现数据的相加,并把结果保存在寄存器ax中,之后返回调用该函数的主程序的地址位置。其中数据b是先入栈,数据a后入栈。
实验总结:
(1)本次实验加深了对于显存地址和数据信息中字型信息和颜色信息的理解,更加熟练掌握了数据复制和输出的方法。
(2)当子程序和主程序发生寄存器冲突时通过事先将寄存器数据保存到栈中是一个合理的方法。
(3)通过cmp、jcxz、je、jne等命令可以实现条件更加的复杂的地址转移方式。用来判断字符的类型和数据的结束位置。
(4)编写子程序更好的实现了程序的复用和程序的可读性,提高了程序的开发效率。
(5)通过系统功能调用可以实现从系统预先设置好的功能,如读入键盘输入等信息,在屏幕输出信息。
(6)通过对c语言程序反汇编可以发现一些高级语言和汇编语言在对同一件事情上不同的处理方式,这对于程序的深层次理解更有帮助。