这是我今天破解一个crackme看到的
XOR EAX,ESI
发现原来是VC 编译器将除法优化为乘法的结果,好不容易搞明白,贴出两个对我帮助很大的帖子http://bbs.pediy.com/archive/index.php?t-68849.html
http://www.cppblog.com/huyutian/articles/124742.html
并作备份如下:
今天调试一个程序时遇到了一段奇怪的汇编代码
看了半天也没看明白,主要是这个68DB8BADh出现的很突兀,与前后代码在逻辑上都不相关联。到网上搜了下,还居然找到了答案。原来这是一段编译器将除法优化为乘法运算的典型代码。众所周知,除法是最耗CPU的,能够转化为等效的乘法就要快得多了。但不是每次除法都能这么优化的。对于一些特定数作为被除数时,这种优化还是很有效的。
http://www.thesolver.it/Manuali/Factotum/source/076.htm这里列出了一些典型数的除法转换表。
这个表是32位运算下除法转换为乘法的一些案例。比如68DB8BADh这个魔术数就是用来转换除以625的。要计算x/625 = (x * 68DB8BADh) >>8.所以上面的代码其实就是计算[esi +0Eh] / 10000.
下面这个表是64位运算时除法转换为乘法的一些魔术数,摘录在此,以防备忘
如果想搞清楚相关的运算原理可以看该网站的Chapter 10. Integer Division by Constants
大家也可以自己编一段小程序验证一下。
10
在VC2008下设置项目编译属性Assembler Output,选择输出汇编代码,看看编译出来的代码与上面的完全一致。
———————————————————————————————————————————
#include
int
{
}
.text:00401000
.text:00401000
.text:00401000
.text:00401005
.text:00401007
.text:0040100C
.text:0040100E
.text:00401010
.text:00401012
.text:00401015
.text:00401017
.text:00401018
.text:00401019
.text:0040101E
规则就是:
除数扩大X倍得到一个2^N。
除法就变为:被除数乘以X,再右移N位了。
A/B
比如
会先乘以
硬件除法器的效率,不用说比加减,就是比乘法,也至少慢几倍。
硬件乘法器目前的研究已经相当成熟,比如十分常见的化莱氏树并行加法快速乘法器,对于设计好的乘法器,比如很多DSP中的乘加单元,在流水中可以一个周期完成一条乘法(当然是乘法器流水线处于理想状态下),在通常情况下,一条乘法指令可以在4~8个周期内完成。
但除法器要完成一次除法运算,在当今极度优化的硬件上,也至少需要十几个周期。
用乘法替换除法的近似算法,在库和编译器里随处可见。如果配置编译器按最大速度优化,那么编译器很可能会执行这种优化。而如果按最小体积优化,可能就使用硬件的除法指令了。
原文转自:http://blog.sina.com.cn/s/blog_62d718780100mqmm.html