实验4 汇编应用编程和c语言程序反汇编分析
实验内容
1.实验内容1
教材「实验9 根据材料编程」(P187-189) 编程:在屏幕中间分别显示绿色、绿底红色、白底蓝色的字符串'welcome to masm!'。
程序正确编写后,预期输出结果如下:

在内存地址空间中,B8000H~BFFFFH供32KB的空间,为80×25彩色字符模式的显示缓冲区。该显示缓冲区分为8页,每页4KB(≈4000B),每页有25行,一行可显示80个字符,一个字符占两个字节,共160个字节,低位字节存储字符的ASCII码,高位字节存储字符的颜色属性。
屏幕中间对应的显存位置的计算:以B800H作为段地址,要在屏幕中间显示三行字符串,这三行字符串应分别显示在第12、13、14行。要显示的字符串占16个字节,每个字符的颜色属性占16个字节,共32个字节,因为一行有160个字节,所以要让字符显示在屏幕中间,应从每行的第33列,即第64个字节开始存放字符及其颜色属性。第12行的开始处的偏移地址为1760,再加上64,等于1824,转换为十六进制就是720H。所以要显示的第一行字符串的起始位置偏移地址应为720H,加上160个字节就是第二行字符串起始位置的偏移地址,加上320个字节就是第3行字符串的起始位置的偏移地址。
字符串颜色属性的设置:根据属性字节的格式即可按位设置属性字节
黑底绿字:属性字节为00000010B,十六进制为02H;
绿底红字:属性字节为00100100B,十六进制为24H;
白底蓝字:属性字节为01110001B,十六进制为71H。
代码:
assume cs:code, ds:data data segment db 'welcome to masm!' data ends code segment start: mov ax,data mov ds,ax mov ax,0b800h mov es,ax mov si,0 mov bx,1824 mov cx,16 s: mov ah,2h; mov al,[si] mov es:[bx],ax mov ah,24h mov es:[bx+160],ax mov ah,71h mov es:[bx+320],ax inc si add bx,2 loop s mov ah,4ch int 21h code ends end start
运行结果:

2.实验任务2
编写子程序printStr,实现以指定颜色在屏幕上输出字符串。调用它,完成字符串输出。
assume cs:code, ds:data data segment str db 'try', 0 data ends code segment start: mov ax, data mov ds, ax mov si, offset str mov al, 2 call printStr mov ah, 4ch int 21h printStr: push bx push cx push si push di mov bx, 0b800H mov es, bx mov di, 0 s: mov cl, [si] mov ch, 0 jcxz over mov ch, al mov es:[di], cx inc si add di, 2 jmp s over: pop di pop si pop cx pop bx ret code ends end start
运行结果:
把line3改为:
1 str db 'Darth Vader wins!', 0
将line12改为:
1 mov al,4
再次汇编连接,运行并观察结果:
line19-22, line36-39,这组对称使用的push、pop,这样用的目的是什么?
line31的功能是什么?
3.实验任务三
1.子任务1
汇编、链接task3.asm,并使用debug进入调试。
assume cs:code, ds:data data segment x dw 1984 str db 16 dup(0) data ends code segment start: mov ax, data mov ds, ax mov ax, x mov di, offset str call num2str mov ah, 4ch int 21h num2str: push ax push bx push cx push dx mov cx, 0 mov bl, 10 s1: div bl inc cx mov dl, ah push dx mov ah, 0 cmp al, 0 jne s1 s2: pop dx or dl, 30h mov [di], dl inc di loop s2 pop dx pop cx pop bx pop ax ret code ends end start
使用u命令进行反汇编,可见应执行至076C:000E。使用g E命令执行至076C:000E,如下图:

使用-g 000e后:

可以发现DI = 0006
使用-d 2 5 查看内存中的元素:

