x86汇编总结

2015.03.27发布于笔记暂无评论/目录

近来工作和学习的时候多少会遇到一些汇编代码,特在此总结一些简单的汇编语言知识点。以能看懂常见的汇编代码为目的,不做深入探究。

语法

x86汇编语言主要有两个语法分支: AT&T和Intel。我们平常接触到的GNU系的工具(包括GCC,OBJDUMP等)都是使用AT&T语法,若无特别说明,下面的汇编代码例子也是如此。

两种语法分支的主要区别[1][2]:

AT&T Intel 注释
寄存器前缀 %eax eax
立即数前缀 $5 5
指令后缀 movl mov 操作数长度[3]
参数次序 movl $5, %eax mov eax, 5 R[eax] = 5
取址1 var [var] 变量
取址2 0x8(%eax) [eax + 0x8] 偏移
取址3 arr(, %eax, 4) [eax * 4 + arr] 数组

寄存器

仅介绍常见的寄存器。

通用寄存器

32位x86架构的CPU有8个通用寄存器[4]:

  • AX: Accumulator register
  • CX: Counter register
  • DX: Data register
  • BX: Base register
  • SP: Stack pointer register,指向栈顶。
  • BP: Stack base pointer register,指向当前stack frame的底部。
  • SI: Source index register
  • DI: Destination index register

以上名称对应的寄存器均为16位,在32位模式下,上面的寄存器名称前需要加E,64位模式下需要加R。例如,访问32位的AX寄存器需要使用名称EAX,而访问64位(x86_64)的需要使用RAX。

另外,AX, BX, CX, DX这四个通用寄存器的高8位和低8位还可以分成两个单独的寄存器使用,名称分别是XH和XL(X=A,B,C,D)。

下面是RAX寄存器的示意图

+---------------------------------------------------------------+
| 8bits | 8bits | 8bits | 8bits | 8bits | 8bits | 8bits | 8bits |
|---------------------------------------------------------------|
|                              RAX                              |
|---------------------------------------------------------------|
|                               |              EAX              |
|---------------------------------------------------------------|
|                                               |      AX       | 
|---------------------------------------------------------------|
|                                               |  AH   |   AL  |
+---------------------------------------------------------------+

x86_64添加了8个新的通用寄存器,且引入了新的命名规则,详情可参考这里

其他常用寄存器

  • EFLAGS: 32位寄存器,用于保存指令结果和处理器状态,具体说明可参考这里
  • IP: 指令寄存器,用于保存要执行的指令,和通用寄存器类似,32位模式下用EIP,64位模式下用RIP。

指令

mov

拷贝数据

# R[eax] = 5
movl $5, %eax
# var = 5
movl %eax, var

cmp

比较操作符,并将结果暂存于EFLAGS寄存器。

跳转指令

跳转指令可以修改IP寄存器的值,以实现控制流转换。

  • jmp: 无条件跳转到对应的label地址处。

      jmp label
    
  • je: 如果上一次cmp指令结果是相等的,跳转到label处。

      je label
    
  • jne: 和je相反,如果上一次cmp指令结果不相等,跳转到label处。

      jne label
    
  • jl: 如果上一次cmp指令的结果是小于,跳转到label处。

      cmp $5, $eax
      jl label
    

    需要注意AT&T语法的参数次序问题,上面的代码意思是当R[eax] < 5时跳转到label处。

其他跳转指令可参考这里

call ret

  • call: 将下一条指令的地址入栈,然后跳转到proc地址处。

      call proc
    
  • ret: 将栈顶的数据出栈并载入IP寄存器(即跳转回call的下一条指令处)。

      ret
    

enter leave

  • enter: 新建一个stack frame,相当于:

      push %ebp
      mov  %esp, %ebp
    
  • leave: 销毁当前stack frame,恢复上一个stack frame,相当于:

      mov %ebp, %esp
      pop %ebp
    

运算指令

  • add: 加法

      # R[ebx] += R[eax]
      add %eax, %ebx
    
  • sub: 减法

      # R[ebx] -= R[eax]
      sub %eax, %ebx
    
  • inc: 自增

      # R[eax] += 1
      inc %eax
    
  • dec: 自减

      # R[eax] -= 1
      dec %eax
    

其他常用指令

  • lea: Load effective address

      # R[eax] = R[ebx] - 8
      lea -0x8(%ebx), %eax
    

    注意和mov指令的区别:

      # mem[R[eax]] = R[ebx] - 8
      mov -0x8(%ebx), %eax
    

阅读资料


  1. x86 assembly language#Syntax,2015.03.27

  2. Brennan's Guide to Inline Assembly, 2015.03.27

  3. movb(byte 8bit), movw(word 16bit), movl(dword 32bit), movq(qword 64bit)

  4. X86 Assembly#X86 Architecture, 2015.03.30

#asm#总结#汇编

评论