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

四、实验结论

1.实验任务1

taks1.asm源代码如下:

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 ;数据段地址
    mov ax, 0b800H
    mov es, ax ;附加段地址
    mov bx, 0010H  ; 颜色数据于数据段偏移地址
    mov di, 1824; 第一行第一个字符w的在附加段中的偏移地址,即第12行第32列(12*160+64=1824)
    mov cx, 3      ;三行输出,三次循环
s1: 
    mov si, 0  ;每次输出后都要初始到数据段开始重新输出目标字符
    push cx    ;将外层循环次数cx入栈保存
    mov cx, 16 ;一行16个字符,循环16次
s2: 
    mov al, ds:[si] ; 将数据段对应字符内容一一读出
    mov ah, ds:[bx] ;读取字符样式
    mov es:[di], ax   ;将读出的对应样式的字符写入显存
    inc si  
    add di,2
    loop s2   ;跳出内层循环,对应屏幕上打印完一行
    add di, 128  ;算出下一行开始偏移地址+(160-32)
    inc bx
    pop cx ;在跳转s1前将外层cx出栈
    loop s1 ;回到外层循环开始
    mov ah, 4ch
    int 21h
code ends
end start

运行截图如下:

说明:本实验任务关键就在于计算屏幕中央对应的显存区域,已知是80*25,所以是第11-13行,然后每行16个字符,所以是32-48列,因此算出第一行开始偏移地址是1824,然后第二行第三行依次比上一行160即可,然后使用两层循环结构写入显存即可即可

2.实验任务2

task2.asm的源代码如下:

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

 然后运行程序截图如下:

 答:(1)push将跳转用到的寄存器状态压入栈中,因为子程序中也用到了这些寄存器,防止因为子程序段修改这些寄存器的值导致跳转不能正常执行,因此压入栈中等待子程序段执行后再把压入的寄存器状态出栈。

(2)line30"mov es:[di], cx"中,es对应b800H是显存的基准地址,[di]则是偏移地址,表示将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
        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

(1)子任务1

u命令对代码段反汇编截图如下:

 使用g命令执行到Line15然后可以使用d命令可以看到数据段中写入数字字符串'1984':

 (2)子任务2

对task3.asm源代码进行修改、完善,把task2.asm中用于输出以0结尾的字符串的子程序加进来,
实现对转换后的字符串进行输出:
修改后代码如下:
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
        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
运行结果如下:

 将Line3中数字随意修改后重新汇编链接运行如下:

补充:经过评论提示,对于输出到屏幕的内容与样式并没有完整设置好,在call prinstr之前增加了mov al,2设置颜色入口参数,以及增加mov si,offset str。设置si初始值使得第一次进入s段中打印时会跳过ASCII码对应内容,修改后的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
        mov di, offset str
        call num2str
        mov al, 2  ;修改颜色入口参数
        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 
    mov si, offset str
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
        mov [si], al
        cmp al, '#'
        je next
        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

测试运行截图如下,输入字符串hello并以#结束,程序会自动在#后输出一个相同字符串:

 其中line12-19行实现了读取使用者从键盘中输入的字符串并且将其存放到data数据段中,在遇到'#'时结束跳转到next程序段

line21-27行 使用软中断指令Int21的二号子功能将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);
}

使用devc++进行debug:

可以看到sum程序段反汇编如下:

main程序段反汇编如下

 可以看到main()中789行使用mov指令在ecx中存储了eax即DWORD PTR[rbq-0x4](值为2),对应的高级语言将a的值,和edx存储的是DWORD PTR[rbq-0x8](值为7)对应高级语言的b的值,然后通过eax读取sum()的返回值。可以看到sum()中3.4行通过读取ecx和edx的值读取了参数a,b的值,而寄存器eax存储sum()函数的结果,然后在main()中反汇编11行通过Mov指令将eax赋给DWORD[rbp-0xc]对应的就是高级语言中main()函数体第二行将sum(a,b)的返回值赋值给c,得出结论,高级语言通过寄存器来实现参数传递和返回值。

 

 

 

posted @ 2020-12-18 12:24  斐然曰  阅读(160)  评论(3)    收藏  举报