实验4 汇编应用编程和c语言程序反汇编分析
实验4 汇编应用编程和c语言程序反汇编分析
一、实验目的
- 理解80×25彩色字符模式显示原理
- 理解转移指令jmp, loop, jcxz的跳转原理,掌握使用其实现分支和循环的用法
- 理解转移指令call, ret, retf的跳转原理,掌握组合使用call和ret/retf编写汇编子程序的方法,掌握参数传递方式
- 理解标志寄存器的作用
- 理解条件转移指令je, jz, ja, jb, jg, jl等的跳转原理,掌握组合使用汇编指令cmp和条件转移指令实现分支和循环的用法
- 了解在visual studio/Xcode等环境或利用gcc命令行参数反汇编c语言程序的方法,理解编译器生成的反汇编代码
- 综合应用寻址方式和汇编指令完成应用编程
二、实验准备
实验前,请复习/学习教材以下内容:
第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。可以看出编译器仅将需要改变的寄存器入栈。
五、实验总结
- 80×25的彩色字符模式,即一屏25行80列。每一行显示一个字符需要两个字节,一共160个字节。
默认,在显存第0列显示时,对应的显存空间为B8000H ~ B8F9FH。
而每个字符占两个字节:低位存放字符的ASCII码值,高位存放字符的显示属性,且顺序为:闪烁 背景色(RGB) 高亮 前景色(RGB)。根据属性字节的格式即可按位设置属性字节 - 在设置设置数据区时,可以在内容前加上标号比如
x dw 1984,假设起始地址为ds:0,则程序中x相当于[0000],offset x相当于0000

浙公网安备 33010602011771号