欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

汇编语言学习(四)

程序员文章站 2022-03-13 10:45:53
...

该部分主要包含了王爽《汇编语言》第9章的全部内容和第10章除实验外的内容。

第9章主要介绍了多种jmp指令,其中部分指令根据位移进行转移。需要理解和掌握根据位移进行转移的意义。

而第10章主要介绍了call和ret指令,由call和ret组成了子程序的框架。call和ret也都用到了栈。需要理解call和ret对栈段带来的变化。

1.jmp

1.jmp指令的分类

jmp short s的机器码中,并未包含标号s的地址,而是包含了转移的位移

由于CPU执行指令的过程为:

1.从CS:IP指向的内存单元读取指令,读取的指令进入指令缓冲器

2.(IP)=(IP)+所取指令的长度,从而指向下一条指令

3.执行指令,转到1,重复这个过程。

所以转移位移的大小等于 = 标号处的位移 - jmp指令后第一个字节的地址

依据位移转移的意义:

便于程序在内存中的浮动分配。如果指令中包含了转移目的地址,则程序段在内存中的偏移地址就有了严格的限制。

转移指令 特点 功能
jmp short 标号 段内短转移:依据位移进行转移 (IP)=(IP)+8位位移
jmp near ptr 标号 段内近转移:依据位移进行转移 (IP)=(IP)+16位位移
jmp far ptr 标号 段间(远)转移:转移目的地址在指令中 (CS:IP)标号在段中地址
jmp 16位reg 后加寄存器 (IP)=(16位reg)
jmp word ptr 内存单元地址 段内转移:后加内存单元地址 (IP)等于内存单元数据
jmp dword ptr 内存单元地址 段间转移:后加内存单元地址 (CS:IP)等于内存单元数据
jcxz 标号 短转移,依据位移,cx不为0向下执行 cx=0,则(IP)=(IP)+8位位移
loop 标号 短转移,依据位移进行转移 cx减1,cx不为零跳到标号处执行
2.检测点:若使jmp指令执行后,CS:IP指向程序的第一条指令,在data段应该定义哪些数据?
assume cs:code,ds:data
data segment
    db 0,0,0   ;注意应该为字节型,jmp时取第二个和第三个零作为IP的值
data ends
code segment
code ends
start:  mov ax,data
        mov ds,ax
        mov bx,0
        jmp word ptr [bx+1]
end start
3.实验8 分析一个奇怪的程序,思考为何是这种结果?
assume cs:codesg
codesg segment
        mov ax,4C00h
        int 21h
start:mov ax,0
s:      nop
        nop
        mov di,offset s
        mov si,offset s2
        mov ax,cs:[si]
        mov cs:[di],ax  
s0:     jmp short s
s1:     mov ax,0
        int 21h
        mov ax,0
s2:     jmp short s1
        nop
codesg ends
end start

汇编语言学习(四)

可以看出,该程序在执行时的顺序是:

s -> s0 -> s -> mov ax,4C00h

分析程序可知,s的前两个nop指令的机器码被s2的jmp short s1指令的机器码所替代。之所以会出现从s向上跳到程序结束处mov ax,4C00h,而不是跳到s1处,是由于jmp short s1指令的机器码中并没有存储s1的位置,而是存储了从s2至s1的相对位移,借助这个相对位移,s跳到了程序结束处

4.实验9 根据材料编程

原理:内存地址空间中,B8000H~BFFFFH共32KB的空间,为80*25彩色字符模式的显示缓冲区。向这个地址空间写入数据,写入的内容将立即出现在显示器上。

显示缓冲区分为8页,每页4KB,显示器可以显示任意一页的内容。一般情况下,显示器显示第0页的内容。

一行中,一个字符占两个字节的存储空间,低位字节存储字符的ASCII码,高位字节存储字符的属性。

属性字节的格式:

7 6 5 4 3 2 1 0
BL R G B I R G B
闪烁 背景红 背景绿 背景蓝 高亮 前景红 前景绿 前景蓝

黑底对应背景色是000,白底是111。

闪烁效果只有在全屏方式下才能看到。

输入过程中:

汇编语言学习(四)

输入结束后:(截图看不出来闪烁)

汇编语言学习(四)

用代码编写如下:

assume cs:code,ds:data,ss:stack
data segment
    db 'Welcome to masm!'
    db 8Ah,0CCh,0F9h
data ends
stack segment
    dw 8 dup (0)
stack ends
code segment
start:  mov ax,data
            mov ds,ax
            mov ax,stack
            mov ss,ax
            mov sp,16
            mov ax,0B872h
            mov es,ax

            mov cx,3
            mov si,0 ;ds:[16+si]
s:          push cx
            mov bx,0 ;ds:[bx+idata]
            mov di,0 ;es:[di+idata]
            mov cx,16
s1:         mov al,ds:[bx]
            mov es:[di],al
            add di,2
            add bx,1
            loop s1  ;填ASCII码
            mov cx,16
            mov di,1
s2:         mov al,ds:10h[si]
            mov es:[di],al
            add di,2
            loop s2  ;填字符属性
            mov ax,es
            add ax,0Ah
            mov es,ax
            add si,1
            pop cx
            loop s   ;三行

            mov ax,4C00h
            int 21h
code ends
end start

2.call和ret

1.基本语法
call和ret 特点 功能类似于汇编指令
ret 用栈中数据修改IP,近转移 pop IP
retf 用栈中数据修改CS和IP,远转移 pop IP | pop CS
call 标号 转到标号处执行,依据位移转移 push IP | jmp near ptr 标号
call far ptr 标号 转到标号处执行,实现段间转移 push CS|push IP|jump far ptr 标号
call 16位reg 转移地址在寄存器 push IP | jump 16位reg
call word ptr 内存地址 转移地址在内存 push IP|jump word ptr 内存
call dword ptr 内存地址 转移地址在内存 push CS|push IP|jmp dword ptr 内存
2.检测点:下面的程序执行后,ax中的数值为多少?
assume cs:code,ss:stack
stack segment
    dw 8 dup (0)
stack ends
code segment
start:   mov ax,stack
        mov ss,ax
        mov sp,16
        mov ds,ax
        mov ax,0
        call WORD ptr ds:[0EH]
        inc ax
        inc ax
        inc ax
        mov ax,4C00h
        int 21h
code ends
end start

对程序的执行步骤进行分析:

1.顺序执行至call word ptr ds:[0EH]处。已知条件是dsss相等,而且ss:[0EH]处值为0。

首先CPU加载该指令,IP指向下一条指令inc ax,接着CPU执行call指令,将inc ax的IP地址放入栈中,IP被修改为0。

所以目前CS:IP指向start:mov ax,stack

2.继续顺序执行至call word ptr ds:[0EH]处。已知条件是dsss相等,但是ss:[0EH]处值为inc ax的IP地址。

CPU加载指令,IP指向下一条指令inc ax,接着CPU执行call指令,将inc ax的IP地址放入栈中,IP被修改指向下一句inc ax

3.顺序执行,得到(ax) = 3

执行步骤的分析中容易出现错误的地方:

1.未注意dsss相等,无法进行下一步分析。

2.未考虑call指令将下一句的IP地址push到栈中,下一次取出来直接用。

3.模块化程序设计

利用call和ret指令,可以实现多个相互联系、功能独立的子程序。为使:

1.编写调用子程序的程序时不必关心子程序到底使用了哪些寄存器。

2.编写子程序时不必关心调用者使用了哪些寄存器。

3.不会发生寄存器冲突。

确定了编写子程序的标准框架:

子程序开始:子程序使用的寄存器入栈
           子程序内容
           子程序使用的寄存器出栈
           返回(ret、retf)
相关标签: 王爽 汇编语言