首页
社区
课程
招聘
[原创]release版本下除法优化过后还原除数的方法
发表于: 2017-11-10 04:52 3691

[原创]release版本下除法优化过后还原除数的方法

2017-11-10 04:52
3691

Release版本优化除法需要条件:

  1)除数不为零

  2)除数为立即数


 如不需看例子可直接查看文章总结(请往下拉)

由于例子进程为32位,所以最低移位数是32(如果是64位进程,那么最低移位数是64)

无符号被除数  除 2的幂

        例子:

        UINT uNum;

        uNum = uNum /8;

        release优化汇编如下

                    mov    eax, [ebp+uNum]

                    shr     eax, 3

                    除数为:2^3


无符号被除数 除 非2的幂 

                   例子:

         UINT uNum;

         uNum =uNum /11;

        release优化汇编如下

                    mov     eax, 0BA2E8BA3h
                    mul     [ebp+uNum]
                    shr     edx, 3
                    MagicNumber== 0BA2E8BA3h;

                    移位数N=32+3=35

因为使用的是 mul 指令,还原方法:       

 2^N/M的商向上取整

2^35/0BA2E8BA3h-->34359738368/3123612579=10.9999999996

10.9999999996向上取整为:11

除数为:11


特例: 

   UINT uNum;

   uNum =uNum /7;

  release优化汇编如下 

          mov     ecx, [ebp+uNum]

          mov     eax, 24924925h

          mul     ecx

          sub     ecx, edx

.         shr     ecx, 1

          add     ecx, edx

          shr     ecx, 2

魔法数M=24924925h;

移位数N=32+1+2=35;

因为使用的是 mul 指令,还原方法:    

 2^N/(2^32+M)的商向上取整

详细还原如下:

2^35/24924925h-->34359738368/(4294967296+613566757)=6.999999999

6.99999999向上取整为:7

除数为:7


无符号被除数 除 非2的幂负数

       例子:

UINT uNum;

uNum =uNum /-9;

release优化汇编如下

mov     eax, 80000005h

mul     [ebp+uNum]

 shr      edx, 1Fh

魔法数M=80000005h;

移位数N=32+1FH=63;

因为使用的是 mul 指令,(由于混除,当做无符号除法),还原方法:

2^N/M的商向上取整

详细还原如下:

2^63/80000005h-->9223372036854775808/2147483643=4294967286.00000002

4294967286.00000002向上取整为:4294967287

因为商值较大,转为十六进制:0FFFFFFF7h,当有符号解释为十进制:-9

除数为:-9


有符号被除数 除 2的幂

       例子:

int nNum;

nNum = nNum /16;

release优化汇编如下

        mov     eax, [ebp+nNum]

        cdq

        and     edx, 0Fh

        add     eax, edx

        sar     eax, 4

有符号除2的幂为  定式:

Mov  eax,mem

Cdq

And edx,immA

Add eax,edx

Sar eax,immB

还原方法:

当2^immB - 1 == immA

除数为2^immB


有符号被除数 除 非2的幂

       例子1: 1)当除数为正

int nNum;

nNum =nNum /19;

release优化汇编如下 

    mov     eax, 6BCA1AF3h

    imul    [ebp+nNum]

    sar     edx, 3

    mov     eax, edx

    shr     eax, 1Fh

    add     eax, edx

相比无符号被除数除非2的幂多了后三行汇编(还原无需在意)

魔法数M=6BCA1AF3h;

移位数N=32+3=35;

因为使用的imul  指令,所以需要知道除数为正还是负,

由于6BCA1AF3h<0x80000000,而另imul与sar之间edx并未做减法(nNum)调整,固判定除数为正数还原方法:

2^N/M的商向上取整

详细还原如下:

2^35/0BA2E8BA3h-->34359738368/1808407283=18.999999995

18.999999995向上取整为:19

除数为:19



例子1: 2)当除数为正 

int nNum;

nNum =nNum /7;

