汇编指令与伪指令总结

汇编语言包含两种指令:
1、汇编指令:有对应机器码的指令,可编译为机器指令被CPU执行
2、伪指令:没有对应机器码,不被CPU执行

dw字型 ——2bytes
db字节型——1byte
dd双字型——4bytes
mov/add/sub:

mov 寄存器,数据
mov 寄存器,寄存器
mov 寄存器,内存单元
mov 内存单元,寄存器

在寄存器和内存单元间(双向)传递数据时,以寄存器的大小为标准传递数据,用8位寄存器就传8位,用116位寄存器就传16位。

mov 段寄存器,寄存器
mov 寄存器,段寄存器

add/sub指令除了不能对段寄存器操作外,其余用法与mov相同

push和pop:
栈知识补充:栈的生长方向是由高地址到低地址,栈初始为空时,SS:SP指向栈底即栈空间最高地址单元的再高一个地址单元,即空栈时SS:SP指向栈外push ax表示将ax中的内容入栈,由以下两步完成:
(1)sp=sp-2,sp向前两个Bytes,栈顶更新
(2)将ax中的内容送入SS:SP指向的内存单元可以看出,使用栈段时应从高地址开始使用,如:

stack segment
    dw 0,0,0,0,0,0,0,0
stack end
scodesg segment
    mov ax,stack
    mov ss,ax
    mov sp,16
            .
            .
            .
codesg ends

push (段)寄存器
pop (段)寄存器
push 内存单元
pop 内存单元

segment······ends:成对出现,用于定义一个段,格式如下:
段名 segment
.
.
段名 ends

end

end是一个汇编程序结束的标记,在编译汇编程序过程中若遇到end就结束对源程序的编译。
可以在某条指令前加上标记如start,整个程序最后end start,此处end的作用是告知编译器程序的入口。

assume
假设某一个段与某一个段寄存器关联。在数据段中定义的每一个变量标志符其实都代表了一个偏移量(也称为有效地址),这个偏移量与数据段段值相结合就指向某个内存地址。在程序中使用 ASSUME伪指令是用来指明一个默认的段地址。一旦你把某个数据段的段名指定给某个段寄存器(比如ASSUME DS,DATA1),这之后当你使用这个数据段(DATA1)内定义的变量,编译程序就自动把它与这个段寄存器(DS)里的段值(表示一个段地址)结合起来使用。
即只有当段中定义了变量assume才发挥作用?此处按下不表

inc bx:bx中的内容加1
功能上与add bx,1等价
dec bx:bx中的内容减1

loop p
先对cx减1,然后判cx是否为0,不为0,转后面给出标号所指的入口p;
为0,顺序执行

and和or
and:按位逻辑与
or:按位逻辑或
【字符常量由db定义,可当成整数对待】
对任意一个字符串,每个英文字母分别和00100000B做逻辑或可转换成小写字母
和11011111做逻辑与可转换成全大写字母

div
除法指令,用法:
div reg
div 内存单元
(实际上是div 除数)
其中:除数放在一个寄存器或内存单元中
被除数放在ax,dx中:
如果除数是8位,则被除数16位,默认放在ax中
如果除数是16位,则被除数32位,dx中放高16位,ax中放低16位
如果除数是8位,则al储存除法的商,ah存储除法的余数
如果除数是16位,则ax存储除法的商,dx存储除法的余数

16进制数的低四位是二进制数的低八位;
16进制数的高四位是二进制数的高八位。

dup
操作符。和db、dw、dd等数据定义伪指令配合使用,用于数据的重复
eg.

db 3 dup(0,1,2)

定义了9个字节,相当于

db 0,1,2,0,1,2,0,1,2
db 3 dup('abc','ABC')

定义了18个字节,相当于

db 'abcABCabcABCabcABC'

能够修改IP或同时修改CS和IP的指令统称转移指令。

offset操作符,由编译器处理。用于取得标号的偏移地址。

start:mov ax,offset start
     s:mov bx,offset s
codesg ends
end start

上面程序将start和s处的偏移地址分别保存到了ax和bx中

nop
空操作,机器码占一个字节

jmp
无条件转移指令,可以只修改IP,也可以同时修改CS和IP
jmp 段地址:偏移地址 可以通过这样的指令修改CS和IP
jmp 合法寄存器 可以仅将IP改为寄存器中的值

