实验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!'。

 

assume cs:code, ds:data
data segment
    db 'welcome to masm!'
    db 2h,24h,71h
data ends

code segment
start:
    mov ax, data
    mov ds, ax
    mov ax,0b872h
    mov es,ax

    mov di,0
    mov ah,ds:[di+10h]
    mov al,ds:[di+11h]
    mov bh,ds:[di+12h]
    mov si,0
    mov cx,16
s:  mov bl,ds:[si]
    mov es:[di],bl
    mov es:[di+1],ah 
    mov es:[di+0a0h],bl 
    mov es:[di+0a1h],al 
    mov es:[di+140h],bl 
    mov es:[di+141h],bh 
    inc si
    add di,2
    loop s

    mov ax,4c00h
    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改为:
str db 'another try', 0

这里只是将字符串改变,但是使用jcxz是当判断后面出现0才结束写入的循环,所以改变了显示的个数。

 

 

把line12改为:
mov al, 4

4为00000100b,所以是黑底红色,结果如下

 

 

问:line19-22, line36-39,这组对称使用的push、pop,这样用的目的是什么?
 
答:用于保护和恢复寄存器的值,更好的利用寄存器。
 
问:line30的功能是什么?
 
答:将高位是颜色信息,低位是字符ASCLL信息的cx,存入显存。

3. 实验任务3

使用任意文本编辑器,录入汇编源程序task3.asm。
 
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           //将1984存入ax当被除数  07C0H=1984
        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       //余数赋值0    因为这之前已经除过一次10了,而al能表示的最大数为255,所以这个代码能表示的范围是0-2599
        cmp al, 0       //如果商为0,表示你将数字全部单个取出入栈了,那么jne判断不成功就会执行下面的代码,而不会继续s1的循环了
        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
 
对task3.asm进行汇编、链接,得到可执行程序,结果为:
 
子任务1
  对tTask_3.asm进行汇编、链接,得到可执行程序后,在debug中使用u命令反汇编,使用g命令执行
  到line15(程序退出之前),使用d命令查看数据段内容,观察是否把转换后的数字字符串'1984'存放
  在数据段中str标号后面的单元。
 
在debug中使用u命令反汇编,使用g命令执行到line15(程序退出之前),使用d命令查看数据段内容:
 

结果确实是1984的ASCLL值

子任务2
  对Task_3.asm源代码进行修改、完善,把Task_3.asm中用于输出以0结尾的字符串的子程序加进来,实现对转换后的字符串进行输出。

加入代码:

 
assume cs:code, ds:data
data segment
        x dw 2020
        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
        call  shuchu

        mov ah, 4ch
        int 21h

num2str:
        push ax
        push bx
        push cx
        push dx
        
        mov bx,0b800h
        mov es,bx
        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
shuchu :
        push ax
        push bx
        push cx
        push dx
        
        mov bx, 0b800H
        mov es, bx
        mov di, 0
        mov al,2        //指定输出的是绿色黑底
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

使用任意文本编辑器,录入汇编源程序task4.asm。
 
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         //读取一个字符,放到ah中
        mov [si], al
        cmp al, '#'      //如果输入的是#,那么停止输入,转跳到下面的循环输出语句,如果不是#,那么跳回s1进行输入
        je next          //使用的是ZF寄存器
        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实现的功能是?

 

答:一直从键盘读入字符,判断其是否是#,如果不是则将读入的字符存放到data数据段当中。

 

问:line21-27实现的功能是?

 

答:将data数据段中的字符打印到显示屏上。

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); 
}
 

反汇编得到的结果:

 

 

问:分析反汇编代码,从汇编的角度,观察高级语言中参数传递和返回值是通过什么实现的,以及,参数入
栈顺序,返回值的带回方式,等等。

 

答:从汇编角度来看,参数传递是将参数保存到内存单元,然后使用寄存器来调参使用。被调函数的返回值在该例中是通过eax寄存器来存储的。多个参数入栈时是后定义的数据先入栈,如本函数调用过程中参数的入栈顺序:参数b先入栈,参数a后入栈。程序返回到主调函数可以通过eax寄存器来获取被调函数的返回值

 

 

posted @ 2020-12-16 20:25  gd_li  阅读(193)  评论(3)    收藏  举报