一、实验内容
1、实验任务1
编程:在屏幕中间分别显示绿色、绿底红色、白底蓝色的字符串'welcome to masm!'。
1 assume cs:code,ds:data 2 data segment 3 db 'Welcome to masm!' 4 data ends 5 code segment 6 start: 7 mov ax,data 8 mov ds,ax 9 10 mov ax,0b800h 11 mov es,ax 12 13 mov si,0 14 mov di,0 15 mov ah,2 16 mov cx,16 17 s: 18 mov al,ds:[di] 19 mov es:[1824+si],ax 20 add si,2 21 inc di 22 loop s 23 24 mov si,0 25 mov di,0 26 mov ah,24h 27 mov cx,16 28 29 s1: 30 mov al,ds:[di] 31 mov es:[1824+si+160],ax 32 add si,2 33 inc di 34 loop s1 35 36 mov si,0 37 mov di,0 38 mov ah,71h 39 mov cx,16 40 s2: 41 mov al,ds:[di] 42 mov es:[1824+si+320],ax 43 add si,2 44 inc di 45 loop s2 46 47 mov ah,4ch 48 int 21h 49 50 code ends 51 end start
- 程序正确编写后,预期输出结果如下:

2、实验任务2
- 编写子程序printStr,实现以指定颜色在屏幕上输出字符串。调用它,完成字符串输出。
- 子程序printSar
- 功能:以指定颜色在屏幕上(从屏幕左上角开始)输出字符串
- 要求:字符串以0结尾
- 入口参数
字符串的起始地址—> ds: si (其中,字符串所在段的段地址—> ds, 字符串起始地址的偏移地址—> si
字符串颜色—> al
-
- 出口参数:无
- 使用任意文本编辑器,录入汇编源程序task42.asm。
1 assume cs:code, ds:data 2 data segment 3 str db '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, 2 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
- 汇编、运行程序,观察运行结果。
- 使用u命令对task42.exe 反汇编
- -u 0 32
- 实验运行结果
- 对源程序做如下修改:
- 把line3改为:
1 str db 'another try', 0
- 把line12改为:
1 mov al, 4
- 修改代码后汇编、运行程序
- 实验结果如下

基于运行结果,理解源代码,以及,组合使用转移指令call和ret实现子程序的原理与方法。具体地,在
line18-40中:
- line19-22, line36-39,这组对称使用的push、pop,这样用的目的是什么?
- 用于保护主程序中寄存器存放的数据不被修改。
- line19-22在子程序执行之前将寄存器的数据保存至栈中,line36-39子程序执行结束前将寄存器的数据从栈中恢复。
- line30的功能是什么?
- 将数据送入显存单元,显示出对应颜色的符号,cx中ch对应颜色,cl值对应符号
3、实验任务3
- 使用任意文本编辑器,录入汇编源程序task43.asm。
- 子程序num2str:
- 功能:把0~2559之间的任意整数转换成数字字符串,例如,把1984转换成'1984'
- 入口参数
要转换的整数 —> ax
数字字符串的起始地址 —> ds:di (其中:数字字符串所在段的段地址—> ds,字符串
起始地址的偏移地址—>di)
出口参数:无
1 assume cs:code, ds:data 2 data segment 3 x dw 1984 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 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
阅读源代码,理解子程序num2str的汇编实现。
一、子任务1
- 对task43.asm进行汇编、链接,得到可执行程序后,在debug中使用u命令反汇编


- 使用g命令执行到line15(程序退出之前)

- 使用d命令查看数据段内容,观察是否把转换后的数字字符串'1984'存放在数据段中str标号后面的单元。

实验结果可以看出成功把转换后的数字字符串'1984'存放在数据段中str标号后面的单元。
二、子任务2
- 对task43.asm源代码进行修改、完善,把task42.asm中用于输出以0结尾的字符串的子程序加进来,
实现对转换后的字符串进行输出。
- 修改后的代码如下:
1 assume cs:code, ds:data 2 data segment 3 x dw 1984 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 si, offset str 16 mov al, 4 17 call printStr 18 19 mov ah, 4ch 20 int 21h 21 22 num2str: 23 push ax 24 push bx 25 push cx 26 push dx 27 28 mov cx, 0 29 mov bl, 10 30 s1: 31 div bl 32 inc cx 33 mov dl, ah 34 push dx 35 mov ah, 0 36 cmp al, 0 37 jne s1 38 s2: 39 pop dx 40 or dl, 30h 41 mov [di], dl 42 inc di 43 loop s2 44 45 pop dx 46 pop cx 47 pop bx 48 pop ax 49 50 ret 51 52 printStr: 53 push bx 54 push cx 55 push si 56 push di 57 58 mov bx, 0b800H 59 mov es, bx 60 mov di, 0 61 s: mov cl, [si] 62 mov ch, 0 63 jcxz over 64 mov ch, al 65 mov es:[di], cx 66 inc si 67 add di, 2 68 jmp s 69 70 over: pop di 71 pop si 72 pop cx 73 pop bx 74 ret 75 76 code ends 77 end start
- 实验结果如下:

- 把task3.asm源代码中,line3中整数改成0~2559之间的任意数值,运行测试,观察结果。
- 比如改为75后结果如下

4、实验任务4
- 使用任意文本编辑器,录入汇编源程序task44.asm。
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
- 汇编、链接、运行程序,输入一个字符串并以#结束观察运行结果如下。



- 结合运行结果,理解程序功能,了解软中断指令。具体地:
- mov ax,1 int 21h :从键盘输入单个字符,从键盘输入的字符保存在al中
- mov ax,2 mov dl,[si] int 21h :在屏幕上输出单个字符
- 该程序的功能就是从键盘中输入一个字符串并以#结束,结果回显
- line12-19实现的功能是?
- 从键盘中读入字符,直到遇到‘#’结束
- line21-27实现的功能是?
- 回显出键盘输入的字符(‘#’除外)
5、实验任务5
- 在visual studio集成环境中,编写一个简单的包含有函数调用的c程序。代码如下:
1 #include <stdio.h> 2 int sum(int, int); 3 int main() { 4 int a = 2, b = 7, c; 5 c = sum(a, b); 6 return 0; 7 } 8 int sum(int x, int y) { 9 return (x + y); 10 }
- 在line5, line9分别设置断点,在调试模式下,查看反汇编代码。
1 #include <stdio.h> 2 int sum(int, int); 3 int main() { 4 011D1760 push ebp 5 011D1761 mov ebp,esp 6 011D1763 sub esp,0E4h 7 011D1769 push ebx 8 011D176A push esi 9 011D176B push edi 10 011D176C lea edi,[ebp-0E4h] 11 011D1772 mov ecx,39h 12 011D1777 mov eax,0CCCCCCCCh 13 011D177C rep stos dword ptr es:[edi] 14 011D177E mov ecx,offset _F6BB13E8_源@cpp (011DC003h) 15 011D1783 call @__CheckForDebuggerJustMyCode@4 (011D1208h) 16 int a = 2, b = 7, c; 17 011D1788 mov dword ptr [a],2 18 011D178F mov dword ptr [b],7 19 c = sum(a, b); 20 011D1796 mov eax,dword ptr [b] 21 011D1799 push eax 22 011D179A mov ecx,dword ptr [a] 23 011D179D push ecx 24 011D179E call sum (011D107Dh) 25 011D17A3 add esp,8 26 011D17A6 mov dword ptr [c],eax 27 return 0; 28 011D17A9 xor eax,eax 29 } 30 011D17AB pop edi 31 011D17AC pop esi 32 011D17AD pop ebx 33 011D17AE add esp,0E4h 34 011D17B4 cmp ebp,esp 35 011D17B6 call __RTC_CheckEsp (011D1212h) 36 011D17BB mov esp,ebp 37 011D17BD pop ebp 38 011D17BE ret
1 int sum(int x, int y) { 2 011D16F0 push ebp 3 011D16F1 mov ebp,esp 4 011D16F3 sub esp,0C0h 5 011D16F9 push ebx 6 011D16FA push esi 7 011D16FB push edi 8 011D16FC lea edi,[ebp-0C0h] 9 011D1702 mov ecx,30h 10 011D1707 mov eax,0CCCCCCCCh 11 011D170C rep stos dword ptr es:[edi] 12 011D170E mov ecx,offset _F6BB13E8_源@cpp (011DC003h) 13 011D1713 call @__CheckForDebuggerJustMyCode@4 (011D1208h) 14 return (x + y); 15 011D1718 mov eax,dword ptr [x] 16 011D171B add eax,dword ptr [y] 17 } 18 011D171E pop edi 19 011D171F pop esi 20 011D1720 pop ebx 21 011D1721 add esp,0C0h 22 011D1727 cmp ebp,esp 23 011D1729 call __RTC_CheckEsp (011D1212h) 24 011D172E mov esp,ebp 25 011D1730 pop ebp 26 011D1731 ret


- 分析反汇编代码,从汇编的角度,观察高级语言中参数传递和返回值是通过什么实现的,
- 以及,参数入栈顺序,返回值的带回方式,等等。
从汇编角度,高级语言中的参数传递用寄存器保存参数的值,同时从右到左依次压栈,依次压栈之后,
调用函数sum,跳到被调用函数sum地址去执行, 将寄存器eax中保存的函数sum的返回值赋值给c。


posted on
浙公网安备 33010602011771号