根据位移进行转移的jmp
jmp short 标号
段内短转移,转到标号处执行。对IP的修改范围为-128~127,即向前最多128bits
CPU在执行jmp指令时不需要转移的目标地址,jmp指令的实际功能为:修改IP=IP+8位位移
1、8位位移=标号处地址-jmp指令后的第一个字节的地址(编译时算出)
2、short指明此处的位移为8位位移
3、8位位移范围为-128~127,用补码表示
4、8位位移由编译程序在编译时算出

jmp near ptr 标号
段内近转移,转到标号处执行。对IP的修改范围为-32768~32767,即向前最多32768bits
CPU在执行jmp指令时不需要转移的目标地址,jmp指令的实际功能为:修改IP=IP+16位位移
1、16位位移=标号处地址-jmp指令后的第一个字节的地址(编译时算出)
2、near ptr指明此处的位移为16位位移
3、16位位移范围为-32768~32767,用补码表示
4、16位位移由编译程序在编译时算出

短转移和近转移都只修改了IP的值

转移目的地址在指令中的jmp指令

jmp far ptr 标号

段间转移,又称远转移。该指令可同时将CS和IP修改为标号处的段地址和偏移地址。
只有jmp far ptr会将目的地址写在其机器码中

转移目的地址在寄存器中的jmp指令

jmp 16位寄存器

功能:IP=寄存器中的数据

转移目的地址在内存中的jmp指令

1、jmp word ptr 内存单元地址(段内转移)

将内存单元中的一个字作为偏移地址进行转移

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

将从内存单元地址开始存放的
作为转移地址,高地址处的字作目的段地址,低地址处的字作目的偏移地址
CS=内存单元地址+2里的数据
IP=内存单元所放地址里的数据

jcxz
有条件转移指令,所有有条件转移指令都是短转移,对IP的修改范围为-128~127

jcxz 标号

当此时cx=0时跳转到标号处
当cx!=0时继续向下执行

loop
循环指令,所有循环指令都是短转移。
操作:
1.cx=cx-1
2.若cx != 0,IP=IP+8位位移(编译时算出)

jmp short、jmp near ptr、jcxz、loop对IP的修改都是根据转移目的地址和起始地址之间的位移进行修改的。它们的机器码中只包含到目的地址的位移

call和ret
ret和retf
ret:只修改IP所以只能实现短转移
1、IP=SS*16+SP
2、SP=SP+2
以上两步相当于

pop IP

retf:既可修改IP又可修改CS
1、IP=SS16+SP
2、SP=SP+2
3、CS=SS
16+SP
4、SP=SP+2
以上四步相当于

pop IP
pop CS
(先IP后CS)

call:根据位移进行转移

      call 标号

1、将当前IP入栈
2、修改IP:IP=IP+(标号处地址-call指令后第一个字节的地址)
相当于

        push IP
        jmp near ptr 标号

转移的目的地址在指令中

         call far ptr 标号

段间转移
1、SP=SP-2
2、CS入栈
3、IP入栈
4、CS=标号所在段的段地址
5、IP=标号所在段的偏移地址
相当于

push CS
push IP
jmp far ptr 标号

转移的地址在寄存器中

call 16位寄存器

1、SP=SP-2
2、IP入栈
3、IP=16位寄存器中的值
相当于

push IP
jmp 16位寄存器

转移地址在内存中
转移地址在内存中时,要告知call指令到内存取多长的地址:取16位(1个word)就只能修改IP,实现段内转移;取32位(两个字)就既能修改CS又能修改IP,故需要ptr来指明内存大小,以控制是段内转移还是段间转移。

call word ptr 内存单元地址

相当于

push IP
jmp word ptr 内存单元地址
call dword ptr 内存单元地址

相当于

push CS
push IP
jmp dword ptr 内存单元地址

(内存单元中高位作CS,即所call的内存单元地址+2中的值;低位作IP,即所call的内存单元中的值)
可以看到,call和ret(return)或return far可实现函数调功能。先call子函数,再ret返回。用于在使用call时先将CS入栈,再将IP入栈,所以使用ret或retf时先出栈IP再出栈CS。

mul乘法指令
1、乘数
* 都是8位
* 一个在al中
* 另一个在8位寄存器reg或内存单元中
* 都是16位
* 一个在ax中
* 另一个在16位寄存器reg或内存单元中

2、运算格式

    mul reg
    mul 内存单元

3、运算结果
8位乘法:结果在ax中
16位乘法:高16位结果在dx中,低16位结果在ax中

adc
带进位加法

adc 操作对象1,操作对象2

用法与add相同,但是功能有差别:
操作对象1=操作对象1+操作对象2+CF
作带进位加法

