【原创】汇编语言的基本知识(二)

五,loop指令实现循环

1,[bx]和内存单元的描述

(1)完整地描述一个内存单元需要2种信息:1,内存单元的地址;2,内存单元的长度

用[0]表示内存单元的时候,0表示单元的偏移地址,段地址默认在ds中;

[bx]同样也表示一个内存单元,它的偏移地址在bx中,段地址默认在ds中;

2,一般用"()"来表示一个寄存器或一个内存单元中的内容

,3,loop指令的坐拥:1,(cx) = (cx) -1 ;2判断cx中的值,不为0则转至标号出执行程序,为0则向下执行

#计算2的12次方

assumne cs:code
code segment
    mov ax,2
    mov cx,11
s: add ax,ax
    loop s
    mov ax,4c00h
    int 21h
code ends
end

4,在汇编源程序中,数据不能以字母开头,要在前面加0,比如A000H在汇编程序中改写为"0A000H"

5,段前缀:在访问内存的指令中,使用:显示地指明内存单元的段地址,在汇编语言中称为段前缀

mov ax,ds:[bx]
mov ax,cs:[bx]
...
ds: cs:等都是段前缀

6,段前缀的使用,例:将内存ffff:0~ffff:b单元中的数据复制到0:200~0:20b单元中。

assume cs:code
    code segment 
        mov bx,0
        mov cx,12
    s: mov ax,0ffffh
        mov ds,ax
        mov dl,[bx]
    
        mov ax,0020h
        mov ds,ax
        mov [bx],dl
        
        inc bx
        loop s
    
        mov ax,4c00h
        int 21h

code ends
end

7,将数据,代码,栈放入不同的段

assume cs:code ,ds:data,ss:stack
data segment
    dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987
data ends
stack segment
    dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
stack ends
code segment
start:mov ax,stack
    mov ss,ax
    mov sp,20h
    mov ax,data
    mov ds,ax
    mov bx,0
    mov cx,8
s: push [bx]
    add bx,2
    loop s0
    mov ax,4c00h
    int 21h
code ends
end start

 

六,更灵活的定位内存地址

1,逻辑指令 and和or

#按位进行与运算
mov al,01100011B
and  al,00111011B
结果为:al=00100011B

#按位进行或运算
mov al,01100011B
or    al,00111011B
结果为:al=01111011B

2,以字符形式给出数据:ASCLL码

mov al,'a' 相当于执行 mov al,61H, 'a'的asciil码的16进制为61

3,用[bx+idata]的方式进行数组的处理,inc指令

举例:将datasg中定义的第一个字符串转化为大写,第二个字符串转化为小写

assume cs:codesg ds:datasg

datasg segment
    db 'BiSiC'
    db 'MinIX'
datasg ends
codesg segment
    start:mov ax,datasg
    mov ds,ax
    mov bx,0
    mov cx,5    
s: mov al,[bx]
    and al,11011111b
    mov [bx],al
    mov al,[5+bx]
    or al,00100000b
    mov [5+bx],al
   inc bx
    loop s

codesg ends

end start

4,不同的寻址方式的灵活应用

[idata] 1个常量,直接定位一个内存单元

[bx] 1个变量,间接定位一个内存单元

[bx+idata] 1个变量+1个常量

[bx+si] 2个变量

[bx+si+idata] 2个变量+1个常量

 5,程序中经常需要进行数据的暂存,需要一个通用的方案解决寄存器数量有限的问题

(1)当寄存器不够用的时候,就需要用内存单元保存数据了;

(2)一般来说,在需要暂存数据的时候,我们都应该使用栈。

 

七,数据处理的2个基本问题

1,用reg表示1个寄存器,sreg表示一个段寄存器

reg包括:ax bx cx dx al bl cl dl ah bh ch dh sp bp si di

sreg包括:ds cs es ss

这4个寄存器可以单个出现:bx si di bp

2,数据位置的表达
(1)立即数:对于直接包含在机器指令中的数据(执行前在cpu的指令缓冲器中)

mov ax,1
add bx,2000h
or bx,00010000b
mov al, 'a'

