assembly_log


汇编语言

一、操作数格式

  1. 操作数被分为三种类型

    • 立即数(immediate): 用来表示常数值,在ATT格式的汇编代码中,立即数的书写方式是‘$’后面跟一个C标准整数,如$-577或$0x1F
    • 寄存器(register): 标志某个寄存器的内容,16个寄存器的低位1字节、2字节、4字节、8字节中的一个作为操作数
    • 内存引用:根据计算出来的地址访问某个内存位置
  2. 下表为操作数格式

    对于下表中出现的符号,有以下定义:

    • ra : 表示任意寄存器a
    • R[ra] : 引用ra的值
    • Mb[Addr]: 表示对储存在内存中从地址Addr开始的b个字节的引用
    • Imm(rb, ri, s): 内存引用,有效地址被计算为 Imm + R[rb] + R[ri] s*
类型 格式 操作数值 名称
立即数 $Imm Imm 立即数寻址
寄存器 ra R[ra] 寄存器寻址
储存器 Imm M[Imm] 绝对寻址
储存器 (ra) M[R[ra]] 间接寻址
储存器 Imm(rb) M[Imm + R[ri]] (基址+偏移量)寻址
储存器 (rb, ri) M[R[rb] + R[ri]] 变址寻址
储存器 Imm(rb, ri) M[Imm + R[rb] + R[ri]] 变址寻址
储存器 (,ri, s) M[R[ri] s*] 比例变址寻址
储存器 Imm(,ri, s) M[Imm + R[ri] s*] 比例变址寻址
储存器 (rb, ri, s) M[R[rb] + R[ri] s*] 比例变址寻址
储存器 Imm(rb, ri, s) M[Imm + R[rb] + R[ri] s*] 比例变址寻址
表 1-1 操作数格式。

二、数据传送指令

1. MOV 类

指令 效果 描述
MOV S, D DS 传送
movb 传送字节
movw 传送字
movl 传送双字
movq 传送四字
movabsq I, R RI 传送绝对四字
表 2-1 简单的数据传送指令
指令 效果 描述
MOVZ S, R RS(零扩展) 以零扩展进行传输
movzbw 将做了零扩展的字节传送到字
movzbl 将做了零扩展的字节传送到双字
movzwl 将做了零扩展的字传送到双字
movzbq 将做了零扩展的字节传送到四字
movzwq 将做了零扩展的字传送到四字
表 2-2 零扩展数据传送指令。这些指令以寄存器或内存地址作为源,以寄存器作为目的
指令 效果 描述
MOVS S, R RS(符号扩展) 传送符号扩展的字节
movsbw 将做了符号扩展的字节传送到字
movsbl 将做了符号扩展的字节传送到双字
movswl 将做了符号扩展的字传送到双字
movsbq 将做了符号扩展的字节传送到四字
movslq 将做了符号扩展的双字传送到四字
ctlq %rax ← %eax(符号扩展) 把%eax符号扩展到%rax
表 2-3 符号扩展数据传送指令。movs指令以寄存器或内存地址作为源,以寄存器作为目的。ctlq指令只作用于寄存器%eax和%rax

2. 压入与弹出栈数据

指令 效果 描述
pushq S R[%rsp] ← R[%rsp] - 8;
M[R[%rsp]] ← S
将四字压入栈
popq D D ← M[R[%rsp]];
R[%rsp] ← R[%rsp] + 8
将四字弹出栈
表 2-4 入栈和出栈指令

三、x86_64的寄存器

​ 一个x86-64 的中央处理单元(CPU)包含一组16个存储64位值的通用目的寄存器。这些寄存器用来存储整数数据和指针。下图显示了这16个寄存器。它们的名字都以%r开头,不过后面还跟着一些不同命名规则的名字,这是由于指令集历史演化造成的。最初的8086中有8个16位的寄存器,即%ax到%sp。每个寄存器都有特殊用途。扩展到IA32架构时,这些寄存器也扩展成32位寄存器,标号从%eax到%ebp。扩展到x86-64后,原来的8个寄存器扩展成64位,标号从%rax到%rsp。除此之外,还增加了8个新的寄存器,它们的标号是按照新的命名规则制定的:从%r8到%r15。

图3-1 x86_64寄存器

四、算数与逻辑操作

1. 整数算数操作

​ 图4-1列出了x86-64的一些整数和逻辑操作。大多数操作都分成了指令类,这些指令类有各种带不同大小操作的变种(只有leaq没有其他大小的变种)。例如,指令类ADD由四条加法指令组成:addbaddwaddladdq

​ 事实上,给出的每个指令类都有对这四种不同大小数据的指令。这些指令操作被分为四种:加载有效地址、一元操作、二元操作和移位

图4-1 整数算术操作

2. 特殊的算术操作

​ 两个64位有符号或无符号整数相乘得到的乘积需要128位来表示。x86-64指令集对128位(16字节)数的操作提供有限的支持。图 4-2 描述的是支持产生两个64位数字的全128位乘积以及整数除法的指令。

图 4-2 特殊的算术操作

​ imulq指令有两种不同的形式,一种是“双操作数”乘法指令,它从两个64位操作数产生一个64位乘积。此外,x86-64指令集还提供了两条不同的“单操作数”乘法指令,以计算两个64位值的全128位乘积——一个是无符号数乘法(mulq),另一个是补码乘法(imulq)。这两条指令都要求一个参数必须在寄存器%rax中,而另一个作为指令的源操作数给出。然后乘积存放在**寄存器%rdx(高64位)和%rax(低64位)中。汇编器能够通过计算操作数的数目,分辨出想用哪条指令。

注: linux的x86环境下,使用g++ -Og -S test.cpp可以获得.s结尾的汇编代码,也可以使用objdump -d text.o来获取反汇编代码(反汇编代码的移动指令会省略后面的长度,如movq变为mov


文章作者: cfrost
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 cfrost !
  目录