我是靠谱客的博主 聪明白云,最近开发中收集的这篇文章主要介绍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 -,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

文章目录

  • 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 不会使用)。

为了节省空间,许多指令都使用合并的形式,如下列例子:

是否重要指令参数意义
*MOVr1,r/m/#nr1=r/m/#n

第一个参数必须是一个寄存器,但第二个可以是寄存器或是内存地址,或是一个立即数。
译者jave.lin:上面的r1就是必须为寄存器r/m/#n对应寄存器/内存地址/立即数,立即数的时候前面需要价格#井号,立即数的意思就是一个写死的数值,如#999

为了节省更多的空间,指令也可以如下表示:

是否重要指令参数意义
*MOVr1/m,r/m/#nr1/m=r/m/#n

译者jave.lin:目标值可以是一个寄存器,也可以是一个内存地址

意思是第一个参数可以是一个寄存器,也可以是一个内存地址,而第二个可以是一个寄存器,内存地址,或是立即数。

另外说明一下,dst, src 不能两边都是内存地址。

更进一步的说,带有位宽(8,16,32)的可以附加到源src或是目标dst表示参数必须的位宽大小。例如,r8意思是8bit位的寄存器。

Memory, Data Transfer, and Data Conversion - 内存,数据传输,数据转换

内存与数据传输指令不影响标记。

Effective Address - 有效的地址

