imull S,edx:eax = eax * S(edx表示64位的高32位,eax表示低32位),有符号64位乘法。
mull S,edx:eax = eax * S,无符号64位乘法。
cltd,eax寄存器中的数,按照符号位扩展到edx,转为8个字节。
idivl S,edx =edx:eax mod S,eax =edx:eax / S,有符号除法。
divl S,edx =edx:eax mod S,eax =edx:eax / S,无符号除法。
一对寄存器edx:eax组成64位的四字。
示例:
long long mul_64(long long a, long long b)
{
long long c = a*b;
return c;
}
gcc -O1 -S -m32 mul_64.c
mul_64:
pushl %ebp
movl %esp, %ebp
subl $12, %esp //栈指针下移12个字节。
movl %ebx, (%esp) //保存ebx。
movl %esi, 4(%esp) //保存esi。
movl %edi, 8(%esp) //保存edi。
movl 8(%ebp), %ecx
movl 12(%ebp), %ebx//ebx:ecx用于保存64位整数a。
movl 16(%ebp), %eax
movl 20(%ebp), %edx//edx:eax用于保存64位整数b。
movl %edx, %esi //b的高位32位装入esi。
imull %ecx, %esi //a的低32位与b的高32位相乘,结果放到esi中。
movl %ebx, %edi //a的高位32位装入edi。
imull %eax, %edi //a的高32位与b的低32位相乘,结果放到edi中。
addl %edi, %esi //两个中间结果相加,放到esi中。
mull %ecx //a的低32位与b的低32位相乘,结果放到edx:eax中。
addl %edx, %esi //把上条指令计算结果的高32位,与edi保存的中间结果相加。
movl %esi, %edx//把计算结果保存回edx中。
movl (%esp), %ebx //恢复ebx值
movl 4(%esp), %esi //恢复esi值
movl 8(%esp), %edi //恢复edi值
movl %ebp, %esp
popl %ebp
ret
对算法的解释:
a = (a1* 2^32 + a2)
b = (b1*2^32 + b2)
假设a1,b1都不为0,两个高32位乘必然大于2^64,会溢出,所以忽略。
因此乘法只计算a1*b2 + b1*a2,如果这个结果溢出,也不用关心。
如果没有溢出,那么结果应该保存在高32位,与a2*b2结果求和。
int div_32(long a, long b)
{
long c = a / b;
return c;
}
gcc -O1 -S -m32 div.c
div_32:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %edx //把a装入到edx
movl %edx, %eax //复制a到eax
sarl $31, %edx //算术右移31位,相当于edx都用符号位填充了。
idivl 12(%ebp) //a/b = eax a modb = edx
popl %ebp
ret