x86-64常用指令总结
文章目录
- 数据格式
- 寄存器
- 操作数格式(寻址方式)
- 数据传送指令
- 压入和弹出栈数据
- 算术和逻辑操作
- 控制指令
- 条件码
- 访问条件码
- 跳转指令
- 条件传送指令
- 转移控制
个人博客
本文将《深入理解计算机系统》中涉及到的 x86-64 常用指令进行了总结,需要的时候方便查询
本文采取的是ATT格式的汇编代码,这是 gcc、objdump 等工具的默认格式。但是在其他一些工具里,比如说微软的工具和 Intel 的文档里,其汇编代码都是 Intel 格式的
数据格式
| Intel 数据类型 | 汇编代码后缀 | 大小(字节) |
|---|---|---|
| 字节 | b | 1 |
| 字 | w | 2 |
| 双字 | l | 4 |
| 四字 | q | 8 |
| 单精度 | s | 4 |
| 双精度 | l | 8 |
Intel 使用
字(word)表示16位数据类型汇编指令除了要指明操作对象,还要指明操作对象的数据类型及长度。为了指明操作对象的数据类型及长度,可以在指令后面加上表示数据类型的后缀,比如
movl和movq分别表示操作的对象为双字和四字,gcc 生成的汇编代码一般都有这样的一个字符后缀;但其实操作对象的长度也可以通过寄存器给出,比如说eax和rax分别表示32位和64位,因此指令后面不加后缀也是可以的
寄存器

