标题: 逆向工程中面对并理解编译器对除法的优化
http://scz.617.cn/misc/201603311247.txt
参看:
Understanding of MSVS C++ compiler optimizations - Hans Passant [2014-07-08] http://stackoverflow.com/questions/24628899/understanding-of-msvs-c-compiler-optimizations
这是我看过的最简洁的解答:
Processors are not very good at dividing, an idiv can take between 11 and 18 cycles. As opposed to shifts and multiplies, they usually only take a single cycle.
So the optimizer replaced your division by a multiplication using fixed-point math, taking advantage of a 32-bit multiply producing a 64-bit result into edx:eax. Back-of-the-envelope:
n / 100 = n * 0.32 / 32 = n * (0.32 * pow(2,32)) / 32 / pow(2,32)
Those divisions are very cheap, just a right-shift. And the multiplier becomes:
n / 10 = n * 0.4 / 4 = n * (0.4 * pow(2,32)) / 4 / pow(2,32) 0.4 * pow(2,32) = 1717986918.4 ~= 1717986919 = 0x66666667 (向上取整)
n / 5 = n * 2 / 10 = n * (2 * 0.4 * pow(2,32)) / 4 / pow(2,32) 2 * 0.4 * pow(2,32) = 3435973836.8 ~= 3435973837 = 0xCCCCCCCD (向上取整)
n / 3 = n * (2/3) / 2 = n * ((2/3) * pow(2,32)) / 2 / pow(2,32) (2/3) * pow(2,32) ~= 2863311530.667 ~= 2863311531 = 0xAAAAAAAB (向上取整)
有多种优化方式,比如:
n / 10 = n * 0.4 / 4 = n * (0.4 * pow(2,32)) / 4 / pow(2,32) n / 10 = n / 5 / 2 = n * (0.8 * pow(2,32)) / 8 / pow(2,32)
n / 5 = n * 2 / 10 = n * (0.8 * pow(2,32)) / 4 / pow(2,32) n / 5 = n / 10 * 2 = n * (0.4 * pow(2,32)) / 2 / pow(2,32)
保底的优化:
一般形式:
假设c不是2的幂,b为小于c的2的幂
前面只是介绍了编译器对除法优化的基本原理,并不是严格的数学推导。这里涉及一 个如何取整的问题,前述例子中4/7的情形是向下取整。前文没有解释如何取整,理 解其本质需要一些初等代数的知识,下文讲解得比较细:
快速立即除法的乘法实现(通用算法) - HAM [2009-10-31] http://blog.csdn.net/concreteham/article/details/4750740
如果拿0x51EB851F做关键字进行百度搜索,能找到一些从汇编角度讲解这种优化的中 文文章,其中有一篇被四处转载的,还做什么误差分析,我的建议是只看上文即可。
有一些现成的程序,在指定除数的情况下给出优化结果:
http://win32assembly.programminghorizon.com/files/magicnumber.zip http://www.masmforum.com/archive2012/6717_MagicNumber64.zip
推荐后者,比如指定除数125,得到:
这是编译器对除法的优化,一般人这辈子都不需要关心这种优化。但是,对于逆向工 程来说,可能必须面对并理解这种优化,现有F5无法将优化结果还原成人类可读方式。
话说回来,从功利性实践角度讲,不理解优化原理也无所谓,在逆向输出中看到神密 常量,放狗搜之即可,一般秒中。
罗列这种神密常量没有意义,尤其同一除数存在多种优化方式的情况下,下面这些仅 仅是便于查找:
0xAAAAAAAB 3 2/3 0xCCCCCCCD 5 4/5 0x92492492 7 4/7 0x49249249 7 2/7 0x24924925 7 1/7 0x38E38E39 9 0x66666667 10 4/10 0x51EB851F 100 32/100 0x10624DD3 1000