前言
本篇文章介绍x86-64的算数和逻辑操作指令,主要包含下面几部分:
- 加载有效地址指令
- 一元操作指令
- 二元操作指令
- 移位指令
- 特殊指令
加载有效地址指令
加载有效地址指令的指令名称为leaq
(load effective address quad),从这个名称就可以看出leaq的特点:
- 该指令的源操作数是一个内存引用,但是
不是指的内存引用在内存中的值,而是内存引用本身这个地址的值
,这会让我们一下想到指针,也让我们一下子想到取地址符&。 - 该指令的目的操作数是一个
四字的寄存器
,为什么一定是四字呢,因为在x86-64的CPU中,一个内存地址就是用四字来表示的。
更进一步,leaq指令还有一点很牛逼的就是,结合内存引用的计算方式
m
e
m
A
d
d
=
I
m
m
(
R
b
,
R
i
,
s
)
mem Add= Imm(R_b,R_i,s)
memAdd=Imm(Rb,Ri,s)
我们可以很方便的运行很多运算,我们实际举一个例子,下面是正经C代码
#include <stdio.h>
long scale(long x, long y, long z);
int main()
{
int a = scale(10,11,12);
return 0;
}
long scale(long x, long y, long z)
{
long t = x + 4 * y + 12 * z;
return t;
}
我们用gcc编译成汇编代码,不同的优化级别会生成不同的代码,比如使用默认的优化gcc -S test1.c -o test1.s
,生成的部分代码如下:
movq %rdi, -24(%rbp) # rdi就是x
movq %rsi, -32(%rbp) # rsi就是y
movq %rdx, -40(%rbp) # rdx就是z
movq -32(%rbp), %rax
leaq 0(,%rax,4), %rdx # 4 * y
movq -24(%rbp), %rax
leaq (%rdx,%rax), %rcx # x + 4 * y
movq -40(%rbp), %rdx
movq %rdx, %rax
addq %rax, %rax # 2 * z
addq %rdx, %rax # 2 * z + z = 3 * z
salq $2, %rax # (3 * z) * 4 = 12 * z
addq %rcx, %rax # x + 4 * y + 12 * z
经过-O3优化后gcc -S test1.c -o test1.s -O3
的代码如下:
# rdi就是x
# rsi就是y
# rdx就是z
leaq (%rdi,%rsi,4), %rax # x + 4 * y
leaq (%rdx,%rdx,2), %rdx # z + 2 * z = 3 * z
leaq (%rax,%rdx,4), %rax # x + 4 * y + (3 * z)*4
这玩意真是个天才的设计
一元操作指令
一元操作指令有四个:
INC D:D = D +1
DEC D:D = D -1
NEG D:D = -D 数值取反
NOT D:按位取反
D既可以是一个寄存器,也可以是一个内存引用
二元操作指令
二元操作指令有六个:
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
D既可以是一个寄存器,也可以是一个内存引用
S可以是一个立即数,寄存器或者内存引用
移位指令
移位指令有四个:
SAL k, D:全称(Shift Arithmetic(算术) Left),D向左移动k位
SHL k, D:全称(Shift Logical(逻辑) Left),D向左移动k位
SAR k, D:全称(Shift Arithmetic(算术) Right),D向右移动k位,左侧的位用符号位补齐
SHR k, D:全称(Shift Logical(逻辑) Right),D向右移动k位,左侧的位用0补齐
注意:
k可以是一个立即数,或者是寄存器cl
,只能是这个寄存器,并且按理说cl有八位,最多可以移位255。但是实际不是这样,移位操作对
w
w
w位长的数据值进行操作,移位量是由寄存器cl的低m位决定的,这里
2
m
=
w
2^m = w
2m=w 。高位会被忽略
特殊指令
单操作数乘法
imulq S:计算 S * %rax的值,S和%rax都作为有符号数处理,结果高64位存储在寄存器rdx中,低64位存储在寄存器rax中
mulq S:计算 S * %rax的值,S和%rax都作为无符号数处理,结果高64位存储在寄存器rdx中,低64位存储在寄存器rax中
idivq S:寄存器rdx(高64位)和rax(低64位)中的128位数作为有符号被除数,S作为有符号除数,结果余数存储在寄存器rdx中,商存储在寄存器rax中
divq S:寄存器rdx(高64位)和rax(低64位)中的128位数作为无符号被除数,S作为无符号除数,结果余数存储在寄存器rdx中,商存储在寄存器rax中
clto:将寄存器rax的值以符号位扩展到寄存器rdx和rax的128位中