实验4 汇编应用编程和c语言程序反汇编分析

实验4 汇编应用编程和c语言程序反汇编分析

一、实验目的

  1. 理解80×25彩色字符模式显示原理
  2. 理解转移指令jmp, loop, jcxz的跳转原理,掌握使用其实现分支和循环的用法
  3. 理解转移指令call, ret, retf的跳转原理,掌握组合使用call和ret/retf编写汇编子程序的方法,掌握参数传递方式
  4. 理解标志寄存器的作用
  5. 理解条件转移指令je, jz, ja, jb, jg, jl等的跳转原理,掌握组合使用汇编指令cmp和条件转移指令实现分支和循环的用法
  6. 了解在visual studio/Xcode等环境或利用gcc命令行参数反汇编c语言程序的方法,理解编译器生成的反汇编代码
  7. 综合应用寻址方式和汇编指令完成应用编程

二、实验准备

实验前,请复习/学习教材以下内容:
第9章 转移指令的原理
第10章 call和ret指令
第11章 标志寄存器

三、实验结论

1. 实验任务1

编程:在屏幕中间分别显示绿色、绿底红色、白底蓝色的字符串'welcome to masm!'。

在内存地址空间中,B8000H~BFFFFH供32KB的空间,为80×25彩色字符模式的显示缓冲区。
25行,居中的三行为12、13、14行,对应起始地址1760、1920、2080;需要显示的字符共16个,一行80列,即从32列开始,对应到地址应该+64,即1824、1984、2144。
而每个字符占两个字节:低位存放字符的ASCII码值,高位存放字符的显示属性,且顺序为:闪烁 背景色(RGB) 高亮 前景色(RGB)
根据属性字节的格式即可按位设置属性字节
黑底绿字:属性字节为00000010B,十六进制为02H;
绿底红字:属性字节为00100100B,十六进制为24H;
白底蓝字:属性字节为01110001B,十六进制为71H。

这里我直接循环3次,分别输出三行,虽然多重循环能够减少代码量,但命令条数基本一致,3次循环逻辑更加简单。
源程序:

assume cs:code, ds:data
data segment
	     db 'welcome to masm!'
	     db 00000010B,00100100B,01110001B
data ends

code segment
	start:
	      mov  ax, data
	      mov  ds, ax       	;将ds设为data段

	      mov  ax, 0b800H
	      mov  es, ax       	;将es段设为0b800h,为显存段

	      mov  cx, 16       	;共16个字符循环16次
	      mov  si, 0
	      mov  di, 1824     	;1760+64 第11列
	s1:   mov  al, [si]     	;ds:0(N)存入al,即data段的字节依次存入al
	      mov  es:[di], al  	;设置显示的字符
	      mov  al, ds:[16]
	      mov  es:[di+1], al	;设置显示字符的颜色
	      inc  si           	;si+1,指向下一个字符
	      add  di, 2        	;di+2,指向下一个显存字
	      loop s1

	      mov  cx, 16
	      mov  si, 0
	      mov  di, 1984     	;1920+64 第13列
	s2:   mov  al, [si]
	      mov  es:[di], al
	      mov  al, ds:[17]
	      mov  es:[di+1], al
	      inc  si
	      add  di, 2
	      loop s2

	      mov  cx, 16
	      mov  si, 0
	      mov  di, 2144     	;2080+64 第14列
	s3:   mov  al, [si]
	      mov  es:[di], al
	      mov  al, ds:[18]
	      mov  es:[di+1], al
	      inc  si
	      add  di, 2
	      loop s3

	      mov  ah, 4ch
	      int  21h
code ends
end start

运行结果截图

2. 实验任务2

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改为str db 'another try', 0实际上是更改输出串
将line12改为mov al, 4,实际上是更改字符串颜色
运行结果截图:

line19-22, line36-39,这组对称使用的push、pop,这样用的目的是什么?

将进入子程序前的寄存器通过栈保存起来,保留现场,在子程序结束后还原现场,让程序能够继续执行

line30的功能是什么?

设置字符的颜色属性

3. 实验任务3

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

由于程序过长超过了显示范围,因此只反汇编默认长度

可以看到1984写入成功

附上子任务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, 4         	;指定颜色(绿色)
	         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
        
	         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


可以看到输出成功

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	;将字符存入ds:si
	      cmp  al, '#' 	;如果输入的字符是#
	      je   next    	;则跳转至next执行
	      inc  si      	;si+1,下一个字符位置
	      jmp  s1      	;跳转至s1,即循环输入
	next: 
	      mov  cx, si  	;si在输入完成后正好为输入字符个数,这里作为输出的循环次数
	      mov  si, 0
	s2:   mov  ah, 2   	;输出字符
	      mov  dl, [si]	;ds:si输出
	      int  21h
	      inc  si      	;si+1,下一个字符位置
	      loop s2      	;loop循环

	      mov  ah, 4ch
	      int  21h
code ends
end start

运行测试截图

回答任务中提出的两个问题

line12-19实现的功能是?

从键盘接受字符依次存入ds:si,遇到#终止进入输入部分

line21-27实现的功能是?

将ds:si中字符依次输出
5. 实验任务5

高级语言中参数传递,从汇编的角度是如何传递的

汇编语言中不存在命名空间,也不存在函数的说法,任何一段代码均可访问全部寄存器,因此将需要将参数放入寄存器即可实现参数传递。当然,根据高级语言的逻辑,在改变对应寄存器前需要将原函数内对应寄存器入栈,保存现场

返回值是如何返回的

与传递参数相同,将返回值放入寄存器即可

多个参数的入栈顺序是什么样的

在vs2019的编译器中,参数的入栈顺序为从右往左,但是只要出栈顺序与入栈顺序一致即可,不同的编译器可能顺序不同

函数调用栈

在该程序中,在进入函数前,由于传递参数将eax、ecx入栈;在进入函数后,将控制地址的寄存器入栈,包括ebp、ebx、esi、edi。可以看出编译器仅将需要改变的寄存器入栈。

五、实验总结

  1. 80×25的彩色字符模式,即一屏25行80列。每一行显示一个字符需要两个字节,一共160个字节。
    默认,在显存第0列显示时,对应的显存空间为B8000H ~ B8F9FH。
    而每个字符占两个字节:低位存放字符的ASCII码值,高位存放字符的显示属性,且顺序为:闪烁 背景色(RGB) 高亮 前景色(RGB)。根据属性字节的格式即可按位设置属性字节
  2. 在设置设置数据区时,可以在内容前加上标号比如x dw 1984,假设起始地址为ds:0,则程序中x相当于[0000],offset x相当于0000
posted @ 2020-12-12 20:58  GoatKing  阅读(116)  评论(2)    收藏  举报