概述
文章目录
- In this article - 此文
- Instruction Notation - 指令符号
- Memory, Data Transfer, and Data Conversion - 内存,数据传输,数据转换
- Effective Address - 有效的地址
- Data Transfer - 数据传输
- Stack Manipulation - 栈操作
- Data Conversion - 数据转换
- Arithmetic and Bit Manipulation - 算术与位操作
- Arithmetic - 算术
- Binary-coded Decimal - 二进制编码的十进制
- Bits - Bit位
- Control Flow - 控制流
- String Manipulation - 字符串操作
- Flags - 标记位
- Interlocked Instructions - 原子锁指令
- Miscellaneous - 杂项
- Idioms - 常用的
系列目录: Processor Architecture - 处理器体系架构
原文: x86 Instructions
In this article - 此文
使用*(星号)标记上的都是非常重要的指令,没标记上的都不是关键指令。
在x86 处理,指令是变长的,所以练习逆向的反汇编看到的指令大小也是与此相应变长的。此文的后面blablabla的一堆无用废话真特么懒得翻译,这就是西方的文章特色吗?讲的是断点调试反汇编的位置要选择好而已。因为有些代码优化后,或是有些代码汇编后对应的汇编指令是不指一条的。或是有些代码因为预测、优化等删除了部分源码对应的指令,所以断点是没有反应的。但是原文写的太特么难看,我也不想看,就用自己的话来描述。
Instruction Notation - 指令符号
一般的指令符号将目标寄存器放左边,而源寄存器放右边。然而,这个规则有些例外。
算术指令通常有两个寄存器,由源与目标寄存器组合而成。当对两个寄存器(源与目标)算术运算后,结果会写到目标寄存器。(这里的翻译我改了一下,因为原文写的真特么辣鸡,真的很讨厌英文的辣鸡表达方式,但是太多技术起源都是用英文资料的,不然我才不去翻译。这段描述可以这么理解,如:add
算术指令,有dst
, src
两个寄存器,将dst
与src
相加,并将结果设置到dst
,即可:add dst, src;
就是将dst = dst + src
或是dst+=src
的意思)
一些指令有16位与32位版本,但这里只列出32位版本的。这里也不会列出 floating-point 浮点指令,privileged 特权指令,和仅仅用于段模型的指令(Microsoft Win32 不会使用)。
为了节省空间,许多指令都使用合并的形式,如下列例子:
是否重要 | 指令 | 参数 | 意义 |
---|---|---|---|
* | MOV | r1,r/m/#n | r1=r/m/#n |
第一个参数必须是一个寄存器,但第二个可以是寄存器或是内存地址,或是一个立即数。
(译者jave.lin:上面的r1
就是必须为寄存器
,r/m/#n
对应寄存器/内存地址/立即数
,立即数的时候前面需要价格#
井号,立即数的意思就是一个写死的数值,如#999
)
为了节省更多的空间,指令也可以如下表示:
是否重要 | 指令 | 参数 | 意义 |
---|---|---|---|
* | MOV | r1/m,r/m/#n | r1/m=r/m/#n |
译者jave.lin:目标值可以是一个寄存器,也可以是一个内存地址
意思是第一个参数可以是一个寄存器,也可以是一个内存地址,而第二个可以是一个寄存器,内存地址,或是立即数。
另外说明一下,dst, src 不能两边都是内存地址。
更进一步的说,带有位宽(8,16,32)的可以附加到源src或是目标dst表示参数必须的位宽大小。例如,r8意思是8bit位的寄存器。
Memory, Data Transfer, and Data Conversion - 内存,数据传输,数据转换
内存与数据传输指令不影响标记。
Effective Address - 有效的地址
是否重要 | 指令 | 参数 | 意义 |
---|---|---|---|
* | LEA | r,m | 载入有效的地址(r = address of m,r = m的地址 |
例如,LEA eax, [esi+4] 意思 eax = esi + 4。该指令常用语执行算术。
Data Transfer - 数据传输
是否重要 | 指令 | 参数 | 意义 |
---|---|---|---|
MOV | r1/m,r2/m/#n | r1/m=r2/m/#n | |
MOV | r1/m,r/m/#n | 符号扩展或 | |
* | MOVZX | r,r/m | 零扩展 |
MOVSX和MOVZX是mov指令的特殊版本,它们执行从源到目标的符号扩展或零扩展。这是仅有的允许源与目标是不同大小的指令(实际上,他们也必须是不同的大小)。
Stack Manipulation - 栈操作
栈指针是存放在 esp 寄存器。esp 的值指向栈顶(最近的push,最早的pop的位置),越早存于栈中的元素它的地址将越大(栈的地址增长是负的,几:push会减少esp,pop会增加esp)
是否重要 | 指令 | 参数 | 意义 |
---|---|---|---|
PUSH | r/m/#n | 数值压栈 | |
POP | r/m | 数值出栈 | |
PUSHFD | 标记压栈 | ||
POPFD | 标记出栈 | ||
PUSHAD | 所有整型压栈 | ||
POPAD | 所有整型出栈 | ||
ENTER | #n,#n | 构建栈帧 | |
* | LEAVE | 清理栈帧 |
C/C++编译器不会使用enter指令。(enter指令用于如Algol或Pascal程序语言的嵌套调用。)
leave 指令等价于:
mov esp, ebp
pop ebp
Data Conversion - 数据转换
指令 | 意义 |
---|---|
CBW | 转换 byte (al) 为 word (ax)。 |
CWD | 转换 word (ax) 为 dword (dx:ax) |
CWDE | 转换 word (ax) 为 dword (eax) |
CDQ | 转换 dword (eax) 为 qword (edx:eax) |
CBW例子:al = 10000000, ax = 11111111 10000000, if al = 01111111, ax = 00000000 01111111,就是将al的最高位设置到ax的高位中
Arithmetic and Bit Manipulation - 算术与位操作
所有算术与位操作指令都会修改flags标记。
Arithmetic - 算术
是否重要 | 指令 | 参数 | 意义 |
---|---|---|---|
ADD | r1/m, r2/m/#n | r1/m += r2/m/#n | |
ADC | r1/m, r2/m/#n | r1/m += r2/m/#n + 进位 | |
SUB | r1/m, r2/m/#n | r1/m -= r2/m/#n | |
SBB | r1/m, r2/m/#n | r1/m -= r2/m/#n + 进位 | |
NEG | r1/m | r1/m = -r1/m | |
INC | r/m | r/m +=1 | |
DEC | r/m | r/m -=1 | |
CMP | r1/m, r2/m/#n | 计算r1/m - r2/m/#n |
cmp 指令计算减法与根据减法结果设置 flags 标记,但把结果抛到外面去了。下面通常是配合 jump 指令来测试减法结果来执行跳转。
是否重要 | 指令 | 参数 | 意义 |
---|---|---|---|
MUL | r/m8 | ax = al * r/m8 | |
MUL | r/m16 | dx:ax = ax * r/m16 | |
MUL | r/32 | edx:eax = eax * r/m32 | |
IMUL | r/m8 | ax = al * r/m8 | |
IMUL | r/m16 | dx:ax = ax * r/m16 | |
IMUL | r/m32 | edx:eax = eax * r/m32 | |
IMUL | r1, r2/m | r1 *= r2/m | |
IMUL | r1, r2/m, #n | r1 = r2/m * #n |
无符号与有符号的操作。在操作过后flags标记的状态是不确定的。
是否重要 | 指令 | 参数 | 意义 |
---|---|---|---|
DIV | r/m8 | (ah, al) = (ax % r/m8, ax / r/m8)ah=ax % (r/m8)的余数,al = ax / (r/m8)的商 | |
DIV | r/m16 | (dx, ax) = dx:ax / r/m16 | |
DIV | r/m32 | (edx, eax) = edx:eax / r/m32 | |
IDIV | r/m8 | (ah, al) = ax / r/m8 | |
IDIV | r/m16 | (dx, ax) = dx:ax / r/m16 | |
IDIV | r/m32 | (edx, eax) = edx:eax / r/m32 |
无符号与有符号除法。第一个寄存器在伪代码中解释是接收余数,而第二个是接收商。如果目标的结果已出,那么除法会有异常生成。
在除法过后的 flags 标记是不确定的。
是否重要 | 指令 | 参数 | 意义 |
---|---|---|---|
* | SETcc | r/m8 | 设置 r/m8 为 0 或 1 |
如果cc 条件为true,那么8bit位设置为1。否则8bit位设置为0。
Binary-coded Decimal - 二进制编码的十进制
你将不会在汇编指令里看到这个指令,除了你在用COBOL调试代码时会编写外。
指令 | 意思 |
---|---|
DAA | 十进制的加法 |
DAS | 十进制的减法 |
上面这些指令在执行二进制编码的十进制操作后会修改 al 寄存器。
指令 | 意思 |
---|---|
AAA | ASCII adjust after addition(ASCII的加法) |
AAS | ASCII adjust after subtraction(ASCII的减法) |
上面这些指令在执行了二进制编码的十进制操作后会修改 gl 寄存器。
指令 | 意思 |
---|---|
AAM | ASCII adjust after multiplication(ASCII的乘法) |
AAD | ASCII adjust after division(ASCII的除法) |
上面这些指令在执行了二进制编码的十进制操作后会修改 al 与 ah 寄存器。
Bits - Bit位
是否重要 | 指令 | 参数 | 意义 |
---|---|---|---|
AND | r1/m, r2/m/#n | r1/m = r1/m and r2/m/#n | |
OR | r1/m, r2/m/#n | r1/m = r1/m or r2/m/#n | |
XOR | r1/m, r2/m/#n | r1/m = r1/m xor r2/m/#n | |
NOT | r1/m | r1/m = 按位 r1/m取反 | |
* | TEST | r1/m, r2/m/#n | 计算r1/m = r1/m and r2/m/#n |
test 指令计算逻辑 与 操作并根据结果设置 flags 标记,但不会把结果抛出去。下面列出常见的根据tests逻辑与的条件跳转。
是否重要 | 指令 | 参数 | 意义 |
---|---|---|---|
SHL | r1/m, cl/#n | r1/m <<= cl/#n | |
SHR | r1/m, cl/#n | r1/m >>= cl/#n zero-fill | |
* | SAR | r1/m, cl/#n | r1/m >>= cl/#n sign-fill |
最后一个bit位位移后放到进位标记。
是否重要 | 指令 | 参数 | 意义 |
---|---|---|---|
SHLD | r1, r2/m, cl/#n | Shift left double.对double类型左移 |
对 r1 左位移 cl/#n 的位数,并将 r2/m 的最高位(最左边的bit位)填充到 r1 的最低位(最右边的bit位)。r1 最左边被位移出的放置到carry进位标记。
假如r1=0101, r2=1000, #n=1, 就是r1向左位移1位,r1=x101x,最左边的x先抛弃并写入carry进位,最右边的x位将用r2的最左边的bit位(即:最高位)来填入,r2[=1000最高为是1,所以r1=101x中的最右边的x填入1,r1的结果为1011
指令 | 参数 | 意义 |
---|---|---|
SHRD | r1, r2/m, cl/#n | Shift right double.对double类型右移 |
对 r1 右位移 cl/#n 位数,并将 r2/m 最低为填入r1的最高位(最左边的bit位)。r1 最右边被位移出的放置到carry进位标记。
指令 | 参数 | 意义 |
---|---|---|
BT | r1, r2/#n | 复制 r1 对应的 r2/#n 位到carry标记为。按这么说r1就是mask掩码的作用 |
BTS | r1, r2/#n | 设置 r1 的所有1位 对应的 r2/#n 位上,并将r2复制到carry标记为。 |
BTC | r1, r2/#n | 清理 r1 的所有1位 对应的 r2/#n 位上,并将r2复制到carry标记为。 |
Control Flow - 控制流
是否重要 | 指令 | 参数 | 意义 |
---|---|---|---|
Jcc | dest | 分支条件 | |
JMP | dest | 直接跳转 | |
CALL | dest | 直接调用 | |
* | CALL | r/m | 直接调用 |
call 指令先将 return 的地址压栈,然后再跳转到目标地址。
是否重要 | 指令 | 参数 | 意义 |
---|---|---|---|
* | RET | #n | 返回 |
返回指令先pop出栈,然后跳转到栈上的return 返回的地址。一个非零的 #n 在 RET 后作为参数,代表pop出栈后的返回地址,#n 值应该被添加到 stack pointer 栈指针里。
指令 | 意义 |
---|---|
LOOP | 减少 ecx 的值,如果非零结果,则跳转。 |
LOOPZ | 减少 ecx 的值,如果非零结果,并且 zr 标记位有被设置了==(zr == 1)==,则跳转。 |
LOOPNZ | 减少 ecx 的值,如果非零结果,并且 zr 标记位没被设置==(zr == 0)==,则跳转。 |
JECXZ | 如果 ecx 为零,则跳转。 |
这些指令都是 x86 的 CISC 遗留产物,而在近代处理器实际上会比使用长时间编写的等效机制都要慢。(没看懂)
String Manipulation - 字符串操作
是否重要 | 指令 | 参数 | 意义 |
---|---|---|---|
MOVST | 将 esi 传送到 edi 上。 | ||
CMPST | 比较 esi 和 edi。 | ||
SCAST | 扫描 edi 到 accT 上。 | ||
LODST | 从 esi 加载到 accT 上。 | ||
STOST | 从a ccT 储存 到 edi 上。 |
在操作后,源与目标寄存器都会根据对应设置的 direction flag (方向标记:上或下)来 增加或减少 sizeof(T) 的量。
指令前缀可以使用 REP 来重复操作 ecx 寄存器上指定的次数。
rep mov 指令常用于复制内存块。
rep stos 指令常用于使用 accT 来填充到内存块。
Flags - 标记位
指令 | 意思 |
---|---|
LAHF | 从flags 标记为加载到 ah。 |
SAHF | 储存 ah 的值到 flags 上。 |
STC | 设置进位。 |
CLC | 清理进位。 |
CMC | 完成进位。 |
STD | 设置方向为下。 |
CLD | 设置方向为上。 |
STI | 启用中断。 |
CLI | 禁用中断。 |
Interlocked Instructions - 原子锁指令
指令 | 参数 | 意义 |
---|---|---|
XCHG | r1, r/m | 交换r1 与 r/m的值。 |
XADD | r1, r/m | 增加r1 到 r/m,上,并将原始值放回 r1。 |
CMPXCHG | r1, r/m | 比较与调整条件。 |
cmpxchg 指令是以下处理流的原子版本:
cmp
accT, r/m
jz
match
mov
accT, r/m
jmp
done
match:
mov
r/m, r1
done:
Miscellaneous - 杂项
是否重要 | 指令 | 参数 | 意义 |
---|---|---|---|
INT | #n | 捕获内核。 | |
BOUND | r,m | 如果r不在范围内则捕获。 | |
* | NOP | 无操作。 | |
XLATB | al = [ebx + al] | ||
BSWAP | r | 在寄存器中交换字节序。(Little Endian/Big Endian) |
这里 int 指令有个特殊的情况。
指令 | 参数 | 意义 |
---|---|---|
INT | 3 | 调试器断点捕获。 |
操作码 INT 3 是 0xCC。操作码 NOP 是 0x90。
当调试代码时,你可能需要补上外面的一些代码。你可以使用 0x90 来替换掉有问题的字节。
Idioms - 常用的
是否重要 | 指令 | 参数 | 意义 |
---|---|---|---|
XOR | r,r | r = 0 | |
TEST | r,r | 检测 r 是否为零。 | |
* | ADD | r,r | 左位移r 1位。 |
最后
以上就是聪明白云为你收集整理的x86 Instructions -x86 指令In this article - 此文Instruction Notation - 指令符号Memory, Data Transfer, and Data Conversion - 内存,数据传输,数据转换Arithmetic and Bit Manipulation - 算术与位操作Binary-coded Decimal - 二进制编码的十进制Bits - Bit位Control Flow - 控制流String Manipulation -的全部内容,希望文章能够帮你解决x86 Instructions -x86 指令In this article - 此文Instruction Notation - 指令符号Memory, Data Transfer, and Data Conversion - 内存,数据传输,数据转换Arithmetic and Bit Manipulation - 算术与位操作Binary-coded Decimal - 二进制编码的十进制Bits - Bit位Control Flow - 控制流String Manipulation -所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复