(2)寄存器:指令要处理的数据再寄存器中,需要给出相应的寄存器名

mov ax,bx
mov ds,ax
push bx
mov ds:[0],bx
push ds
mov ss,ax
mov sp,ax

(3)段地址(SA)和偏移地址(EA):要处理的数据再内存中,用[X]的格式给出EA

#段地址默认在ds中
mov ax,[0]
mov ax,[di]
mov ax,[bx+8]
mov ax,[bx+si]
mov ax,[bx+si+8]

#段地址默认在ss中
mov ax,[bp]
mov ax,[bp+8]
mov ax,[bp+si]
mov ax,[bp+si+8]

#显示给出段地址的寄存器
mov ax,ds:[bp]
mov ax,es:[bx]
mov ax,ss:[bx+si]
mov ax,cs:[bx+si+8]

3,指令要处理的数据有多长

 cpu指令可以处理两种尺寸的数据:byte(字节)和word(子)。所以在机器指令中要指明是字操作还是字节操作

(1)通过寄存器名指明要处理的尺寸

(2)没有寄存器名存在的情况下,用操作符X ptr指明内存单元的长度

mov word ptr ds:[0],1
mov byte ptr ds:[0],1

(3)其他方法:push [1000H]就不用指明,因为push指令只进行word字操作

4,div指令:除法指令

1,除数:
有8位和16位2种,在一个reg或内存单元中

2,被除数:
默认放在AX或DX和AX中

3,结果:
如果除数为8位,则AL存储商,AH存储余数,
如果除数为16位,则AX存储商,DX存储余数

5,伪指令dd

dd定义字节型,dw定义字型

dd定义双字型

6,dup是一个操作数,在汇编语言中同db dw dd等一样,也是由编译器识别处理的符号。与db dw dd配合使用,用来进行数据的重复,比如

db 3 dup (0)  ;定义了3个字节,它们的值都是0
#相当于
db 0,0,0

db 3 dup (0,1,2)
#相当于
db 0,1,2,0,1,2,0,1,2

db 3 dup ('abc','ABC')
#相当于
db 'abcABCabcABCabcABC'

db 重复次数 dup (重复的数据)

dw 重复次数 dup (重复的数据)

dd 重复次数 dup (重复的数据)

 

八,转移指令的原理

1,可以修改IP,或同时修改CS和IP的指令统称为转移指令。一般有一下几类:

无条件转移指令(jmp)
条件转移指令
循环指令(loop)
过程
终端

2,操作符offset在汇编语言中是由编译器处理的符号,它的功能是取得标号的位移地址。

3,jmp为无条件转移指令,可以只修改IP,也可以同时修改CS和IP,jmp指令要给出2种信息

(1)转移的目的地址

(2)转移的距离(段间转移、段内段转移,段内近转移)

4,段内段转移:jmp short 标号

assume cs:codesg

codesg segment
    start:mov ax,0
        jmp short s
        add ax,1
    s: inc ax
codesg ends
end start

在"jmp short 标号"指令所对应的机器码中,并不包含转移的目的地址,而包含的是转移的位移

实际上,jmp short 标号的功能为:(IP)=(IP)+8位位移

(1)8位位移=标号处的地址-jmp指令后的第一个字节的地址

(2)short指明此处的位移为8位位移

(3)8位位移的范围为-128~127,用补码表示

(4)8位位移有比哪一程序在编译时算出(此处可以深究下)

5,段内近转移:jmp near ptr 标号;其功能为:(IP)=(IP)+16位位移

6,段间转移(远转移):jmp far ptr 标号,功能为

(CS)=标号所在段的段地址;(IP)=标号所在段的偏移地址

7,转移地址在寄存器中:jmp 16位ref 。功能为:(IP)=(16位reg)

8,转移地址在内存中:

(1)jmp word ptr 内存单元地址,属于段内转移

  (IP)=(内存单元地址)

(2)jmp dword ptr 内存单元地址,属于段间转移

  (CS)=(内存单元地址+2)

  (IP)=(内存单元地址)

9,jcxz指令:有条件转移指令,所有有条件指令都是短转移,在对应的机器码中包含转移的位移,而不是目的地址

