x86 Instructions -x86 指令

文章目录

  • 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两个寄存器,将dstsrc相加,并将结果设置到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 零扩展

MOVSXMOVZXmov指令的特殊版本,它们执行从源到目标的符号扩展或零扩展。这是仅有的允许源与目标是不同大小的指令(实际上,他们也必须是不同的大小)。

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的除法)

上面这些指令在执行了二进制编码的十进制操作后会修改 alah 寄存器。

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 比较 esiedi
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 交换r1r/m的值。
XADD r1, r/m 增加r1r/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位。

你可能感兴趣的:(Architecture)