实验4 汇编应用编程和c语言程序反汇编分析
------------恢复内容开始------------
实验任务一:
1 assume cs:code, ds:data, ss:stack 2 3 data segment 4 db 'welcome to masm!' 5 db 2h,24h,71h ;三行文字的颜色 6 data ends 7 8 stack segment 9 db 16 dup (0) 10 stack ends 11 12 code segment 13 start: 14 mov ax,data 15 mov ds,ax ;代码段的段始址送到ds 16 17 mov ax,stack 18 mov ss,ax 19 mov sp,16 ;栈段的栈顶指针指向ss:16 20 21 mov ax,0B87Ch ;将字符串显示在屏幕中间的位置 22 mov es,ax 23 24 mov cx,3 ;三行的显示代码是外层循环三次 25 mov bx,0 ;记录当前是第几行,也是外层循环的次数 26 27 s: push cx 28 mov cx,16 ;每行显示16个字符,内存循环16次 29 mov di,0 ;记录内存循环的次数 30 31 s0: mov al,ds:[di] ;低字节显示文字 32 mov ah,ds:[bx+16] ;高字节显示颜色属性 33 mov si,di 34 add si,si 35 mov es:[si],ax 36 inc di 37 loop s0 38 39 pop cx 40 mov ax,es 41 add ax,00ah ;切换到下一行的位置 42 mov es,ax 43 inc bx 44 loop s 45 46 mov ax,4c00h 47 int 21h 48 code ends 49 end start
运行结果为:

在一页显示缓冲区中:
偏移000~09F对应显示器上的第1行(80个字符占160个字节);
偏移0A0~13F对应显示器上的第2行;
偏移140~1DF对应显示器上的第3行;
以此类推,可知偏移780~81F对应显示器上的第12行。
在一行中,一个字符占两个字节的存储空间(一个字),低位字节存储字符的ASCLL码,高位字节存储字符的属性。一行共有80个字符,占160个字节。
即在一行中:
00~01单元对应显示器上的第1列;
02~03单元对应显示器上的第2列;
04~05单元对应显示器上的第3列;
依此类推,可知,40~41单元对应显示器上的第30列。
因此字符串首地址设为:B878*16+40=B87Ch
黑底绿字,属性字节为:00000010
绿底红字,属性字节为:00100100
白底蓝字,属性字节为:01110001
注意:在显示缓冲区中,偶地址存放字符,奇地址存放字符的颜色属性
实验任务二:
1 assume cs:code, ds:data 2 data segment 3 str db 'another try', 0 ;定义以0结尾的字符串try 4 data ends 5 6 code segment 7 start: 8 mov ax, data 9 mov ds, ax 10 11 mov si, offset str ;offset操作符取得了str的偏移地址0 12 mov al, 4 13 call printStr ;跳转指令,跳转到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 ;cx为0时,指令跳转到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
运行结果为:

1 assume cs:code, ds:data 2 data segment 3 x dw 1984 ;定义x为一个字变量赋初值为1984 4 str db 16 dup(0) ;定义str为一个byte数组,存放16个字节的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 ah, 4ch 16 int 21h 17 18 num2str: 19 push ax 20 push bx 21 push cx 22 push dx 23 24 mov cx, 0 25 mov bl, 10 26 s1: 27 div bl 28 inc cx 29 mov dl, ah 30 push dx 31 mov ah, 0 32 cmp al, 0 33 jne s1 34 s2: 35 pop dx 36 or dl, 30h 37 mov [di], dl 38 inc di 39 loop s2 40 41 pop dx 42 pop cx 43 pop bx 44 pop ax 45 46 ret 47 code ends 48 end start
子任务一:
汇编,链接之后对该程序用u命令进行反汇编,用g命令执行到mov ah,4ch,用d命令查看执行之后的结果,发现把转换后的数字字符串'1984'存放在数据段中str标号后面的单元。

子任务二:
1 assume cs:code, ds:data 2 data segment 3 x dw 1984 ;定义x为一个字变量赋初值为1984 4 str db 16 dup(0) ;定义str为一个byte数组,存放16个字节的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 mov si, offset str 15 call printStr 16 17 mov ah, 4ch 18 int 21h 19 20 num2str: 21 push ax 22 push bx 23 push cx 24 push dx 25 26 mov cx, 0 27 mov bl, 10 28 s1: 29 div bl 30 inc cx 31 mov dl, ah 32 push dx 33 mov ah, 0 34 cmp al, 0 35 jne s1 36 s2: 37 pop dx 38 or dl, 30h 39 mov [di], dl 40 inc di 41 loop s2 42 43 pop dx 44 pop cx 45 pop bx 46 pop ax 47 48 ret 49 50 printStr: 51 push bx 52 push cx 53 push si 54 push di 55 56 mov bx, 0b800H 57 mov es, bx 58 mov di, 0 59 s: 60 mov cl, [si] 61 mov ch, 0 62 jcxz over 63 mov ch, al 64 mov es:[di], cx 65 inc si 66 add di, 2 67 jmp s 68 69 over: pop di 70 pop si 71 pop cx 72 pop bx 73 ret 74 code ends 75 end start
运行结果为:

将line3中的整数改为1234,汇编,链接,运行结果为:

将line3中的整数改为2020,汇编,链接,运行结果为:

通过实验发现,修改数字之后,输出的字符颜色及属性都不相同。
实验任务四:
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
运行结果为:



通过断点设置,查看反汇编代码,发现在c=sum(a,b)处的汇编指令先将b移到eax寄存器中,将eax压栈,将a移到ecx寄存器中,将ecx压栈,接着跳转到048116Dh处执行,并将此时的add esp,8的偏移地址压栈,被调函数也可以使用eax、edx、ecx这三个寄存器,所以规定调用者需保存eax、edx和ecx,在从被调函数返回后先恢复这三个寄存器的值再继续;被调用者保存ebx、esi和edi这三个寄存器,对他们进行压栈处理,执行完之后,进行出栈操作,遇到ret指令时,继续回到call指令的下一条指令执行。
------------恢复内容结束------------
浙公网安备 33010602011771号