格式:jcxz 标号(如果(CX)=0,转移到标号处执行)

操作:当(CX)=0时,(IP)=(IP)+8位位移

相当于:if((CX)==0) jmp short 标号

10,loop指令,所有循环指令都是短转移,在对应的机器码中包含转移的位移,而不是目的地址

格式:loop 标号

操作:

(1)(CX)=(CX)-1 

(2)如果(CX)不等于0,(IP)=(IP)+8位位移  

相当于:

(CX)--;

if((CX)<>0) jmp short 标号

11,根据位移进行转移的意义:方便程序段在内存中的浮动装配

12,call和ret指令都是转移指令,通常一起使用实现子程序的设计

(1)ret指令用栈中的数据,修改IP的内容,从而实现近转移,

  相当于执行  pop IP

(IP)=((SS)*16+(SP))
(SP)=(SP)+2

 

(2)retf指令用栈中的数据,修改CS和IP的内容,从二实现远转移 

  相当于执行 pop IP    pop CS

(IP)=((SS)*16+(SP))
(SP)=(SP)+2
(CS)=((SS)*16+(SP))
(SP)=(SP)+2

 

(3)call指令:根据位移进行转移时

格式:call 标号

(SP)=(SP)-2
((SS)*16+(SP))=(IP)
(IP)=(IP)+16位位移

相当于进行

push IP

jmp near ptr 标号

 13,call far ptr 标号 :目的地址在指令中,实现的是段间转移,

(SP)=(SP)-2
((SS)*16+(SP)) = (CS)
(SP)=(SP)-2
((SS)*16+(SP)) = (IP)

(CS)=标号所在段的段地址
(IP)=标号所在段的偏移地址

相当于进行

push CS

push IP

jmp far ptr 标号

14,call 16位reg:转移地址在寄存器中

(SP)=(SP)-2
((SS)*16+(SP)) = (IP)
(IP)=(16位reg)

相当于 push IP

jmp 16位reg

15,call word ptr 内存单元地址:转移地址在内存中

相当于 

push IP

jmp word ptr 内存单元地址

16,call dword ptr 内存单元地址:转移地址在内存中

相当于

push CS

push IP

jmp dword ptr 内存单元地址

17,call和ret的配合使用

assume cs:code

code segment
main: ...
        ...
    call sub1
        ...
         ...
    mov ax,4c00h
    int 21h

sub1: ...
        ...
    call sub2
        ...
        ...
    ret

sub2: ...
        ...
        ...
    ret
code ends
end main

(1)从上面可以看出,call和ret指令共同支持了汇编语言编程中的模块化设计。

(2)参数和结果的传递:参数存在什么地方,计算结果存放在什么地方;答案是寄存器

(3)对于存放参数的寄存器和存放结果的寄存器,调用者和子程序的读写操作恰恰相反

调用者将参数送入参数寄存器,从结果寄存器中取得返回值

子程序从参数寄存器中取得参数,将返回值送入结果寄存器

assume cs:code

data segment
    dw 1,2,3,4,5,6,7,8
    dd  0,0,0,0,0,0,0,0
data ends

code segment

    start:mov ax,data
            mov ds,ax
            mov si,0
            mov di,16

            mov cx,8
    s:     mov bx,[si]
            call cube
            mov [di],ax
            mov [di].2,dx
            add si,2
            add di,4
            loop s

            mov ax,4c00h
            int 21h
    cube: mov ax,bx
            mul bx
            mul bx
            ret

code ends
end start

18,mul指令:乘法

(1)2个相乘的数,要么都是8位要么都是16位,

如果是8位,一个默认在AL中,另一个在8位reg或内存字节单元中

如果是16位,一个默认在AX中,另一个在16位reg或内存字单元中

(2)结果:如果是8位乘法,结果在AX中;如果是16位乘法,结果高位默认在DX中存放,低位在AX中存放。

格式:mul reg或者mul 内存单元

举例:

mov al,100
mov bl,10
mul bl

 

posted @ 2021-01-28 15:00  小匡程序员  阅读(430)  评论(0编辑  收藏  举报