算术和逻辑运算指令
leaq指令
leaq S, D // load effective address
q表示地址长度是64位
leaq 7(%rdx, %rdx, 4), %rax // 地址复制到rax中
有效地址的计算方式
假设寄存器rdx
内保存的数值是x
,则有效地址为7 + %rdx + %rdx * 4 = 5x + 7
leaq
指令会将有效地址值5x+7
直接写入到目的寄存器rax
一元操作指令
只要一个操作数,可以是寄存器,也可以是内存地址
INC D // Increment 加一
DEC D // Decrement 减一
NEG D // Negate 取负
NOT D // Complement 取补
二元操作指令
第一个是源操作数可以是立即数、寄存器或内存地址
第二个既是源操作数,也是目的操作数,可以使寄存器或内存地址,但不能是立即数
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 与
举例
地址: 0x100 | 0x108 | 0x110 | 0x118
内容: 0xFF | 0xAB | 0x13 | 0x11
%rax -> 0x100
%rcx -> 0x1
%rdx -> 0x3
addq %rcx, (%rax) // Mem[0x100] = Men[0x100] + R[%rcx]
这条加法指令将内存地址0x100
内的数据与寄存器rcx
相加,二者之和再存储到内存地址0x100
处,该指令执行完后,内存地址0x100
处所存储的数据由0xFF
变成0x100
subq %rdx, 8(%rax) // Mem[0x108] = Mem[0x108] - R[%rdx]
减法指令将内存地址0x108
内的数据减去寄存器rdx
内的数据,二者之差存储到内存地址0x108
处,该指令执行完后,内存地址0x108
处所存储的数据由0xAB
变成0xA8
incq 16(%rax) // Mem[0x110] = Mem[0x110] + 1
加一指令将内存地址0x110
内的数据加1,由0x13
变成0x14
subq %rdx, %rax // R[%rax] = R[%rax] - R[%rdx]
减法指令将寄存器rax
内的值减去寄存器rdx
内的值,所以由0x100
变成0xFD
移位操作指令
SAL k, D // D ← D << k Left Shift 左移
SHL k, D // D ← D << k Left Shift 左移,等同于SAL
SAR k, D // D ← D >> k(A) Arithmetic right shift 算术右移
SHR k, D // D ← D >> k(L) Logical right shift 逻辑右移
- 算术右移填符号位,逻辑右移填0
对于移位量k
,可以是立即数,或者是放在寄存器cl
中的数
- 移位指令只能用寄存器
cl
作为操作数
对于salb
,目的操作数数8位,所以移位量由cl
的低3位来决定
对于salw
,目的操作数数16位,所以移位量由cl
的低4位来决定
对于salw
,目的操作数数16位,所以移位量由cl
的低4位来决定
对于salq
,目的操作数数64位,所以移位量由cl
的低6位来决定
举例
long t2 = z * 48;
汇编指令
leaq (%rdx, %rdx, 2), %rax // R[%rdx] + R[%rdx]*2 = 3 * z
salq $4, %rax // 2^4 * R[%rax] = 16 * (3 * z) = 48 * z
乘法计算被分成两步
第一步先计算3 * z
,结果保存到寄存器rax
中,第二步将寄存器rax
左移4位,等价于乘以16,这样就通过一条leaq
和一条左移指令实现了乘法操作