X86指令系统

本文最后更新于:January 1, 2023 pm

X86指令系统

X86 32位寻址方式

寻址方式主要在三方面上进行运用:

  • 操作数的寻址
  • 转移地址的寻址
  • IO端口的寻址

以下分别对X86指令的三方面寻址方式进行说明

操作数寻址

由冯诺依曼架构可以得到这样的结论: 操作数的来源只有三处:

  1. 指令直接给出
  2. 存放在寄存器中
  3. 存放在内存单元中

其中最简单的方式就是由指令直接给出,最复杂的则为存放在内存单元中,以下将分别说明不同的寻址方式!

立即寻址

立即寻址即是由指令直接给出源操作数立即寻址只能用于指令的源操作数!
例:

1
mov al 1200H; 将1200H这个数放如al中

寄存器(直接)寻址

即操作数直接存放在寄存器中,处理器会直接从寄存器中拿取操作数。
例:

1
mov bl al; 将al中的数移动到bl中

寄存器间接寻址

操作数存放在内存之中,其偏移地址存放在寄存器之中,处理器先从寄存器中拿到偏移地址,再得到在内存之中的物理地址,再去该物理地址拿取操作数。
操作数的段基址取决于间址寄存器,若为EBP、ESP则默认在堆栈段,其他寄存器则为数据段。当然如果是flat模式则没有区别。
例:

1
2
3
v1 dw 1024; 定义字变量v1
lea ebx v1; 将v1的偏移地址取到ebx中,注意必须放置在32位寄存器中
mov ax, [ebx]; 将ebx寄存器存储的内存单元的操作数取到ax中,中括号说明是寄存器间接寻址而非寄存器(直接)寻址,注意v1是dw类型变量,需要16位以上寄存器进行存放

直接寻址

操作数存放在内存之中,偏移地址由变量表示。
例:

1
2
v1 db 1; 定义字节变量v1
mov al v1; 将v1对应的偏移地址的数据传送到al中

特别的,在X86保护模式下用户不能使用常数作为存储单元地址,若使用常数则视为立即寻址。
例:

1
mov al [1200H]; 等价于 mov al 1200H

寄存器相对寻址

操作数存放在内存中,操作数的偏移地址为间址寄存器的内容加上一个位移量,位移量可以是一个常数,也可以是变量
例:

1
2
3
4
5
6
7
data dd 1; 相对偏移量
mov ax, [ebx+data]; 将ebx+data寄存器存储的内存单元的操作数移动到ax中
mov ax, data[ebx]; 相同的含义不同的语句形式
mov ax, [ebx]+data; 相同的含义不同的语句形式
mov ax, [ebx+5]; 相同的含义不同的语句形式
mov ax, 5[ebx]; 相同的含义不同的语句形式
mov ax, [ebx]+5; 相同的含义不同的语句形式

Hint: mov ax,[ebx]5是错误的用法,当常数或变量在后面时,必须加加号,在前面可加可不加

基址-变址寻址

操作数存放在内存中,操作数的偏移地址为

+×+()基址寄存器的内容 + 变址寄存器的内容\times 比例 + (位移量)

公式
例:

1
mov ebx [ebp+10]+[edi*8]; 将ebp内的内容+10+edi内容乘以8得到内存单元,再去该内存单元取得操作数

隐含寻址

指令中隐含了一个或两个操作数的地址,即操作数在默认的地址中
例:

1
mul bl; 等价于 al * bl -> ax

转移地址寻址

转移地址一般分为两种寻址方式:

  • 直接寻址: 当前指令与目的地指令距离在-128~127字节内时,均采用立即寻址的方式,即将位移量(1B)放在指令中,形成2字节的jmp指令
  • 间接寻址: 当指令与目的地指令距离超过了短转移(-128~127字节)的限制时,位移量则为4B,形成5字节的jmp指令

IO端口寻址

IO端口寻址也分为两种寻址方式:

  • 直接寻址: 端口地址为8位时(可寻址256个端口),指令中的PORT直接由一个8位无符号常数提供,是立即寻址变体
    例:
1
2
in acc, port; acc是al/ax/eax,port为端口地址
out port, acc; 立即寻址操作数不能为目的操作数,但在这里可以,所以为变体
  • 间接寻址: 当端口地址超过255时,地址码为16位(可寻址64K个端口),指令中的端口地址必须由DX指定(不能使用EDX指定),其中端口地址为0~255时也可使用间接寻址
    例:
1
2
3
mov dx, 132; 端口地址为132
in acc, dx; acc是al/ax/eax,从132端口取数据到acc中
out dx, acc; acc是al/ax/eax,将acc中数据输出到132端口

X86指令

学习汇编指令主要从五个角度出发:

  • 指令格式
  • 指令功能
  • 对操作数的要求
  • 指令对操作数的影响
  • 指令对标志位的影响

