您当前的位置: 首页 > 

Jave.Lin

暂无认证

  • 1浏览

    0关注

    704博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

x86 Instructions -x86 指令

Jave.Lin 发布时间:2020-05-26 13:58:46 ,浏览量:1

文章目录
  • 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/#nMOVr1/m,r/m/#n符号扩展或*MOVZXr,r/m零扩展

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

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/#nADCr1/m, r2/m/#nr1/m += r2/m/#n + 进位SUBr1/m, r2/m/#nr1/m -= r2/m/#nSBBr1/m, r2/m/#nr1/m -= r2/m/#n + 进位NEGr1/mr1/m = -r1/mINCr/mr/m +=1DECr/mr/m -=1CMPr1/m, r2/m/#n计算r1/m - r2/m/#n

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

是否重要指令参数意义MULr/m8ax = al * r/m8MULr/m16dx:ax = ax * r/m16MULr/32edx:eax = eax * r/m32IMULr/m8ax = al * r/m8IMULr/m16dx:ax = ax * r/m16IMULr/m32edx:eax = eax * r/m32IMULr1, r2/mr1 *= r2/mIMULr1, 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/m16DIVr/m32(edx, eax) = edx:eax / r/m32IDIVr/m8(ah, al) = ax / r/m8IDIVr/m16(dx, ax) = dx:ax / r/m16IDIVr/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的除法)

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

Bits - Bit位 是否重要指令参数意义ANDr1/m, r2/m/#nr1/m = r1/m and r2/m/#nORr1/m, r2/m/#nr1/m = r1/m or r2/m/#nXORr1/m, r2/m/#nr1/m = r1/m xor r2/m/#nNOTr1/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 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 - 字符串操作 是否重要指令参数意义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 - 原子锁指令 指令参数意义XCHGr1, r/m交换r1 与 r/m的值。XADDr1, r/m增加r1 到 r/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 = 0TESTr,r检测 r 是否为零。*ADDr,r左位移r 1位。
关注
打赏
1664331872
查看更多评论
立即登录/注册

微信扫码登录

0.0402s