NOP
表示
No Operation
,机器码为
0x90
,没有操作数,执行这条指令时
CPU
什么事都不干。
PUSH
PUSH
指令将数据压入
栈
中。
指令格式为
push x
。
x
可取
imm8
,
imm16
,
imm32
,
r/m16
,
r/m32
,
r/m64
。
栈指针寄存器
ESP(RSP)
自动递减。
POP
POP
指令从栈中弹数据。
指令格式为
pop x
。
x
可取
r/m16, r/m32, r/m64
。
栈指针寄存器
ESP(RSP)
自动递增。
MOV
MOV
指令将数据从源操作数移动到目的操作数。
指令格式为
mov x1, x2
。意为从
x2
移动数据到
x1
。
x1, x2
可以是:
寄存器到寄存器
内存到寄存器,寄存器到内存
立即数到寄存器,立即数到内存
不能从内存直接到内存。
LEA
LEA
指令用于载入有效地址。
指令格式为
lea x1, x2
。
x1
可以是
r16/32/64
,
x2
是内存地址,常用
[]
语法形式,意为引用求值。
常用于指针运算,有时用于数值计算。
ADD
ADD
指令计算加法操作。
指令格式为
add x1, x2
。
x1
,
x2
可以是
r/m16
,
r/m32
,
r/m64
,
x2
还可以是立即数,但二者不能同时是内存操作数。
指令的计算结果将影响
eflflags
寄存器,修改
OF, SF, ZF, AF, PF, CF
标志位。
SUB
SUB
指令计算减法操作。
指令格式为
sub x1, x2
。
x1
,
x2
可以是
r/m16
,
r/m32
,
r/m64
,
x2
还可以是立即数,但二者不能同时是内存操作数。
指令的计算结果将影响
eflflags
寄存器,修改
OF, SF, ZF, AF, PF, CF
标志位。
IML/MUL
IMUL
指令用于实现有符号数的乘法运算。
三种指令格式:
imul r/m32 ; edx:eax = eax * r/m32
imul reg, r/m32 ; reg = reg * r/m32
imul reg, r/m32, imm ; reg = r/m32 * imm
MUL
指令是无符号乘法。
IDIV/DIV
DIV
指令用于实现无符号数的除法运算。
两种指令格式:
无符号除法,
div ax, r/m8 ; ax
除以
r/m8
,
al
是商,
ah
是余数
无符号除法,
div eax, r/m32 ; edx:eax
除以
r/m32
,
eax
是商,
edx
是余数
若被除数是
DWORD
,在指令执行前
edx
被置为
0
。
若除数是
0
,则抛出
除零异常
。
AND
AND
指令实现操作数的逻辑与运算。
指令格式为
and x1, x2
。
x1, x2
可以是
r/m16, r/m32, r/m64, x2
还可以是立即数,但二者不能同时是内存操作数。
OR
OR
指令实现操作数的逻辑或运算。
指令格式为
or x1, x2
。
x1, x2
可以是
r/m16, r/m32, r/m64, x2
还可以是立即数,但二者不能同时是内存操作数。
XOR
XOR
指令实现操作数的异或运算。
指令格式为
xor x1, x2
。
x1, x2
可以是
r/m16, r/m32, r/m64, x2
还可以是立即数,但二者不能同时是内存操作数。
注:
XOR
常用于清零运算,如
xor eax, eax
,效率高。
NOT
NOT
指令实现操作数的逻辑非运算。
指令格式为
not x
。
x
可以取
r/m16, r/m32, r/m64
。
SHL
SHL
指令用于实现操作数的逻辑左移运算。
指令格式为
shl x1, x2
:
x1
可以取
r/m16, r/m32, r/m64
x2
可以是
cl
或者占用
1
字节的立即数,表示左移长度
注:左移运算是乘
2
的高效实现方法,被用于乘法性能优化。
SHR
SHR
指令用于实现操作数的逻辑右移运算。
指令格式为
shr x1, x2
:
x1
可以取
r/m16, r/m32, r/m64
x2
可以是
cl
或者占用
1
字节的立即数,表示右移长度
注:右移运算是除以
2
的高效实现方法,被用于除法性能优化。
JMP
JMP
指令改变
EIP(RIP)
的值到目标地址,实现控制流跳转。
指令格式为
jmp x
。
x
可取
imm, r/m16, r/m32, r/m64
等。
jmp
目标地址
x
的主要形式:
短跳方式,使用相对地址
近跳方式,使用相对地址
远跳方式(段间转移)
绝对地址,使用直接地址
绝对地址,使用间接地址
Jcc
Jcc
指令是一系列指令的集合,该指令在指定条件满足时将控制流转向目标地址。
指令格式为
jcc x
。
启动设置:
比较操作设置
eflflags
寄存器的标志位
如
JNZ
指令,当
eflflags
的
ZF
未被设置(
ZF=0
)时,指令满足跳转条件,执行控制转移到目标地址
x
几个常见
jcc
指令的判断条件:
1.
相对于
jmp
指令的下一条指令,
1
字节(
-128 ~ 127
)范围
例如,
0x00401021
处指令
“jmp 0x00401028”
为短跳方式,实际上,内存中并没有
0x00401023
这
一字符串或常量,而是前跳
5
个字节
2.
某些反汇编器将其标记为
jmp short
相对于
jmp
指令的下一条指令,相对地址
4
字节范围
指令中硬编码方式的内存地址
指令中寄存器或内存间接访问的地址
jz/je
:
if ZF == 1
jnz/jne: if ZF == 0
jle/jng: if ZF == 1 or SF != OF
jge/jnl: if SF == OF
jbe: if CF == 1 or ZF == 1
jb: if CF == 1
这些条件通过查看
eflflags
寄存器的相应位进行判断。常用的设置
eflflags
标志位的指令有
cmp, test
,
运算指令等。
CMP
CMP
指令用于两个操作数的大小比较。
指令格式为
cmp x1, x2
。
cmp
指令通过将
x1
减去
x2
的方式实现比较,根据减法结果设置
eflflags
的相应标志位,且将减法结果
丢弃。
cmp <-> sub
:
以相同的方式进行减法操作,以同样的方式设置
eflflags
寄存器
但
sub
指令将计算结果存入
x1
,而
cmp
指令不保存计算结果
修改的
eflflags
寄存器标志位有
CF, OF, SF, ZF, AF, PF
。
TEST
TEST
指令用于两个操作数的逻辑比较。
指令格式为
test x1, x2
。
test
指令通过计算两个操作数的
逻辑与
**
(&)**
位运算实现比较操作,根据与操作的结果设置
eflflags
的
相应标志位,且将与操作计算结果丢弃
修改的
eflflags
寄存器标志位有
SF, ZF, PF
。
CALL
CALL
指令将程序控制流转向一个子函数。
指令格式为
call x
,x 可取
r/m16, r/m32, r/m64, ptr16:16, ptr16:32
。
启动设置:参数传递,使用
函数调用约定
。
具体过程:
1.
首先,将下一条指令的地址压入栈中
2.
然后,改变
EIP(RIP)
的值为
x
3. x
可以是绝对地址,也可以是相对于
CALL
指令尾的相对地址
LEAVE
LEAVE
指令用于子函数退出时清理栈的操作,常与
RET
指令配套使用。
实际操作为:
设置
ESP(RSP)
为
EBP(RBP)
弹出栈顶数据到
EBP(RBP)
RET
RET
指令将程序控制流从子函数返回到调用函数。
两种指令格式:
ret
ret x