在下面六大类的每条指令中均会说明该五个角度,并且需要记忆!

数据传送指令

数据传送指令一般对标志位无影响

mov

格式:

1
mov dest, src

功能:
将src的操作数送到dest内
操作数要求:

  1. 两操作数长度必须相同
  2. 存储单元之间不能直接传送(可以用串操作指令实现直接传送)
  3. 段寄存器CS只能作源操作数,段寄存器之间不能直接传送
  4. 在源操作数是立即数时,目标操作数不能是段寄存器
  5. 标志寄存器(EFLAGS或FLAGS)一般不作为操作数在指令中出现

mov操作数要求
对操作数影响:
无影响
对标志位影响:
无影响

movzx/movsx

格式:

1
2
3
4
5
6
movzx reg32, reg8/mem8
movzx reg32, reg16/mem16
movzx reg16, reg8/mem8
movsx reg32, reg8/mem8
movsx reg32, reg16/mem16
movsx reg16, reg8/mem8

功能:
将位数短的操作数传到较长的寄存器,并进行0扩展(movzx)符号扩展(movsx)
操作数要求:

  1. 源操作数位数要小于目的操作数长度
  2. 目的操作数必须为寄存器
    对操作数影响:
    源操作数无影响,目的操作数变为源操作数的0扩展或符号扩展
    对标志位影响:
    无影响

push/pop/pusha/pushd/popa/popd/pushfd/popfd

格式:

1
2
3
4
5
6
7
8
9
10
11
12
push ABCDH; 将16位立即数入栈
push ABCD0000H; 将32位立即数入栈
push ax; 将ax内容入栈
push word ptr[bx]; 将bx内容的存储字单元入栈
pop ax; 将出栈值放入ax
pop word ptr[bx]; 将出栈值放入bx内容的存储字单元
pusha; 将8个16位通用寄存器按AX、CX、DX、BX、SP、BP、SI与DI的顺序入栈
popa; 从栈顶弹出8个字数据分别送入DI、SI、BP、SP、BX、DX、CX与AX
pushd; 将8个32位通用寄存器按EAX、ECX、EDX、EBX、ESP、EBP、ESI与EDI的顺序入栈
popd; 从栈顶弹出8个双字数据分别送入EDI、ESI、EBP、ESP、EBX、EDX、ECX与EAX
pushfd; EFLAGS进栈
popfd; 出栈送到EFLAGS

功能:
push/pop: 将16位数据入栈或出战
pusha/popa: 将8个16位通用寄存器按AX、CX、DX、BX、SP、BP、SI与DI的顺序入栈和从栈顶弹出8个字数据分别送入DI、SI、BP、SP、BX、DX、CX与AX
pushd/popd: 将8个32位通用寄存器按EAX、ECX、EDX、EBX、ESP、EBP、ESI与EDI的顺序入栈和从栈顶弹出8个双字数据分别送入EDI、ESI、EBP、ESP、EBX、EDX、ECX与EAX
pushfd/popfd: 32位标志寄存器EFLAGS进栈/出栈指令
操作数要求:
若为存储器操作数,需要声明为字存储单元(PTR)
对操作数影响:
对标志位影响:
对标志位无影响,但会影响SP内的值
push: SP变为SP-2
pop: SP变为SP+2

xchg

格式:

1
xchg reg/mem, mem/reg

功能:
交换寄存器和内存单元的值
操作数要求:

  1. 必须有一个操作数是寄存器操作数
  2. 不允许使用段寄存器
    对操作数影响:
    源操作数变为目的操作数,目的操作数变为源操作数
    对标志位影响:
    无影响

in/out

格式:

1
2
in acc, port; 将端口数据传送到acc中
out port, acc; 将acc中数据传送到端口中

功能:
对IO端口进行输入和输出
操作数要求:
port在0~255时可以是立即数,也可以是dx,port大于255时必须是dx
acc可以是al、ax或eax,但不能是其他寄存器
对操作数影响:
无影响
对标志位影响:
无影响

lea

格式:

1
lea reg, mem

功能:
将一个存储单元的32位(保护模式)偏移地址取出送目标寄存器
操作数要求:

  1. 源操作数必须为存储单元操作数
  2. 目的操作数必须为16位或32位寄存器操作数
    对操作数影响:
    若目的操作数为32位寄存器操作数,目的操作数变为源操作数的偏移地址,若目的操作数为16位寄存器操作数,目的操作数变为源操作数的偏移地址的低16位
    对标志位影响:
    无影响

lahf/sahf

格式:

1
2
lahf; 将FLAGS的低8位装入AH
sahf; 将AH装入FLAGS的低8位

