汇编与逆向系列

整理常用指令,方便查看。

mov-数据传送指令

源操作数:可以是一个立即数,存储在寄存器或者内存中

目的操作数:指定一个位置,寄存器或者内存地址

x86-64有一条限制,传送指令的两个操作数不能同时是内存位置

    指令       效果          
+---------+----------+                        
|MOV S,D  |   D<-S   | 传送                   
+---------+----------+                        
|movb     |          | 传送字节               
+---------+----------+                        
|movw     |          | 传送字                 
+---------+----------+                        
|movl     |          | 传送双字               
+---------+----------+                        
|movq     |          | 传送四字               
+---------+----------+                        
|movabsq  |          | 传送绝对四字           
+---------+----------+                        

大多数情况,MOV指令只会更新目的目的操作数指定的那些寄存器字节或者内存位置。唯一的例外是movl指令以寄存器为目的时,它会把该寄存器的高位4字节设置为0。造成这个例外的原因是x86-64采用的惯例,即任何为寄存器生成32位值的指令都会把该寄存器的高位部分置为0。

另外,将较小的源值复制到较大的目的时,有两种填充方式。

MOVZ是把目的中剩余的字节填充为0。MOVS是通过符号位扩展来填充,把源操作的最高位进行复制。

这两种的每条指令最后两个字符都是大小指示符:第一个字符指定源大小,第二个指定目的大小。

这两种方式目的操作数都只能是寄存器

                                              
    指令       效果                                   
+---------+--------------+                                                
|MOVZ S,R |  R<-零扩展(S) | 以零扩展进行传送              
+---------+--------------+                                                
|movzbw   |              |   字节-->字                           
+---------+--------------+                                                 
|movzbl   |              |   字节-->双字                       
+---------+--------------+                                                 
|movzwl   |              |   字-->双字                          
+---------+--------------+                                                
|movzbq   |              |   字节-->四字                       
+---------+--------------+                                                
|movzwq   |              |   字-->四字                           
+---------+--------------+                                                
                                                             

  指令           效果
+----------+-----------------------+ 
|MOVS S,R  |   R<-符号扩展(S)        |  以符号扩展进行传送 
+----------+-----------------------+
|movsbw    |                       |  字节-->字 
+----------+-----------------------+
|movsbl    |                       |  字节-->双字
+----------+-----------------------+
|movswl    |                       |  字-->双字 
+----------+-----------------------+ 
|movsbq    |                       |  字节-->四字
+----------+-----------------------+ 
|movswq    |                       |  字-->四字 
+----------+-----------------------+ 
|movslq    |                       |  双字-->四字 
+----------+-----------------------+
|cltq      |  %rax<-符号扩展(%eax)   |  %eax 扩展到 %rax 
+----------+-----------------------+                                                              

push & pop - 压入和弹出栈指令

%rsp 保存着栈顶元素的地址

栈顶元素地址是栈中元素地址最低值

注意: 因为栈和程序代码以及其他形式的程序数据都是放在同一内存中,所以程序可以用标准的内存寻址方法访问栈内的任意位置。 例如,假设栈顶元素是四字,指令movq 8(%rsp), %rdx会将第二个四字从栈中复制到寄存器%rdx

算术和逻辑操作指令

leaq-加载有效地址

leaq: load effective address,实际是movq指令的变形,但该指令并不是从指定位置读入数据,而是将有效地址写入到目的的操作数

  指令           效果
+----------+-------------+ 
|leaq S,D  |   D <- &S   | 
+----------+-------------+

如:%rdx值为x,则leaq 7(%rdx, %rdx, 4) = 4*x + x + 7 = 5x+7

一元操作

只有一个操作数,既是源又是目的。可以是寄存器也可以是内存地址

  指令         效果
+---------+----------+ 
|  INC D  | D <- D+1 | 自增
+---------+----------+
|  DEC D  | D <- D-1 | 自减
+---------+----------+
|  NEG D  | D <- -D  | 取负
+---------+----------+
|  NOT D  | D <- ~D  | 取补
+---------+----------+

二元操作

第二个操作数,既是源又是目的

  指令         效果
+-----------+----------+ 
|  ADD S,D  | D <- D+S | 加
+-----------+----------+
|  SUB S,D  | D <- D-S | 减
+-----------+----------+
|  IMUL S,D | D <- D*S | 乘
+-----------+----------+
|  XOR S,D  | D <- D^S | 异或
+-----------+----------+
|  OR S,D   | D <- D|S | 或
+-----------+----------+
|  AND S,D  | D <- D&S | 与
+-----------+----------+

移位操作

右移有算术和逻辑两种形式

移位量可以是一个立即数,或者是放在单字节寄存器%cl中,这是特殊的。