可见,程序成功实现了将数字转换为字符串的功能。
2.子任务2
修改后源程序如下:
assume cs:code, ds:data data segment x dw 1984 str db 16 dup(0) data ends code segment start: mov ax, data mov ds, ax mov ax, x mov di, offset str call num2str mov si, offset str mov al, 2 call printStr mov ah, 4ch int 21h num2str: push ax push bx push cx push dx mov cx, 0 mov bl, 10 s1: div bl inc cx mov dl, ah push dx mov ah, 0 cmp al, 0 jne s1 s2: pop dx or dl, 30h mov [di], dl inc di loop s2 mov byte ptr [di], 0 pop dx pop cx pop bx pop ax ret printStr: push bx push cx push si push di mov bx, 0b800H mov es, bx mov di, 0 s: mov cl, [si] mov ch, 0 jcxz over mov ch, al mov es:[di], cx inc si add di, 2 jmp s over: pop di pop si pop cx pop bx ret code ends end start
其中,line16、line17的功能是为printStr子程序提供必要的输入信息。line46的功能为在转换完毕的字符串后添加0,构造为字符串。printStr子程序本身与任务2中一致。
运行结果如下:

改变数据,再次测试,如下图:

可见,程序实现了所需的功能。
4.实验任务4
程序源代码如下:
assume cs:code, ds:data data segment str db 80 dup(?) data ends code segment start: mov ax, data mov ds, ax mov si, 0 s1: mov ah, 1 int 21h mov [si], al cmp al, '#' je next inc si jmp s1 next: mov cx, si mov si, 0 s2: mov ah, 2 mov dl, [si] int 21h inc si loop s2 mov ah, 4ch int 21h code ends end start
运行结果如图所示:

line12-19实现的功能是?
答:循环读入从键盘输入的字符,遇到‘#’停止,最大长度不得超过80。
line21-27实现的功能是?
答:把si的值赋给cx,表明循环次数,然后把读入的字符再重新输出在屏幕上。
5.实验任务五
5.在visual studio集成环境中,编写一个简单的包含有函数调用的c程序。代码如下:
#include <stdio.h> int sum(int, int); int main() { int a = 2, b = 7, c; c = sum(a, b); return 0; } int sum(int x, int y) { return (x + y); }
反汇编的代码:
#include <stdio.h> int sum(int, int); int main() { 001717B0 push ebp 001717B1 mov ebp,esp 001717B3 sub esp,0E4h 001717B9 push ebx 001717BA push esi 001717BB push edi 001717BC lea edi,[ebp-0E4h] 001717C2 mov ecx,39h 001717C7 mov eax,0CCCCCCCCh 001717CC rep stos dword ptr es:[edi] 001717CE mov ecx,offset _XG17926B_demo@cpp (0FFC003h) 001717D3 call @__CheckForDebuggerJustMyCode@4 (0FF130Ch) int a = 2, b = 7, c; 001717D8 mov dword ptr [a],2 ; 001717DF mov dword ptr [b],7 ; c = sum(a, b); 001717E6 mov eax,dword ptr [b] ; 001717E9 push eax ; 001717EA mov ecx,dword ptr [a] ; 001717ED push ecx ; 001717EE call sum (017116Dh) ; 001717F3 add esp,8 001717F6 mov dword ptr [c],eax ; return 0; 001717F9 xor eax,eax ; } 001717FB pop edi 001717FC pop esi 001717FD pop ebx 001717FE add esp,0E4h 00171804 cmp ebp,esp 00171806 call __RTC_CheckEsp (0171235h) 0017180B mov esp,ebp 0017180D pop ebp 0017180E ret
感悟:
汇编语言中,高级语言的参数传递是通过栈实现的。返回值则通过寄存器eax。
具有多个参数时,入栈顺序为自右向左入栈。函数调用栈使用EBP、ESP寄存器记录,入栈顺序为:实参N~1→主调函数返回地址→主调函数帧基指针EBP→被调函数局部变量1~N。
二.实验总结

浙公网安备 33010602011771号