功能:
lahf: 将FLAGS的低8位装入AH
sahf: 将AH装入FLAGS的低8位
操作数要求:
无要求,因为是隐含地址
对操作数影响:
lahf: AH内容变为FLAGS的低8位
sahf: FLAGS低8位变为AH内容
对标志位影响:
lahf: 无影响
sahf: 标志位低8位涉及到的标志位变为AH内容对应位

算术运算指令

算术运算指令的执行大多对状态标志位会产生影响,对标志位的影响是算术运算指令的应用思路之一。

add/adc/inc

格式:

1
2
3
add oprd1, oprd2; oprd1+oprd2送到oprd1内
adc oprd1, oprd2; oprd1+oprd2+CF送到oprd1内
inc oprd; oprd自增1

功能:
add: 将oprd1与oprd2相加送到oprd1中
adc: 将oprd1与oprd2相加再加上CF标志位送到oprd1中。adc指令常用于多字节数相加,使用前要先将CF清零。
inc: oprd自增1
操作数要求:
add/adc: 与mov指令基本相同
inc:

  1. 不能是立即数
  2. 不能是段寄存器
    对操作数影响:
    add/adc: oprd1变为oprd1+oprd2+(CF),oprd2无影响
    inc: oprd自增1
    对标志位影响:
    add/adc: 对6个状态标志位均产生影响(AF、PF、CF、OF、ZF、SF)
    inc: 不影响CF,其他5个状态标志位仍然受到影响

adc实现多字节数相加示例:

1
2
3
4
5
6
7
8
9
10
11
12
m1 db 20 dup(1); m1是20个字节的大数
m2 db 20 dup(2); m2是20个字节的大数
lea esi m1; 取得m1起始地址
lea edi m2; 取得m2起始地址
mov cl 20; 大数字节数作为循环加法数
clc; 清空CF
next: mov al, [esi]; 将esi的数取到al中,因为adc不能直接用于两个存储器操作数之间
adc [edi], al; 带CF的相加
inc esi; 相加指针移动
inc edi; 相加指针移动
dec cl; 剩余未加字节数减少
jnz next; 判断是否相加完成

sub/sbb/dec

格式:

1
2
3
sub oprd1, oprd2; oprd1-oprd2送到oprd1内
sbb oprd1, oprd2; oprd1-oprd2-CF送到oprd1内
dec oprd; oprd自减1

功能:
sub: 将oprd1与oprd2相减送到oprd1中
sbb: 将oprd1与oprd2相减再减去CF标志位送到oprd1中。
inc: oprd自减1
操作数要求:
sub/sbb: 与mov指令基本相同
dec:

  1. 不能是立即数
  2. 不能是段寄存器
    对操作数影响:
    sub/sbb: oprd1变为oprd1-oprd2-(CF),oprd2无影响
    inc: oprd自增1
    对标志位影响:
    sub/sbb: 对6个状态标志位均产生影响(AF、PF、CF、OF、ZF、SF)
    dec: 不影响CF,其他5个状态标志位仍然受到影响

neg

格式:

1
neg oprd; 0-oprd送oprd内

功能:
用0减去操作数,相当于对该操作数求补,但不是补码。
操作数要求:
必须是寄存器操作数(8位、16位、32位均可)或存储器操作数
对操作数影响:
oprd变为0 - oprd
对标志位影响:
6个标志位(AF、PF、CF、OF、ZF、SF)都会被影响
对CF的影响:

  1. oprd为0时,CF=0
  2. oprd不为0时,CF=1

对OF的影响:
当字节操作数为-128(80H),或字操作数为-32768(8000H)或双字操作数为80000000H时,结果将无变化,但溢出标志OF被置1

cmp

格式:

1
cmp oprd1, oprd; 执行oprd1-oprd2,但不送任何单元

功能:
用于比较两个数的大小,可作为条件转移指令转移的条件
操作数要求:
mov指令基本相同
对操作数影响:
无影响
对标志位影响:
对6个状态标志位均产生影响(AF、PF、CF、OF、ZF、SF)

cmp指令对标志位的影响主要通过CF、ZF、OF、SF四个标志位来判断两个数的大小

  • 无符号数比较:
    1. oprd1 > oprd2: CF = 0 & ZF = 0
    2. oprd1 = oprd2: ZF = 1
    3. oprd1 < oprd2: CF = 1 & ZF = 0
  • 带符号数比较:
    1. oprd1 > oprd2: OF = SF & ZF = 0(为正数时,OF与SF相等表示结果仍为正数,说明oprd1大;为负数时,SF为1时结果为负数,OF为1表示结果溢出,oprd1大,SF为0时结果为正数,OF为0表示不溢出,说明oprd2的绝对值大,负数小)
    2. oprd1 = oprd2: ZF = 1
    3. oprd1 < oprd2: OF \neq SF & ZF = 0(与oprd1 > oprd2结论相反,除了ZF = 0)