sbb
带进位减法

sbb 操作对象1,操作对象2

操作对象1=操作对象1-操作对象2-CF

使用带进位的运算时要先使用不带进位的add和sub,否则在CF位情况未知时使用带进位的运算可能导致结果出错。

cmp
比较指令
相当于减法指令,只是不保存结果。
可进行有符号数比较和无符号数比较
cmp 操作对象1,操作对象2
操作对象可以是16位寄存器也可以是8位寄存器(两个对象位数相同)
执行cmp时会计算操作对象1-操作对象2,但不保存结果,只对标志寄存器产生影响。

cmp ax,bx
ax=bx:ax-bx=0->zf=1
ax!=bx:ax-bx!=0->zf=0
axcf=1
ax>=bx:cf=0
ax>bx:cf=0&&zf=0
ax<=bx:cf=1 || zf=1

借助其他标志位对有符号数进行比较:

cmp ax,bx
ax=bx:of=0&&sf=0&&zf=1
ax!=bx:zf=0
axbx:of=0&&sf=0

根据无符号数的比较结果进行转移的各种条件转移指令:
≤表示偏序关系,其中两个操作数可以结合cmp指令表示为:操作数1≤操作数2(cmp 操作数1,操作数2)

指令         含义                         检测的相关标志位
je             等于则转移               zf=1
jne           不相等则转移           zf=0
jb             低于则转移               cf=1
jnb           不低于则转移           cf=0
ja              高于则转移              cf=0且zf=0
jna            不高于则转移           cf=1且zf=1

movsb
串传送指令。
b相当于byte
1、相当于

mov es:[di],byte ptr ds:[si]

(这里只是这样表示)
2、若df=0,则

si=si+1
di=di+1
 若df=1,则
si=si-1
di=di-1

执行一次movsb语句就相当于执行了上面两步

movsw
串传送指令
w相当于word
1、相当于

mov es:[di],word ptr ds:[si]

(这里只是这样表示)
2、若df=0,则

si=si+2
di=di+2
 若df=1,则
si=si-2
di=di-2

执行一次movsw语句就相当于执行了上面两步

rep
movsb和movsw一般配合rep指令使用,格式如下:

rep movsb
rep movsw

rep指令相当于:

s:movsb
loop s

rep也是根据cx的值重复执行后面的传送指令
df=0时从ds:[si]传到es:[di],且每次si和di递增,cld将df设为0
df=1时从ds:[si]传到es:[di],且每次si和di递减,std将df为设为1

cld和std
cld(clean df)指令:将标志寄存器的df位置0,movsb和movsw指令正向传送
std(set df)指令:将标志寄存器的df位置1,movsb和movsw指令反向传送

pushf和popf
pushf:将标志寄存器的值压栈
popf:从栈中弹出数据到标志寄存器

in和out
端口读写指令
只能读入ax或al中
对0~255端口进行读写时:
访问端口:

in al,6h   ;从6h号端口读入一个字节
out 20h,al     ;向20h端口写入一个字节

对256~65535端口进行读写时:端口号放在dx中

mov dx,3f8h     ;将端口号3f8h送入dx
in al,dx             ;从3f8h端口读入一个字节
out dx,al           ;向3f8h端口写入一个字节

shl和shr
逻辑移位指令
将一个寄存器或内存单元中的数据(二进制形式)左移或右移并补0

shl ax,n    ;ax里的数左移n位(2进制形式)即乘以2^n
shr ax,n    ;ax里的数右移n位,即除以2^n

※当移位位数大于1时,必须先将位数放在cl中:

mov al,01010001b
mov cl,3
shl al,cl

shl执行过程:
1、左移
2、移出的一位存入CF中
3、最低位补0

shr执行过程:
1、右移
2、移出的一位存入CF中
3、最高位补0

iret
中断程序返回指令。执行过程为:

pop IP
pop CS
popf

由此可推出在执行中断前所执行的压栈操作为:

pushf
push CS
push IP

int
引发中断
int n相当于引发一个n号中断过程。执行过程为:

1、取中断类型码n
2、标志寄存器入栈,IF=0,TF=0
3、CS、IP入栈
4、IP=n*4,CS=n*4+2

cli和sti
设标志寄存器中IF位的值
cli设IF的值为0,CPU不响应外部的可屏蔽中断
sti设IF的值为1,CPU可相应外部的可屏蔽中断

你可能感兴趣的:(汇编指令与伪指令总结)