移位(shift)操作有两个指令,左移SALSHL,两者效果是一样的,都是将右边填上0。但右移不同,SAR执行算术右移(填上符号位),而SHR执行逻辑右移(填上0)。

移位操作的目的操作数可以是一个寄存器或者一个内存地址。

  指令         效果
+-----------+-----------+ 
|  SAL k,D  | D <- D<<k | 左移
+-----------+-----------+
|  SHL k,D  | D <- D<<k | 左移
+-----------+-----------+
|  SAR k,D  | D <- D>>k | 算术右移
+-----------+-----------+
|  SHR k,D  | D <- D>>k | 逻辑右移
+-----------+-----------+

128位特殊算术操作

两个64位有符号或无符号整数相乘得到的乘积需要128位来表示。x86-64指令集对128位(16字节、8字)数的操作提供有限支持。

    指令                效果
+----------+---------------------------------------+
|imulq S   |  R[%rdx]:R[%rax] <- S*R[%rax]         | 有符号乘法
|mulq S    |  R[%rdx]:R[%rax] <- S*R[%rax]         | 无符号乘法
+----------+---------------------------------------+
|clto      |  R[%rdx]:R[%rax] <- 符号扩展(R[%rax])   | 转换为八字
+----------+---------------------------------------+
|idivq S   |  R[%rdx] <- R[%rdx]:R[%rax] mod S     | 有符号除法
|          |  R[%rdx] <- R[%rdx]:R[%rax] / S       |
+----------+---------------------------------------+
|divq S    | R[%rdx] <- R[%rdx]:R[%rax] mod S      | 无符号除法
|          |  R[%rdx] <- R[%rdx]:R[%rax] / S       |
+----------+---------------------------------------+

控制

机器码提供基本的低级机制来实现有条件的行为:测试数据值,然后根据测试的结果来改变控制流或者数据流

常用的条件码:

  • CF: 进位标志。最近的操作使最高位产生了进位。可用来检查无符号操作的溢出。
  • ZF: 零标志。最近的操作得出结果为0。
  • SF:符号标志。最近的操作得到结果为负数。
  • OF:溢出标志。最近的操作导致一个补码溢出(有符号溢出)—-正溢出和负溢出。

常用访问条件码方式:

  1. 根据条件码的某种组合,将一个字节设置为0或者1
  2. 可以条件地跳转到程序的某个其他的部分
  3. 可以有条件地传送数据

cmp 和 test 指令

这两个指令只更新条件码,不更新寄存器


   指令          效果
+-------------+-------+
|CMP S1,S2    | S2-S1 |  比较
| cmpb        |       |  比较字节
| cmpw        |       |  比较字
| cmpl        |       |  比较双字
| cmpq        |       |  比较四字
+-------------+-------+
|TEST S1,S2   | S2&S1 |  测试
| testb       |       |  测试字节
| testw       |       |  测试字
| testl       |       |  测试双字
| testq       |       |  测试四字
+-------------+-------+ 

set 指令

一条 set 指令的目的操作数是低位单字节寄存器(寄存器)之一,或者一个字节的内存地址,指令将这个字节设置为0或者1。

    指令   等效指令      效果                   
+--------+-----------+-------------------------+
|sete D  |  setz     |  D <- ZF                | 相等/0
+--------+-----------+-------------------------+
|setne D |  setnz    |  D <- ~ZF               | 不相等/非0
+--------+-----------+-------------------------+
|sets D  |           |  D <- SF                | 负数
+--------+-----------+-------------------------+
|setns D |           |  D <- ~SF               | 非负数
+--------+-----------+-------------------------+
|setg D  | setle     |  D <- ~(SF ^ OF) & ~ZF  | 大于(有符号>)
+--------+-----------+-------------------------+
|setge D | setnl     |  D <- ~(SF ^ OF)        | 大于等于(有符号>=)
+--------+-----------+-------------------------+
|setl D  | setnge    |  D <- SF ^ OF           | 小于(有符号<)
+--------+-----------+-------------------------+
|setle D | setng     |  D <- (SF ^ OF) | ZF    | 小于等于(有符号<=)
+--------+-----------+-------------------------+
|seta D  | setnbe    |  D <- ~CF & ~ZF         | 超过(无符号>)
+--------+-----------+-------------------------+
|setae D | setnb     |  D <- ~CF               | 超过或相等(无符号>=)
+--------+-----------+-------------------------+
|setb D  | setnae    |  D <- CF                | 低于(无符号<)
+--------+-----------+-------------------------+
|setbe D | setna     |  D <- CF | ZF           | 低于或等于(无符号<=)
+--------+-----------+-------------------------+

注意:

  • setlsetg表示『小于时设置(set less)』和『大于时设置(set great)』
  • sete表示『当相等时设置(set when equal)』
  • setasetb表示『高于时设置(set ahead)』和『低于时设置(set below)』

跳转指令

待更新