关于x86架构LEA指令非常规运算用法的技术问询
用LEA指令实现整数乘法的原理解析
原C代码:
int baz(int a, int b) { return a * 11; }
使用-O2编译后生成的汇编指令:
baz(int, int): lea eax, [rdi+rdi*4] lea eax, [rdi+rax*2] ret
核心知识点:LEA的真实作用
LEA指令的官方定义是计算源操作数的有效地址并存储到目标寄存器,但它并不会真的去访问这个地址对应的内存——这是理解这段汇编的关键。编译器正是利用这一点,把LEA当成一种高效的「算术运算指令」来用:它支持基址 + 变址*比例 + 位移的组合计算,能在单条指令里完成乘法加加法的操作,比单独用mul+add更高效,还不会影响CPU的标志位(比如CF、ZF这些)。
拆解两条LEA指令的运算逻辑
在x86-64的System V调用约定里,函数的第一个int参数a存在rdi寄存器里(第二个参数b因为没被用到,所以汇编里完全没处理):
- 第一条指令:
lea eax, [rdi+rdi*4]
计算逻辑为:rdi + rdi*4 = rdi*(1+4) = rdi*5,也就是把a*5的结果存到eax里。 - 第二条指令:
lea eax, [rdi+rax*2]
此时rax里存的是刚才的a*5,所以rax*2 = a*10,再加上rdi(即a),最终得到a*10 + a = a*11,正好对应C代码里的返回值。
为什么用LEA而不是直接用mul?
- LEA指令延迟更低,可与其他指令并行执行,适配优化后的代码需求。
- 当乘数能拆成加法和小倍数的组合时,用LEA组合运算比直接
mul更灵活,还不会修改FLAGS寄存器,避免影响其他依赖标志位的代码。
内容的提问来源于stack exchange,提问作者Ka Kkoi
相关产品推荐
相关产品推荐