是否重要指令参数意义
*LEAr,m载入有效的地址(r = address of m,r = m的地址

例如,LEA eax, [esi+4] 意思 eax = esi + 4。该指令常用语执行算术。

Data Transfer - 数据传输

是否重要指令参数意义
MOVr1/m,r2/m/#nr1/m=r2/m/#n
MOVr1/m,r/m/#n符号扩展或
*MOVZXr,r/m零扩展

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

Stack Manipulation - 栈操作

栈指针是存放在 esp 寄存器。esp 的值指向栈顶(最近的push,最早的pop的位置),越早存于栈中的元素它的地址将越大(栈的地址增长是负的,几:push会减少esp,pop会增加esp

是否重要指令参数意义
PUSHr/m/#n数值压栈
POPr/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 - 算术

是否重要指令参数意义
ADDr1/m, r2/m/#nr1/m += r2/m/#n
ADCr1/m, r2/m/#nr1/m += r2/m/#n + 进位
SUBr1/m, r2/m/#nr1/m -= r2/m/#n
SBBr1/m, r2/m/#nr1/m -= r2/m/#n + 进位
NEGr1/mr1/m = -r1/m
INCr/mr/m +=1
DECr/mr/m -=1
CMPr1/m, r2/m/#n计算r1/m - r2/m/#n

cmp 指令计算减法与根据减法结果设置 flags 标记,但把结果抛到外面去了。下面通常是配合 jump 指令来测试减法结果来执行跳转。

是否重要指令参数意义
MULr/m8ax = al * r/m8
MULr/m16dx:ax = ax * r/m16
MULr/32edx:eax = eax * r/m32
IMULr/m8ax = al * r/m8
IMULr/m16dx:ax = ax * r/m16
IMULr/m32edx:eax = eax * r/m32
IMULr1, r2/mr1 *= r2/m
IMULr1, r2/m, #nr1 = r2/m * #n

无符号与有符号的操作。在操作过后flags标记的状态是不确定的。

是否重要指令参数意义
DIVr/m8(ah, al) = (ax % r/m8, ax / r/m8)ah=ax % (r/m8)的余数,al = ax / (r/m8)的商
DIVr/m16(dx, ax) = dx:ax / r/m16
DIVr/m32(edx, eax) = edx:eax / r/m32
IDIVr/m8(ah, al) = ax / r/m8
IDIVr/m16(dx, ax) = dx:ax / r/m16
IDIVr/m32(edx, eax) = edx:eax / r/m32

无符号与有符号除法。第一个寄存器在伪代码中解释是接收余数,而第二个是接收商。如果目标的结果已出,那么除法会有异常生成。

在除法过后的 flags 标记是不确定的。

是否重要指令参数意义
*SETccr/m8设置 r/m8 为 0 或 1

如果cc 条件为true,那么8bit位设置为1。否则8bit位设置为0。

Binary-coded Decimal - 二进制编码的十进制

你将不会在汇编指令里看到这个指令,除了你在用COBOL调试代码时会编写外。

指令意思
DAA十进制的加法
DAS十进制的减法

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

指令意思
AAAASCII adjust after addition(ASCII的加法)
AASASCII adjust after subtraction(ASCII的减法)

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

指令意思
AAMASCII adjust after multiplication(ASCII的乘法)
AADASCII adjust after division(ASCII的除法)

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

Bits - Bit位

是否重要指令参数意义
ANDr1/m, r2/m/#nr1/m = r1/m and r2/m/#n
ORr1/m, r2/m/#nr1/m = r1/m or r2/m/#n
XORr1/m, r2/m/#nr1/m = r1/m xor r2/m/#n
NOTr1/mr1/m = 按位 r1/m取反
*TESTr1/m, r2/m/#n计算r1/m = r1/m and r2/m/#n

test 指令计算逻辑 操作并根据结果设置 flags 标记,但不会把结果抛出去。下面列出常见的根据tests逻辑与的条件跳转。

是否重要指令参数意义
SHLr1/m, cl/#nr1/m <<= cl/#n
SHRr1/m, cl/#nr1/m >>= cl/#n zero-fill
*SARr1/m, cl/#nr1/m >>= cl/#n sign-fill

最后一个bit位位移后放到进位标记。

是否重要指令参数意义
SHLDr1, r2/m, cl/#nShift 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

指令参数意义
SHRDr1, r2/m, cl/#nShift right double.对double类型右移

r1 右位移 cl/#n 位数,并将 r2/m 最低为填入r1的最高位(最左边的bit位)。r1 最右边被位移出的放置到carry进位标记。

指令参数意义
BTr1, r2/#n复制 r1 对应的 r2/#n 位到carry标记为。按这么说r1就是mask掩码的作用
BTSr1, r2/#n设置 r1 的所有1位 对应的 r2/#n 位上,并将r2复制到carry标记为。
BTCr1, r2/#n清理 r1 的所有1位 对应的 r2/#n 位上,并将r2复制到carry标记为。

Control Flow - 控制流

是否重要指令参数意义
Jccdest分支条件
JMPdest直接跳转
CALLdest直接调用
*CALLr/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 - 字符串操作

是否重要指令参数意义
MOVSTesi 传送到 edi 上。
CMPST比较 esiedi
SCAST扫描 edi 到 accT 上。
LODSTesi 加载到 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 - 原子锁指令

指令参数意义
XCHGr1, r/m交换r1r/m的值。
XADDr1, r/m增加r1r/m,上,并将原始值放回 r1
CMPXCHGr1, r/m比较与调整条件。

cmpxchg 指令是以下处理流的原子版本:


cmp
accT, r/m
jz
match
mov
accT, r/m
jmp
done
match:
mov
r/m, r1
done:

Miscellaneous - 杂项

是否重要指令参数意义
INT#n捕获内核。
BOUNDr,m如果r不在范围内则捕获。
*NOP无操作。
XLATBal = [ebx + al]
BSWAPr在寄存器中交换字节序。(Little Endian/Big Endian

这里 int 指令有个特殊的情况。

指令参数意义
INT3调试器断点捕获。

操作码 INT 3 是 0xCC。操作码 NOP 是 0x90。

当调试代码时,你可能需要补上外面的一些代码。你可以使用 0x90 来替换掉有问题的字节。

Idioms - 常用的

是否重要指令参数意义
XORr,rr = 0
TESTr,r检测 r 是否为零。
*ADDr,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 -所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(45)

评论列表共有 0 条评论

立即
投稿
返回
顶部