也可通过直接的跳转指令实现根据两数大小的跳转:

  1. 无符号数比较跳转:
    • ja/jae: ja为当oprd1>oprd2时跳转,jae为当oprd1\geqoprd2时跳转
    • jb/jbe: jb为当oprd2>oprd1时跳转,jbe为当oprd2\geqoprd1时跳转
  2. 带符号数比较跳转:
    • jg/jge: jg为当oprd1>oprd2时跳转,jge为当oprd1\geqoprd2时跳转
    • jl/jle: jl为当oprd2>oprd1时跳转,jle为当oprd2\geqoprd1时跳转

cmp实现20个无符号数寻找最大值示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
max db 0; 定义存储最大值变量单元
buff db 5 dup(1, 2, 3, 4); 20个无符号数
lea edi, max; 取得max的偏移地址,便于后面存储最大值
lea esi, buff; 取得20个数的起始地址
mov cl, 20-1; 20个数只需要比较19次
mov al, [esi]; 取出第一个数到寄存器中
next: inc esi; 循环的开始,需要比较指针自增
cmp al, [esi]; 比较已取出的数与下一个数的大小
jnc goon; 如果al比较大就跳转到goon里面直接进行比较指针的移动
mov al, [esi]; al比较小,更新al
goon: dec cl; cl减1,比较完成
jnz next; 重新比较流程,如果比较次数完成则直接将al内的最大值放入max中
mov [edi], al; 将al内的最大值放入max中

mul/imul

格式:

1
2
3
mul oprd; 无符号数的乘法,使用隐含寻址al、ax、eax,将隐含寻址的值*oprd送到ax、dx:ax、edx:eax中
imul oprd; 与mul相同,但操作数被视为带符号数
imul dest, src; src乘以dest送到dest中

功能:
mul/imul: 将隐含寻址的值乘以oprd倍送到扩展寄存器中(结果为64位时,由edx:eax构成64位寄存器)
imul: 将src×\timesdest的结果送到dest中,若结果超过目的寄存器位数则截断高位
操作数要求:
mul/imul: 隐含寻址时,操作数只能是寄存器操作数或存储器操作数
imul: 可以是寄存器操作数或存储器操作数或比目的操作数位数少的立即数
对操作数影响:
mul/imul: 对oprd无影响,隐含寻址操作数变为乘积的低位
imul: dest操作数变为src*dest的结果的低位
imul:
对标志位影响:
mul: 只对CF和OF产生影响,若高位寄存器(即AH、DX、EDX)为全0则CF=OF=0,否则CF=OF=1
imul: 只对CF和OF产生影响,隐含寻址时,若高位寄存器(即AH、DX、EDX)全为低位的符号位扩展则CF=OF=0,否则CF=OF=1
imul: 只对CF和OF产生影响,如果存放结果的目的寄存器中丢弃了乘积高位的有效数值则CF=OF=1,否则CF=OF=0

div/idiv

1
2
3
4
5
6
div reg/mem8
div reg/mem16
div reg/mem32
idiv reg/mem8
idiv reg/mem16
idiv reg/mem32

功能:
将隐含寻址的目的操作数除以源操作数的倍数,结果放入隐含寻址的操作数中
操作数要求:
指令要求被除数是除数的双倍字长,因此除法指令常与扩展指令CBW、CWD、CDQ配合使用。
div操作数要求
对操作数影响:
源操作数无影响,目的操作数按上图所示变化
对标志位影响:
无影响

cbw/cwd/cdq

1
2
3
cbw; 隐含寻址,将AL的符号位扩展到AH
cwd; 隐含寻址,将AX的符号位扩展到DX
cdq; 隐含寻址,将EAX的符号位扩展到EDX

功能:
扩展源操作数的符号位到指定位置
操作数要求:
必须在隐含寻址的寄存器内
对操作数影响:
源操作数无影响,目的操作数变为源操作数的符号位扩展
对标志位影响:
无影响

BCD码校正指令(daa/aaa/das/aas/aam/aad)

不要求掌握,了解即可。
在X86系统中,BCD码可以有两种表示方式:

  • 压缩型: 一个字节表示两个BCD码,即两位十进制数。每4位表示1个十进制数
  • 非压缩型: 一个字节的低四位表示一个BCD码,而高四位对所表示的十进制数没有影响,常为0000或0011。

BCD码处理指令: 先用二进制数的加、减、乘、除运算指令对BCD码运算,再用BCD码校正指令对结果校正。
BCD码校正指令

位操作指令

位操作大多数时候也是一种算术运算,如乘法在一定程度上可以视为左移,除法在一定程度上可以用右移操作今天代替。同时位操作往往也会导致标志位的变化,同时某些特殊的位操作目的是对特定的标志位操作

and

格式:

1
and oprd1, oprd2; oprd1和oprd2按位&,结果送oprd1

功能:
实现两操作数按位相与的运算,使目标操作数的某些位不变,某些位清零
操作数要求:
mov指令相同
对操作数影响:
源操作数无影响,目的操作数变为按位与的结果
对标志位影响:
CF=OF=0,其余状态位根据结果产生

判断某些位是否为0:

1
2
3
4
5
data db 1; 定义测试变量
lea esi, data; 取得测试变量偏移地址
mov al, 01H; 构造测试位为1,其余位为0的数据
and al, [esi]; 测试变量与测试数据按位与
jz bit1; 如果结果全0说明测试位为0

将CF和OF清零:

1
and ax, ax; 自身按位与不改变操作数,且能将CF和OF清零

or

格式:

1
or oprd1, oprd2; oprd1和oprd2按位|,结果送oprd1

功能:
实现两操作数按位相或的运算,使目标操作数的某些位不变,某些位置1
操作数要求:
mov指令相同
对操作数影响:
源操作数无影响,目的操作数变为按位或的结果
对标志位影响:
CF=OF=0,其余状态位根据结果产生

将CF和OF清零:

1
and ax, ax; 自身按位或不改变操作数,且能将CF和OF清零

not

格式:

1
not oprd; 将操作数按位取反再送回原地址

功能:
将操作数按位取反
操作数要求:

  1. 不能为立即数
  2. 操作数为存储器操作数时需要说明数据类型(db、dw、dd)
    对操作数影响:
    操作数变为按位取反的结果
    对标志位影响:
    无影响

xor

格式:

1
xor oprd1, oprd2; 两操作数按位相异或,结果送目标地址

功能:
两操作数按位相异或,结果送目标地址,xor有个很重要的属性: 自身相异或结果为0,经常用以判断数据是否为预期数据
操作数要求:
mov指令相同
对操作数影响:
源操作数无影响,目的操作数变为两操作数按位相异或结果
对标志位影响:
CF=OF=0,其余状态位根据结果产生

属性应用:
与test例相同,需要判断bit1、bit3、bit5是否为均1,用xor指令十分优雅但会改变数据

1
2
3
4
data db 214; 定义数据
mov al, data; 拿到数据
and al, 2AH; 去除其他位的影响
xor al, 2AH; 如果为数据bit1、bit3、bit5均为1,则与2AH(自身)异或结果为0,只需要判断ZF是否为1即可得知al的几位数据

还有一种在不改变数据的情况下能一次性比较多位的方式: cmp指令

1
2
3
4
5
6
7
8
9
data db 214; 定义数据
mov al, data; 拿到数据
and al, 2AH; 去除其他位的影响
cmp al, 2AH; cmp指令通过al-2AH的方式来判断ZF,并且结果并不会送回到al中,因此不改变数据同样能够得到ZF标志位来进行判断