release优化汇编如下

mov     eax, 92492493h

           imul    [ebp+nNum]

           add     edx, [ebp+nNum]

           sar     edx, 2

           mov     eax, edx

           shr     eax, 1Fh

           add     eax, edx

相比无符号被除数除非2的幂多了后三行汇编(还原无需在意)

魔法数M=6BCA1AF3h;

移位数N=32+2;

因为使用的imul  指令,所以需要知道除数为正还是负,

由于M>=0x80000000,而另imul与sar之间edx有做加法(nNum)调整

固判定除数为正数.还原方式为:

2^N/M的商向上取整

2^34/92492493h-->17179869184/2454267027=6.99999999

6.99999999向上取整为:7

除数为:7



       例子2:1)当除数为负

int nNum;

nNum =nNum /-33;

release优化汇编如下 

      mov     eax, 0C1F07C1Fh

      imul    [ebp+nNum]

      sar     edx, 3

      mov     eax, edx

      shr     eax, 1Fh

      add     eax, edx

相比无符号被除数除非2的幂多了后三行汇编(还原无需在意) 

魔法数M=0C1F07C1Fh;

移位数N=32+3;

因为使用的imul  指令,所以需要知道除数为正还是负,

由于0C1F07C1Fh>=0x80000000,另imul与sar之间edx并未做加法(nNum)调整,固判定除数为负数,还原方式为:

2^N/neg(M)的商向上取整转为负数

neg(0C1F07C1Fh)=1041204193;

2^35/neg(0C1F07C1Fh)-->34359738368/1041204193=32.99999999

32.99999999向上取整为:33,加上负数符号-->-33

除数为:-33



 例子2:2)当除数为负

int nNum;

nNum =nNum /-7

release优化汇编如下

           mov     eax, 6DB6DB6Dh

           imul    [ebp+nNum]

           sub     edx, [ebp+nNum]

           sar     edx, 2

           mov     eax, edx

           shr     eax, 1Fh

           add     eax, edx

相比无符号被除数除非2的幂多了后三行汇编(还原无需在意)  

魔法数M=6DB6DB6Dh;

移位数N=32+2;

因为使用的imul  指令,所以需要知道除数为正还是负,

由于M<0x80000000,而imul与sar之间edx有做减法(nNum)调整,固判定除数为负数还原方式为:

2^N/neg(M)的商向上取整转为负数

neg(6DB6DB6Dh)=2454267027;

          2^34/neg(6DB6DB6Dh)-->17179869184/2454267027=6.99999999

6.99999999向上取整为:7 ,加上负数符号-->-7

除数为:-7


总结:

设B为进程位数

设N为移位数

设M为魔法数

设 C为除数

查看乘法指令为mul  或 imul

Mul指令还原

如果是 mul,则查看是否满足指令有”mul sub shr add shr”定式,如果满足,则使用          C=2^(N+B)/(2^B+M)

如果不满足,则使用                                                                                                                  C=2^(N+B)/M

如果是imul 则需要查看M来判断除数为正负

M<0X80000000 并且在imul 与sar指令中并未出现sub调整,则除数为正

否则除数为负,则使用                                                                                                              C=2^(N+B)/neg(M)

M>=0X80000000 并且在imul 与sar指令中并未出现add调整,则除数为负

否则除数为正,则使用                                                                                                               C=2^(N+B)/M


详细还原推到方式请查看钱林松老师写的DRE










[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (2)
雪    币: 1112
活跃值: (184)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
是不是还要看是哪一种哪一版IDE
2017-11-10 09:10
0
雪    币: 23080
活跃值: (3432)
能力值: (RANK:648 )
在线值:
发帖
回帖
粉丝
3
syxdotar 是不是还要看是哪一种哪一版IDE
和IDE无关,和编译器有关,vc/vs都是一样的,gcc也大同小异
2017-11-10 11:29
0
游客
登录 | 注册 方可回帖
返回
//