%ebp和%esp:栈是从高地址向低地址延伸的。每个函数的每次调用,都有它自己独立的一个栈帧,%esp总是指向当前栈帧的顶部(低地址),而%ebp通常指向当前栈帧的底部(高地址),用于在栈帧中寻址
操作数格式(寻址方式)
| 类型 | 格式 | 操作数值 | 名称 |
|---|---|---|---|
| 立即数 | $Imm | Imm | 立即数寻址 |
| 寄存器 | r a r_a ra | R[ r a r_a ra] | 寄存器寻址 |
| 存储器 | Imm | M[Imm] | 绝对寻址 |
| 存储器 | ( r a r_a ra) | M[R[ r a r_a ra]] | 间接寻址 |
| 存储器 | Imm( r b r_b rb) | M[Imm+R[ r b r_b rb]] | (基址+偏移量)寻址 |
| 存储器 | ( r b , r i r_b,r_i rb,ri) | M[R[ r b r_b rb]+R[ r i r_i ri]] | 变址寻址 |
| 存储器 | Imm( r b , r i r_b,r_i rb,ri) | M[Imm+R[ r b r_b rb]+R[ r i r_i ri]] | 变址寻址 |
| 存储器 | ( , r i , s ,r_i,s ,ri,s) | M[R[ r i r_i ri] ⋅ s \cdot s ⋅s] | 比例变址寻址 |
| 存储器 | Imm( , r i , s ,r_i,s ,ri,s) | M[Imm+R[ r i r_i ri] ⋅ s \cdot s ⋅s] | 比例变址寻址 |
| 存储器 | ( r b , r i , s r_b,r_i,s rb,ri,s) | M[R[ r b r_b rb]+R[ r i r_i ri] ⋅ s \cdot s ⋅s] | 比例变址寻址 |
| 存储器 | Imm( r b , r i , s r_b,r_i,s rb,ri,s) | M[Imm+R[ r b r_b rb]+R[ r i r_i ri] ⋅ s \cdot s ⋅s] | 比例变址寻址 |
数据传送指令
| 指令 | 效果 | 描述 |
|---|---|---|
| MOV S , D \text{MOV }S, D MOV S,D | D ← S D\leftarrow S D←S | 传送 |
| movb movw movl movq movabsp | 传送字节 传送字 传送双字 传送四字 传送绝对的四字 |
x86-64 约定,传送指令的两个操作数不能都指向内存位置
| 指令 | 效果 | 描述 |
|---|---|---|
| MOVZ S , D \text{MOVZ }S, D MOVZ S,D | D ← 零扩展 ( S ) D\leftarrow \text{零扩展}(S) D←零扩展(S) | 以零扩展进行传送 |
| movzbw movzbl movzwl movzbq movzwq | 将做了零扩展的字节传送到字 将做了零扩展的字节传送到双字 将做了零扩展的字传送到双字 将做了零扩展的字节传送到四字 将做了零扩展的字传送到四字 |
| 指令 | 效果 | 描述 |
|---|---|---|
| MOVS S , D \text{MOVS }S, D MOVS S,D | D ← 符号扩展 ( S ) D\leftarrow \text{符号扩展}(S) D←符号扩展(S) | 以零扩展进行传送 |
| movsbw movsbl movswl movsbq movswq movslq cltq | %rax ← \leftarrow ← 符号拓展(%eax) | 将做了符号扩展的字节传送到字 将做了符号扩展的字节传送到双字 将做了符号扩展的字传送到双字 将做了符号扩展的字节传送到四字 将做了符号扩展的字传送到四字 将做了符号扩展的双字传送到四字 把%eax符号扩展到%rax |
压入和弹出栈数据
| 指令 | 效果 | 描述 |
|---|---|---|
| pushq S popq D | R[%rsp] ← \leftarrow ← R[%rsp]-8; M[R[%rsp]] ← \leftarrow ← S D ← \leftarrow ← M[R[%rsp]]; R[%rsp] ← \leftarrow ← R[%rsp]+8 | 将四字压入栈 将四字弹出栈 |
这两个操作都会修改%rsp的值
算术和逻辑操作
| 指令 | 效果 | 描述 |
|---|---|---|
| leaq S, D | D ← \leftarrow ← &S | 加载有效地址 该指令实际上是movq指令的变形, 它的指令形式是从内存读数据到寄存器, 但实际上它没有引用内存,而是将有效地址 写入到目的操作数, 比如 leaq 7(%rdi,%rsi,4),%rax 会把%rax设置为 %rdi+4*%rsi+7 |
| INC D DEC D NEG D NOT D | D ← \leftarrow ← D + 1 D ← \leftarrow ← D - 1 D ← \leftarrow ← -D D ← \leftarrow ← ~D | |
| ADD S,D SUB S,D IMUL S,D XOR S,D OR S,D AND S,D | D ← \leftarrow ← D + S D ← \leftarrow ← D - S D ← \leftarrow ← D * S D ← \leftarrow ← D ^ S D ← \leftarrow ← D | S D ← \leftarrow ← D & S | |
| SAL k,D SHL k,D SAR k,D SHR | D ← \leftarrow ← D << k D ← \leftarrow ← D << k D ← \leftarrow ← D >>(算数) k D ← \leftarrow ← D >>(逻辑) k | 左移 左移(等同于SAL) 算术右移 逻辑右移 |
注意,
ADD S,D由四条加法指令组成,即addb,addw,addl和addq,其他指令也是如此
Intel把16字节的数称为八字(oct word)。下面是一些特殊的指令:
| 指令 | 效果 | 描述 |
|---|---|---|
| imulq S mulq S | R[%rdx]:R[%rax] ← \leftarrow ← S * R[%rax] R[%rdx]:R[%rax] ← \leftarrow ← S * R[%rax] | 有符号乘法,结果高64位放在%rdx,低64位放在%rax 无符号乘法,结果高64位放在%rdx,低64位放在%rax |
| clto | R[%rdx]:R[%rax] ← \leftarrow ← 符号拓展(R[%rax]) | 将%rax符号拓展为8字,高64位放在%rdx |
| idivq divq | R[%rdx] ← \leftarrow ← (R[%rdx]:R[%rax]) mod S R[%rdx] ← \leftarrow ← (R[%rdx]:R[%rax]) ÷ \div ÷ S R[%rdx] ← \leftarrow ← (R[%rdx]:R[%rax]) mod S R[%rdx] ← \leftarrow ← (R[%rdx]:R[%rax]) ÷ \div ÷ S | 有符号除法,将%rdx作为被除数的高64位,%rax作为被除数的低64位 无符号除法,将%rdx作为被除数的高64位,%rax作为被除数的低64位 |
控制指令
条件码
CPU维护着一组单个位的条件码寄存器,它们描述了最近的算数或者逻辑操作的属性,可以检查这些寄存器来执行条件分支指令。最常用的条件码有:
- CF:进位标志,最近的操作使最高位产生了进位,可用于检查无符号操作的溢出
- ZF:零标志,最近的操作得出的结果为0
- SF:符号标志,最近的操作得到的结果为负数
- OF:溢出标志,最近的操作导致一个补码溢出(正溢出获负溢出)
算术和逻辑操作列出的指令中,除了leaq,其他指令都会修改条件码寄存器
除了算数和逻辑操作指令可以改变条件码寄存器,下面的指令也可以改变:
| 指令 | 基于 | 描述 |
|---|---|---|
| CMP S1,S2 | S2 - S1 | 比较,根据 S2 - S1 的值来设置条件码寄存器 |
| TEST S1,S2 | S1 & S2 | 根据 S1 & S2 (逻辑与,不是按位与)的值来设置条件码寄存器 |
访问条件码
条件码通常不会直接读取,常用的使用方法有三种
- 更具条件码的某种组合,将一个字节设置为0或者1
- 根据条件码进行跳转
- 有条件地传送数据
对于第一种情况,将这一整类指令称为SET指令
| 指令 | 同义名 | 效果 | 设置条件 |
|---|---|---|---|
| sete D setne D | setz setnz | D ← \leftarrow ← ZF D ← \leftarrow ← ~ZF | 相等/零 不等/非零 |
| sets D setns D | D ← \leftarrow ← SF D ← \leftarrow ← ~SF | 负数 非负数 | |
| setg D setge D setl D setle D | setnle setnl setnge setng | D ← \leftarrow ← ~(SF^OF) & ~ZF D ← \leftarrow ← ~(SF^OF) D ← \leftarrow ← SF^OF D ← \leftarrow ← SF^OF | ZF | 有符号大于 有符号大于等于 有符号小于 有符号小于等于 |
| seta D setae D setb setbe | setnbe setnb setnae setna | D ← \leftarrow ← ~CF & ~ZF D ← \leftarrow ← ~CF D ← \leftarrow ← CF D ← \leftarrow ← CF | ZF | 无符号大于 无符号大于等于 无符号小于 无符号小于等于 |
跳转指令
| 指令 | 同义名 | 跳转条件 | 描述 |
|---|---|---|---|
| jmp Label jmp *Operand | 1 1 | 直接跳转 间接跳转 | |
| je Label jne Label | jz jnz | ZF ~ZF | 相等 不相等 |
| js Label jns Label | SF ~SF | 负数 非负数 | |
| jg Label jge Label jl Label jle Label | jnle jnl jnge jng | ~(SF^OF) & ~ZF ~(SF^OF) SF^OF SF^OF |ZF | 有符号大于 有符号大于等于 有符号小于 有符号小于等于 |
| ja Label jae Label jb Label jbe Label | jnbe jnb jnae jna | ~CF & ~ZF ~CF CF CF | ZF | 无符号大于 无符号大于等于 无符号小于 无符号小于等于 |
条件传送指令
| 指令 | 同义名 | 跳转条件 | 描述 |
|---|---|---|---|
| cmove S,R cmovne S,R | cmovz cmovnz | ZF ~ZF | 相等 不相等 |
| cmovs S,R cmovns S,R | SF ~SF | 负数 非负数 | |
| cmovg S,R cmovge S,R cmovl S,R cmovle S,R | cmovnle cmovnl cmovnge cmovng | ~(SF^OF) & ~ZF ~(SF^OF) SF^OF SF^OF |ZF | 有符号大于 有符号大于等于 有符号小于 有符号小于等于 |
| cmova S,R cmovae S,R cmovb S,R cmovbe S,R | cmovnbe cmovnb cmovnae cmovna | ~CF & ~ZF ~CF CF CF | ZF | 无符号大于 无符号大于等于 无符号小于 无符号小于等于 |
转移控制
| 指令 | 描述 |
|---|---|
| call Label call *Operand ret | 过程调用 过程调用 从过程调用中返回 |
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
