玩命加载中 . . .

3.4-算术和逻辑运算指令


算术和逻辑运算指令

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和一条左移指令实现了乘法操作


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