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

实验任务1:

task1.asm代码:

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        ;es保存目标显存段地址

    mov bx,720h       ;bx保存第一行目标显存偏移地址的起始地址
    mov cx,16        ;cx保存循环次数,此处一共需要输入16个字符
    mov si,0
    mov di,0a0h       

s:    mov al,ds:[si]      ;移入al,用以确保每次移入内存1个字节
    mov es:[bx],al       ;偏移地址:bx——第一行
   mov es:[bx+di],al      ;偏移地址:bx+di——第二行(di=0a0h=160) mov es:[bx+di+0a0h],al    ;偏移地址:bx+di+0a0h——第三行 inc bx      ;bx自增一次,接下来分别加入各行的属性控制 mov byte ptr es:[bx],02h           ;0 000 0 010 B —— 黑(000)底绿(010)字   mov byte ptr es:[bx+di],24h          ;0 010 0 100 B —— 绿(010)底红(100)字 mov byte ptr es:[bx+di+0a0h],71h        ;0 111 0 001 B —— 白(111)底蓝(001)字 inc si      ;si自增继续读入数据段中下一个字符 inc bx      ;bx再次自增,指定下一个目标内存地址偏移 loop s mov ah, 4ch int 21h code ends end start

编译、连接,运行结果截图:

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

(1) 显示属性:

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

 使用8位(1字节)进行表示

 

 使用mov指令是时, 移入数据至内存空间,需要指明数据类型 否则报错  operand must have size

 (2)屏幕*位置的计算:

一行显示80个字符,显示一个字符需要2字节(内容  属性),一行共160字节

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

正中间三行为Line 11、12、13;

目标显存第一个字符的偏移地址为:1760+(160/2 - 1)- 15 =  1824 = 0720H

第一行:0720H~073FH 之后两行对应位置的偏移量分别加上 160 (0a0H)和 320 (0a0H + 0a0H);

实验成功。

实验任务2:

   task2.asm源代码:

assume cs:code, ds:data
data segment
    str db 'try', 0      ;str 'another try',0
data ends

code segment
start:  
    mov ax, data
    mov ds, ax

    mov si, offset str
    mov al, 2          ;mov al,4
    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

(1)原始代码编译、连接,执行结果:

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

(2)修改:将代码中数据段中字符串修改为 :‘another try’,0

…………………………
data segment str db 'another try', 0 data ends

…………………………

mov al,4      ;mov al,2
…………………………

编译、连接,执行结果:

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

问题:

 1 assume cs:code, ds:data
 2 data segment
 3     str db 'another 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     ;str为数据段起始偏移地址 ——— 设置数据段入口参数
12     mov al, 4                 ;设置字符显示属性  00000 100B——红色
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]   ;cl保存当前读入数据段中的字符; 
28     mov ch, 0      ;设置ch=0,若cl读入0,即已读入字符串末尾;则cx=0
29     jcxz over      ;当cx = 0 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

(3)基于运行结果,理解源代码:

组合使用转移指令call和ret实现子程序的原理与方法:

具体地,在line18-49中:

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

功能:子程序开始之前,将主程序中使用的保存着主程序参数的寄存器的值存入栈中,在子程序功能结束之后,恢复寄存器中参数;

目的:保持主干程序的参数在调用子程序前后一致;

由于寄存器数量有限,子程序在实现其功能时有可能会改变保存着主程序重要参数的寄存器的值,导致主程序执行出错;在子程序运行之前,先将寄存器值全部入栈,子程序调用完成后恢复寄存器值。无法预料子程序中会用到哪些寄存器,索性统一全部进行入栈,结束后出栈恢复的操作。

②line31的功能是什么?

 每次移入一个字数据cx至目标显存,cl:目标内容,ch:目标属性;

 

实验任务3:

 task3.asm源代码为:

assume cs:code, ds:data
data segment           ;数据段共占据20H个字节
        x dw 1984        ;存储长度为一个字两字节,
        str db 16 dup(0)    ;存储长度为一个字节,共16字节,两段数据共17字节,补全至32字节存储
data ends

code segment
start:  
        mov ax, data        
        mov ds, ax         ;将ds段寄存器设置为数据段开始
        mov ax, x          ;反汇编查看实际代码为:mov ax,[0000]    ds:[0000]=07C0
        mov di, offset str      ;设置偏移量di,为后续保存结果设置入口参数  offset str = 0002

        call num2str          
        mov ah, 4ch
        int 21h

num2str:
        push ax             ;进入子程序先保存参数
        push bx
        push cx
        push dx
        
        mov cx, 0
        mov bl, 10             ;设置除数,8位
s1:      
        div bl               ;被除数默认保存在AX中
        inc cx              ;记录位数,作为s2中loop指令的循环次数
        mov dl, ah            ;将AH中的余数移入dl
        push dx              ;将DX入栈,(出栈入栈以字为单位
        mov ah, 0            
        cmp al, 0             ;若此次除法结果的商为0,表示已取到所有数字;cmp al,0  若al=0,指令执行后zf=1
        jne s1               ;若zf=0,回到s1再次执行

s2:        
        pop dx               ;取出一个字
        or dl, 30h            ;将dl中保存的数字转换为字符
        mov [di], dl           ;[di]为str的起始偏移地址  将结果保存到str:依次为1 9 8 4  
        inc di
      inc ax              ;依旧保存循环次数
        loop s2              ;循环四次
        mov cx, ax            ;赋给CX
       mov bx, 0b800H
      mov es, bx             ;es保存显存段地址

      mov al, 2             ;设置输出字符串属性值
     mov di, offset str        ;取需要复制的数据的起始偏移地址,段地址在ds中
     mov si, 0              ;目标显存的偏移地址
s3:     

     push cx                ;保存cx,因为代码中改变了其值
     mov cl, [di]            ;低位保存内容
     mov ch,al              ;高字节保存属性
     mov es:[si], cx           ;内容+属性入栈      inc di                ;di加1,继续下一个字符      add si, 2              ;目标地址偏移加2 pop cx                ;还原cx的值 loop s3

pop dx pop cx pop bx pop ax ret code ends end start

 

 运行结果:

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

 (1)查看程序段内容是否改变:

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

 已经成功转换为字符串,并保存在str开始的内存中;

(2)加入输出代码后能输出;

改变数字:结果如下,

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

输出成功。

实验任务4:

 task4.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

运行结果:

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

 ①line12-19实现的功能:

当前输入字符不为‘#’时,持续从键盘读入字符并在屏幕上显示;

并将输入的字符保存在data段预留的内存中;

②line21-27实现的功能:

在屏幕上输出读入的字符(不包括最后的‘#’);

实验任务5:

反汇编代码:

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

设置断点,开始调试,查看反汇编:

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

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

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

分析反汇编代码,从汇编的角度,观察高级语言中参数传递和返回值是通过什么实现

 ①高级语言中参数传递和返回值是通过什么实现的:通过寄存器和栈来实现;

此处为值传递,被调函数的形参作为被调函数的局部变量,在该函数的栈中开辟内存空间以存放主函数传递进来的实参值,对参数的操作不影响主函数实参的值。

②参数的入栈顺序:参数入栈根据参数列表中的顺序,从右往左;

③返回值的带回方式:结果保存在寄存器中带回。

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

上一篇:实验2 汇编源程序编写与汇编调试.pdf


下一篇:汇编语言(王爽)学习记录_第五章