#### test
格式:
``` x86asm
test oprd1, oprd2; 执行与运算,运算的结果影响标志位,但不送回目标地址

功能:
判断两操作数按位与结果对标志位的影响
操作数要求:
mov指令相同
对操作数影响:
无影响
对标志位影响:
CF=OF=0,其余状态位根据结果产生

可跟and指令一样判断某些位数据,并且不影响测试数据,因此可用来判断多位且不影响数据

1
2
3
4
5
data db 214; 定义数据
mov al, data; 拿到数据
test al02H; 判断bit1
test al, 08H; 判断bit3
test al, 20H; 判断bit5

sal/shl

格式:

1
2
sal oprd1, oprd2; 将oprd1左移oprd2位
shl oprd1, oprd2; 将oprd1左移oprd2位

功能:
sal与shl在机器指令执行时为同一条指令,将oprd1左移oprd2位,区别在于sal将操作数视为无符号数,shl将操作数视为带符号数
操作数要求:
oprd2必须是8位立即数或CL寄存器内容
对操作数影响:
oprd1变为左移后的结果,oprd2无影响
对标志位影响:
影响标志位OF、SF、ZF、PF、CF

左移在二进制操作中可视为特殊乘法: 左移n位oprd1×2n\Leftrightarrow oprd1 \times 2^n

sar/shr

格式:

1
2
sar oprd1, oprd2; 将oprd1右移oprd2位
shr oprd1, oprd2; 将oprd1右移oprd2位

功能:
sar与shr并不相同,sar高位补零,shr高位补符号位,将oprd1右移oprd2位,区别在于sar将操作数视为无符号数,shr将操作数视为带符号数
操作数要求:
oprd2必须是8位立即数或CL寄存器内容
对操作数影响:
oprd1变为右移后的结果,oprd2无影响
对标志位影响:
影响标志位OF、SF、ZF、PF、CF

右移在二进制操作中可视为特殊除法: 右移n位oprd1÷2n\Leftrightarrow oprd1 \div 2^n

rol/rcl

格式:

1
2
rol oprd1, oprd2; 不带CF的循环左移位oprd2位
rcl oprd1, oprd2; 带CF的循环移左位oprd2位

功能:
循环左移oprd2位,并将结果放入oprd1中
操作数要求:
sal/shl相同
对操作数影响:
oprd1变为循环移位后的结果,oprd2无影响
对标志位影响:
影响标志位CF(rol无影响)、OF(若移位位数为1次,且移位前后目的操作数的最高位发生变化,那么OF置1,否则OF清零。若移位位数大于1,那么OF不确定)。其他标志位无影响

ror/rcr

格式:

1
2
ror oprd1, oprd2; 不带CF的循环右移位oprd2位
rcr oprd1, oprd2; 带CF的循环移右位oprd2位

功能:
循环右移oprd2位,并将结果放入oprd1中
操作数要求:
sal/shl相同
对操作数影响:
oprd1变为循环移位后的结果,oprd2无影响
对标志位影响:
影响标志位CF(rol无影响)、OF(若移位位数为1次,且移位前后目的操作数的最高位发生变化,那么OF置1,否则OF清零。若移位位数大于1,那么OF不确定)。其他标志位无影响

通过带CF的循环移位可以实现多字节单元数据联合移位(如adc大数加法一般)

1
2
3
4
M dw 3 dup(1); 定义变量
sal M, 1; 低字节移位到CF
rcl M+2, 1; 带CF循环移位
rcl M+4, 1; 带CF循环移位

多字节单元数据联合移位

shld/shrd

格式:

1
2
shld dest, src, count; 将目的操作数dest向左移动指定位数,移动形成的空位由源操作数source的高位填充,指令执行后source保持不变
shrd dest, src, count; 将目的操作数dest向右移动指定位数,移动形成的空位由源操作数source的低位填充,指令执行后source保持不变

功能:
双精度移位操作,移位时以一定数据进行填充空位而非固定0或1
操作数要求:
sal/shl相同
对操作数影响:
src无影响,dest变为移位后结果
对标志位影响:
会影响SF、ZF、AF、PF、CF

串操作指令

串操作是针对数据块或字符串的操作,可实现存储器到存储器的数据传送,默认源串地址由[ESI]提供,目的串地址由[EDI]提供。
地址修改方向由DF标志位决定,DF=0时为增地址方向,DF=1时为减地址方向。

重复前缀

串操作指令前面可加上自动重复前缀,实现自动重复执行串操作,重复执行次数必须由ECX指定,每次执行ECX自减1。
共有5条重复前缀:

  • rep: 无其他条件重复,即ECX \neq 0时重复
  • repe: 相等重复,即ZF = 1 & ECX \neq 0时重复
  • repz: 为零重复,即ZF = 1 & ECX \neq 0时重复
  • repne: 不相等重复,即ZF = 0 & ECX \neq 0时重复
  • repnz: 不为零重复,即ZF = 0 & ECX \neq 0时重复

movs/movsb/movsw/movsd

格式:

1
2
3
4
movs [edi], [esi]; 将esi内容的存储器单元内容送到edi内容的存储器单元中
movsb; 将esi内容的存储器字节单元内容送到edi内容的存储器字节单元中
movsw; 将esi内容的存储器字单元内容送到edi内容的存储器字单元中
movsd; 将esi内容的存储器双字单元内容送到edi内容的存储器双字单元中

功能:
实现存储器单元的直接传送
操作数要求:
源操作数必须是esi寄存器间接寻址单元,目的操作数必须是edi寄存器间接寻址单元,movs必须指明操作数结构
对操作数影响:
目的操作数会变为源操作数,确定串操作方向后添加重复前缀会自动移动地址
对标志位影响:

cmps/cmpsb/cmpsw/cmpsd

格式:

1
2
3
4
cmps [esi], [edi]; 执行[esi]-[edi],结果影响标志位但不送任何地址
cmpsb; 计算[esi]字节单元 - [edi]字节单元,结果影响标志位但不送任何地址
cmpsw; 计算[esi]字单元 - [edi]字单元,结果影响标志位但不送任何地址
cmpsd; 计算[esi]双字单元 - [edi]双字单元,结果影响标志位但不送任何地址

功能:
实现存储器单元的直接比较并影响标志位
操作数要求:
源操作数必须是esi寄存器间接寻址单元,目的操作数必须是edi寄存器间接寻址单元,cmps必须指明操作数结构
对操作数影响:
无影响,确定串操作方向后添加重复前缀会自动移动地址
对标志位影响:
cmp相同

cmps指令常与条件重复前缀共同使用

1
2
3
4
5
6
7
mem1 db 200 dup(?); 定义mem1
mem1 db 200 dup(?); 定义mem2
lea esi, mem1; 取得起始地址一
lea edi, mem2; 取得起始地址二
mov ecx, 200; 比较区间长度
cld; 设置为地址增方向
repe cmpsb; 重复寻找,直到第一个不同数据

scas/scasb/scasw/scasd

格式:

1
2
3
4
scas edi; 执行EAX、AX、AL - [edi]内容,结果影响标志位但不送任何地址
scasb; 执行AL - [edi]内容,结果影响标志位但不送任何地址
scasw; 执行AX - [edi]内容,结果影响标志位但不送任何地址
scasd; 执行EAX - [edi]内容,结果影响标志位但不送任何地址

功能:
从edi串数据中扫描AL、AX、EAX寄存器内容数据
操作数要求:
必须是edi存储器操作数,scas必须指明操作数结构
对操作数影响:
无影响,确定串操作方向后添加重复前缀会自动移动地址
对标志位影响:
sub相同

scas扫描找出对应字符所在串位置

1
2
3
4
5
6
7
buff db 'ABCDEFGHIJK'; 定义字符串
len $-buff; 微指令求字符串长度
lea edi buff; 取得字符串起始地址
mov al, 'H'; 将寻找字符放入al
mov ecx, len; 重复前缀次数
cld; 设置为地址增方向
repne scasb; 重复扫描字符

lods/lodsb/lodsw/lodsd

格式:

1
2
3
4
lods [esi]; 将[esi]内容装入AL、AX、EAX
lodsb; 将[esi]内容装入AL
lodsw; 将[esi]内容装入AX
lodsd; 将[esi]内容装入EAX

功能:
将存储器操作数装入累加器
操作数要求:
必须是esi寄存器间接寻址存储器操作数,lods必须指明操作数结构
对操作数影响:
累加器内容变为[esi]
对标志位影响:
无影响

lods一般不需要重复前缀,因为累加器数据会被覆盖

stos/stosb/stosw/stosd

格式:

1
2
3
4
stos [edi]; 将AL、AX、EAX内容送入[edi]
stosb; 将AL内容送入[edi]
stosw; 将AX内容送入[edi]
stosd; 将EAX内容送入[edi]

功能:
将累加器内容送入存储器操作数
操作数要求:
必须是edi寄存器间接寻址存储器操作数,stos必须指明操作数结构
对操作数影响:
存储器操作数变为累加器内容,确定串操作方向后添加重复前缀会自动移动地址
对标志位影响:
无影响

stos常用于将内存某个区域置同样的值

1
2
3
4
5
6
buff db 20 dup(?)
mov al, F4H; 需存储值
lea edi, buff; 取得偏移地址
mov ecx, 20; 区域长度
cld; 设置为地址增方向
rep stosb; 重复存储

程序控制指令

程序控制指令一般没有操作数或只有单个操作数,且一般对标志位没有影响。其主要通过标志位控制程序执行的方向。

jmp

格式:

1
jmp oprd

功能:
跳转到距离jmp指令下一条指令oprd字节的指令。如转移地址寻址中说的,有两个寻址方式,当采用直接寻址的方式时,称为短距离转移,jmp指令仅2字节长,当采用间接寻址方式时可按转移地址是否仍在本代码段分为近转移远转移,jmp指令长为5字节
操作数要求:
操作数可以为标号,由汇编器进行翻译为8位的位移量或32位的位移量,也可为寄存器间接寻址的存储器单元
对操作数影响:
无影响
对标志位影响:
无影响

jc/jnc/jo/jno/jz/jnz/jp/jnp/jcxz/jcxnz

格式:

1
2
3
4
5
6
7
8
9
10
jc label; CF=1时跳转
jnc label; CF=0时跳转
jo label; OF=1时跳转
jno label; OF=0时跳转
jz label; ZF=1时跳转
jnz label; ZF=0时跳转
jp label; PF=1时跳转
jnp label; PF=0时跳转
jcxz label; CX或ECX=0时跳转
jcxnz label; CX或ECX不为0时跳转

功能:
根据一个标志位或CX、ECX决定是否跳转
操作数要求:
无要求
对操作数影响:
无影响
对标志位影响:
无影响

ja/jae/jb/jbe/jg/jge/jl/jle

格式:

1
2
3
4
5
6
7
8
ja label; 根据CF和OF状态决定是否跳转
jae label; 根据CF和OF状态决定是否跳转
jb label; 根据CF和OF状态决定是否跳转
jbe label; 根据CF和OF状态决定是否跳转
jg label; 根据OF和SF状态决定是否跳转
jge label; 根据OF和SF状态决定是否跳转
jl label; 根据OF和SF状态决定是否跳转
jle label; 根据OF和SF状态决定是否跳转

功能:
cmp
操作数要求:
无要求
对操作数影响:
无影响
对标志位影响:
无影响

loop/loopz/loopnz

格式:

1
2
3
loop label; ECX不为零
loopz(loope) label; ECX为不为零且ZF=1,则跳转label
loopnz(loopne) label; ECX不为零且ZF=0,则跳转label

功能:
根据ECX内容和ZF决定是否跳转
操作数要求:
转移范围为当前EIP内容的-128~+127内
对操作数影响:
无要求
对标志位影响:
无影响

call

格式:

1
call subprocess; 调用子过程

功能:
调用子过程,等价于以下代码:

1
2
push eip; 将断点地址压栈
mov eip subprocess; 将子过程开始地址放入EIP

操作数要求:
subprocess必须是子过程的开始地址,汇编器会代替程序员进行这件事
对操作数影响:
无影响
对标志位影响:
无影响

ret

格式:

1
2
ret; 从堆栈中弹出断点地址,返回原程序
ret n; 从堆栈中n个数据,其中第n个是断点地址,返回原程序

功能:
在子程序中从堆栈中弹出断点,以返回原程序,其功能等价于以下代码:

1
2
3
4
5
6
7
8
9
10
ret =>
pop eip; 从堆栈中弹出断点地址送到EIP中
ret n =>
pop oprd1; 弹出第一个参数
pop oprd2; 弹出第二个参数
·
·
·
pop oprdn-1; 弹出第n-1个参数
pop eip; 弹出断点地址送到EIP中

操作数要求:
无要求
对操作数影响:
无影响
对标志位影响:
无影响

int/into/iret

格式:

1
2
3
int n; 程序发出中断类型号为n的软中断请求
into; 程序发出溢出中断请求
iret; 中断服务程序发出,用来恢复断点和标志寄存器内容

功能:
int: 给予程序发出软中断请求的能力
into: 检测是否溢出,如果溢出(OF=1)即等价于int 4发出一个类型号为4的中断请求,如果未溢出则不做任何操作
iret: 中断服务程序结束的固定流程指令(恢复现场、开中断)
操作数要求:
int: 操作数为立即数,且范围必须在0~255(X86下中断向量表只有256个表项)
对操作数影响:
无影响
对标志位影响:
无影响

处理器控制指令

处理器一般通过标志位来控制指令的执行方式,因此控制指令一般可以直接更改标志位而无需运算来实现(如通过and、or实现CF和OF清零),或直接通过指令来实现处理器工作情况的控制,如暂停、让出总线使用权等。

clc/stc/cmc

格式:

1
2
3
clc; CF复位
stc; CF置位
cmc; CF取反

功能:
实现对CF的直接操作
操作数要求:
无要求
对操作数影响:
无影响
对标志位影响:
更改CF值

cld/std

格式:

1
2
cld; DF复位
std; DF置位

功能:
实现对DF的直接操作,以进行对串操作的方向控制
操作数要求:
无要求
对操作数影响:
无影响
对标志位影响:
更改CF值

cli/sti

格式:

1
2
cli; IF复位
stu; IF置位

功能:
实现对IF的直接操作,用以控制处理器的中断屏蔽状态,一般在中断处理时使用
操作数要求:
无要求
对操作数影响:
无影响
对标志位影响:
更改IF值

nop

格式:

1
nop; 不执行任何操作,使处理器空闲一个指令周期(3个时钟周期)

功能:
使处理器空闲一个指令周期(3个时钟周期)
操作数要求:
无要求
对操作数影响:
无影响
对标志位影响:
无影响

hlt

格式:

1
2
hlt; 使 CPU 处于暂停状态,不执行任何操作,等待复位信号或下一次外部中断的到

功能:
阻塞CPU,等待中断请求或多机系统的同步
操作数要求:
无要求
对操作数影响:
无影响
对标志位影响:
无影响

wait

格式:

1
2
wait; 使 CPU 处于等待状态,不执行任何操作。 CPU 将等待外部中断发生,如果有中
断发生,则完成中断任务后仍返回 WAIT 指令继续等待。

功能:
使CPU等待,以使得CPU与协处理器或外部设备同步工作
操作数要求:
无要求
对操作数影响:
无影响
对标志位影响:
无影响

esc

格式:

1
2
esc oprd, src; CPU让出总线使得src内容可以到数据总线上,从而将存储器中的指
令或数据传送给其他处理器

功能:
CPU让出总线,使得协处理器能够使用总线进行数据传送
操作数要求:
无要求
对操作数影响:
无影响
对标志位影响:
无影响

lock前缀

格式:

1
lock op; 使得op指令在执行期间封锁总线(独占总线)

功能:
保证指令独占总线,防止协处理器破坏数据
操作数要求:
无要求
对操作数影响:
无要求
对标志位影响:
无要求

代码参考

代码参考


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!