目录 Table of Contents
地址计算指令与其它-2
将 leal 指令用于计算 (实例一)
我们故意构造这么一个 arith 函数
int arith(int x, int y, int z)
{
int t1 = x + y;
int t2 = z + t1;
int t3 = x + 4;
int t4 = y * 48;
int t5 = t3 + t4;
int rval = t2 * t5;
return rval;
}
这个函数就是为了显示一下它的功能, 做了一些很无聊的计算
我们用 gcc 将其编译为汇编代码 :
arith :
; Set up
pushl %ebp
movl %esp, %ebp
; Body
movl 8(%ebp), %eax
movl 12(%ebp), %edx
leal (%edx, %eax), %ecx
leal (%edx, %edx, 2), %edx
sall $4, %edx
addl 16(%ebp), %ecx
leal 4(%edx, %eax), %eax
imull %ecx, %eax
; Finish
movl %ebp, %esp
popl %ebp
ret
函数栈内存如图
首先我们 mov
指令, 相当于把 x y 两个参数分别放到了 eax edx 里面去.
leal (%edx, %eax), %ecx
实际上这里我们用了 leal 指令完成了加法
再往下走, %ecx leal (%edx, %edx, 2), %edx
相当于完成了一个 3*edx, 这种做法要比用单独一条乘法指令快
sall $4, %edx
相当于我把算出来的结果给它左移了四位, 也就是相当于乘了 16, 所以就完成了 48*y 的操作
再往后我们再把这个 z 取出来, 取出来之后我们当然把 z 加上 ecx, 就是 z 加上 t1. 然后还是用 leal
把数据算出来. 实际上完成了 4 + t4 + x
最后还有个 t2 * t5, 因为这是两个变量相乘, 就没有一个常量, 这样你不得不用一条乘法指令
实例二
一开头就把 eax 通过 8(%ebp), 就是把 x 这个参数传进来
第二条指令就是把 y 取出来, 运算了个异或
再往下呢我们做了一个算数的右移 sarl
17 位, 因为 t1 是 int 有符号位, 所以它要做算术右移保证符号位
andl $8185, %eax
就是做了个 mask, 我们看 C 代码, mask 里面有个 1 的什么什么再减去 7, 肯定在编译的过程中就把这个常数给算出来了, 算出来之后就直接把这个常数编译到你的指令里面去了, $8185 就是这么来的. 编译器直接把它算出来, 然后直接用上了, 就变成这个样子.