栈是一个典型的数据结构类型,在此对栈的思想不再赘述,这里讲一下栈的汇编实现。
栈遵循后进先出的原则,通过push将数据压栈,通过pop删除数据。栈底的地址为最大的。
对应命令就是
pushq S,将四字压入栈中
popq D,将四字弹出栈
push等价于:
sub $8,%rsp
movq %rbp,(%rsp)
pop等价于:
movq (%rsp), %rax
add $8, %rsp
加载有效地址leaq
加载有效地址(load effective address) leaq的指令形式是从内存读数据到寄存器。
下面以例子说明
long scale(long x, long y, long z)
{
long t=x+4*y+12*z;
return t;
}
其对应的汇编为
scale:
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) + 4*(3*z)=x+4*y+12*z
ret
一元操作数
INC 加一
DEC 减一
NEG 取负
NOT 取补
二元操作数
ADD S,D 加
SUB S,D 减
IMUL S,D 乘
XOR S,D 异或
OR S,D 或
AND S,D 与
移位操作,先给出移位量,第二项给出要移位的数。移位量可以是一个立即数,或者将移位量存放在单字节寄存器%cl中。
SAL k, D 左移
SHL k,D 左移,等同于SAL
SAR k,D 算术右移
SHR k,D 逻辑右移
乘法操作
imulq双操作数 即从两个64位操作数产生一个64位乘积
补码乘法:要求有一个参数必须在寄存器%rax中,另一个作为指令的源操作数给出。
乘积的高64位%rdx,低64位%rax中。
例子
C语言:
void store_uprod(uint128_t *dest, uint64_t x, uint64_t y)
{
*dest=x*(uint128_t)y;
}
汇编:
store_uprod:
movq %rsi, %rax
mulq %rdx
movq %rax, (%rdi)
movq %rdx, 8(%rdi)
ret
除法
C语言:
void remdiv(long x, long y, long *qp, long *rp)
{
long q=x/y;
long r= x%y;
*qp=q;
*rp=r;
}
汇编:
remdiv:
movq %rdx, %r8
movq %rdi, %rax #低八位复制
cqto #自动按符号位补全高八位
idivq %rsi #除法操作
movq %rax, (%r8) #存商
movq %rdx, (%rcx)#存余数
ret
无符号数除法使用divq指令。