C++反汇编学习笔记(五)各种算数运算的工作形式(2)

1、  除法

  对计算机而言,整数除法的结果必须是整数。计算机取整数部分的方式有如下几种:

  ①    向下取整

    如:-3.5=>-4;3.5=>3;

  ②    向上取整

    如:-3.5=>-3;3.5=>4;

  ③    向零取整

    如:-3.5=>-3;3.5=>3;

  C++和大多数高级语言,对整数除法都规定向零取整。

整数除法的几种情况:

    ①    常量除以常量

    ②    变量除以常量(常量值为2的幂)

    ③    变量除以常量(常量值为非2的幂)

    ④    变量除以常量(常量值为负的2的幂)

    ⑤    变量除以常量(常量值为负的非2的幂)

    ⑥    变量除以变量

  //③和⑤未在代码中进行详细分析,因为有点复杂,搞不太懂优化规则。看最后的总结


C++原码


Debug版


Release版


#include <iostream>

using namespace std;

int main()

{

int a, b;

cin >> a >> b;

//变量除以常量(常量值为2的幂)

a = a / 2;

cout << a ;

a = a / 8;

cout << a;

//变量除以常量(常量值为负的2的幂)

a = a / -2;

cout << a;

a = a / -8;

cout << a;

//变量除以常量(常量值为非2的幂)

a = a / 15;

cout << a;

//

a = a / 11;

cout << a;

//变量除以常量(常量值为负的非2的幂)

a = a / -15;

cout << a;

//

a = a / -11;

cout << a;

//常量除以常量

a = 18 / 15;

cout << a;

//变量除以变量

a = a / b;

cout << a;

system("pause");

return 0;

}


#include <iostream>

using namespace std;

int main()

{

.....略

int a, b;

cin >> a >> b;

..........略

//变量除以常量(常量值为2的幂)

a = a / 2;

00F75EB6  mov         eax,dword ptr [a]

00F75EB9  cdq

00F75EBA  sub         eax,edx

00F75EBC  sar         eax,1

00F75EBE  mov         dword ptr [a],eax

cout << a ;

00F75EC1  mov         esi,esp

cout << a ;

00F75EC3  mov         eax,dword ptr [a]

00F75EC6  push        eax

00F75EC7  mov         ecx,dword ptr ds:[0F810A8h]

00F75ECD  call        dword ptr ds:[0F81094h]

00F75ED3  cmp         esi,esp

00F75ED5  call        __RTC_CheckEsp (0F71339h)

a = a / 8;

00F75EDA  mov         eax,dword ptr [a]

00F75EDD  cdq

00F75EDE  and         edx,7

00F75EE1  add         eax,edx

00F75EE3  sar         eax,3

00F75EE6  mov         dword ptr [a],eax

cout << a;

00F75EE9  mov         esi,esp

00F75EEB  mov         eax,dword ptr [a]

00F75EEE  push        eax

00F75EEF  mov         ecx,dword ptr ds:[0F810A8h]

00F75EF5  call        dword ptr ds:[0F81094h]

00F75EFB  cmp         esi,esp

00F75EFD  call        __RTC_CheckEsp (0F71339h)

//变量除以常量(常量值为负的2的幂)

a = a / -2;

00F75F02  mov         eax,dword ptr [a]

00F75F05  cdq

00F75F06  sub         eax,edx

00F75F08  sar         eax,1

00F75F0A  neg         eax

00F75F0C  mov         dword ptr [a],eax

cout << a;

00F75F0F  mov         esi,esp

00F75F11  mov         eax,dword ptr [a]

00F75F14  push        eax

00F75F15  mov         ecx,dword ptr ds:[0F810A8h]

cout << a;

00F75F1B  call        dword ptr ds:[0F81094h]

00F75F21  cmp         esi,esp

00F75F23  call        __RTC_CheckEsp (0F71339h)

a = a / -8;

00F75F28  mov         eax,dword ptr [a]

00F75F2B  cdq

00F75F2C  and         edx,7

00F75F2F  add         eax,edx

00F75F31  sar         eax,3

00F75F34  neg         eax

00F75F36  mov         dword ptr [a],eax

cout << a;

00F75F39  mov         esi,esp

00F75F3B  mov         eax,dword ptr [a]

00F75F3E  push        eax

00F75F3F  mov         ecx,dword ptr ds:[0F810A8h]

00F75F45  call        dword ptr ds:[0F81094h]

00F75F4B  cmp         esi,esp

00F75F4D  call        __RTC_CheckEsp (0F71339h)

//变量除以常量(常量值为非2的幂)

a = a / 15;

00F75F52  mov         eax,dword ptr [a]

00F75F55  cdq

00F75F56  mov         ecx,0Fh

00F75F5B  idiv        eax,ecx

00F75F5D  mov         dword ptr [a],eax

cout << a;

00F75F60  mov         esi,esp

00F75F62  mov         eax,dword ptr [a]

00F75F65  push        eax

00F75F66  mov         ecx,dword ptr ds:[0F810A8h]

00F75F6C  call        dword ptr ds:[0F81094h]

00F75F72  cmp         esi,esp

00F75F74  call        __RTC_CheckEsp (0F71339h)

//

a = a / 11;

00F75F79  mov         eax,dword ptr [a]

00F75F7C  cdq

00F75F7D  mov         ecx,0Bh

00F75F82  idiv        eax,ecx

00F75F84  mov         dword ptr [a],eax

cout << a;

00F75F87  mov         esi,esp

00F75F89  mov         eax,dword ptr [a]

00F75F8C  push        eax

00F75F8D  mov         ecx,dword ptr ds:[0F810A8h]

00F75F93  call        dword ptr ds:[0F81094h]

00F75F99  cmp         esi,esp

00F75F9B  call        __RTC_CheckEsp (0F71339h)

//变量除以常量(常量值为负的非2的幂)

a = a / -15;

00F75FA0  mov         eax,dword ptr [a]

00F75FA3  cdq

00F75FA4  mov         ecx,0FFFFFFF1h

00F75FA9  idiv        eax,ecx

00F75FAB  mov         dword ptr [a],eax

cout << a;

00F75FAE  mov         esi,esp

00F75FB0  mov         eax,dword ptr [a]

00F75FB3  push        eax

00F75FB4  mov         ecx,dword ptr ds:[0F810A8h]

00F75FBA  call        dword ptr ds:[0F81094h]

00F75FC0  cmp         esi,esp

00F75FC2  call        __RTC_CheckEsp (0F71339h)

//

a = a / -11;

00F75FC7  mov         eax,dword ptr [a]

00F75FCA  cdq

00F75FCB  mov         ecx,0FFFFFFF5h

00F75FD0  idiv        eax,ecx

00F75FD2  mov         dword ptr [a],eax

cout << a;

00F75FD5  mov         esi,esp

00F75FD7  mov         eax,dword ptr [a]

00F75FDA  push        eax

00F75FDB  mov         ecx,dword ptr ds:[0F810A8h]

00F75FE1  call        dword ptr ds:[0F81094h]

00F75FE7  cmp         esi,esp

00F75FE9  call        __RTC_CheckEsp (0F71339h)

//常量除以常量

a = 18 / 15;

00F75FEE  mov         dword ptr [a],1

cout << a;

00F75FF5  mov         esi,esp

00F75FF7  mov         eax,dword ptr [a]

00F75FFA  push        eax

00F75FFB  mov         ecx,dword ptr ds:[0F810A8h]

00F76001  call        dword ptr ds:[0F81094h]

00F76007  cmp         esi,esp

00F76009  call        __RTC_CheckEsp (0F71339h)

//变量除以变量

a = a / b;

00F7600E  mov         eax,dword ptr [a]

00F76011  cdq

00F76012  idiv        eax,dword ptr [b]

00F76015  mov         dword ptr [a],eax

cout << a;

00F76018  mov         esi,esp

00F7601A  mov         eax,dword ptr [a]

00F7601D  push        eax

00F7601E  mov         ecx,dword ptr ds:[0F810A8h]

00F76024  call        dword ptr ds:[0F81094h]

00F7602A  cmp         esi,esp

00F7602C  call        __RTC_CheckEsp (0F71339h)

system("pause");

............略

return 0;

00F76048  xor         eax,eax

}

...........略


#include <iostream>

using namespace std;

int main()

{

//...........略

int a, b;

cin >> a >> b;

011712B0  mov         ecx,dword ptr ds:[1173038h]

int a, b;

cin >> a >> b;

//................略

//变量除以常量(常量值为2的幂)

a = a / 2;

011712CC  mov         eax,dword ptr [a]

cout << a ;

011712CF  mov         ecx,dword ptr ds:[117303Ch]

//用eax的符号位值填充edx,即如果eax(变量a)的值是负数,则edx=0XFFFFFFFF=-1,否则edx=0x0=0;

011712D5  cdq

//因为有符号除法的规则是向0取整,所以如果变量a是负数,则a+1(eax-edx=a-(-1)=a+1),否则a+0(eax-edx=a-0)不做处理,最后进行左移。

//例如:a=5(0x00000101),右移1位(a/2)得a=2;

//a=-5(0x11111011),如果直接右移1位(a/2)得a=0x11111101=-3,而向零取整的正确结果是-2,所以算数移位指令等价与向下取整,因此被除数为负数时,先对其进行调整(a+(2的n次方-1)),再进行移位。

//a+(2的1次方-1)=-5+1=-4(0X11111100),右移1位得a=-2(0X11111110)

011712D6  sub         eax,edx

011712D8  sar         eax,1

011712DA  push        eax

011712DB  mov         dword ptr [a],eax

011712DE  call        dword ptr ds:[1173024h]

a = a / 8;

011712E4  mov         eax,dword ptr [a]

cout << a;

011712E7  mov         ecx,dword ptr ds:[117303Ch]

011712ED  cdq

//如果a为负,则eax=-1,然后eax&7得eax=7(8=2的3次方,然后减1),然后eax+edx,最后进行移位

//例如:a=-9(0x11110111),如果直接右移3位(除以8)得a=-2(0x11111110),而我们要的结果是-1,所以a+7=-2(0x11111110)再进行右移3位得a=-1

011712EE  and         edx,7

011712F1  add         eax,edx

011712F3  sar         eax,3

011712F6  push        eax

011712F7  mov         dword ptr [a],eax

011712FA  call        dword ptr ds:[1173024h]

//变量除以常量(常量值为负的2的幂)

a = a / -2;

//和常量值为正的2的幂情况相似。先进行a除以正的2的幂,最后将结果neg取反。

//例如:a=5时,5/-2=-2;首先a/2得2,取反后a=-2;

// a=-5时,-5/-2=2;首先a/2得-2,取反后a=2;

01171300  mov         eax,dword ptr [a]

cout << a;

01171303  mov         ecx,dword ptr ds:[117303Ch]

01171309  cdq

0117130A  sub         eax,edx

0117130C  sar         eax,1

cout << a;

0117130E  neg         eax

01171310  push        eax

01171311  mov         dword ptr [a],eax

01171314  call        dword ptr ds:[1173024h]

a = a / -8;

0117131A  mov         eax,dword ptr [a]

cout << a;

0117131D  mov         ecx,dword ptr ds:[117303Ch]

01171323  cdq

01171324  and         edx,7

01171327  add         eax,edx

01171329  sar         eax,3

0117132C  neg         eax

0117132E  push        eax

0117132F  mov         dword ptr [a],eax

01171332  call        dword ptr ds:[1173024h]

//变量除以常量(常量值为非2的幂)

a = a / 15;

cout << a;

//由于除法指令的周期比乘法指令周期长很多,所以编译器会用周期较短的乘法和其他指令代替除法。

//设被除数变量为a,b为除数常量,则:

// =a*=a*=a**,由于b为常量,且的取值由编译器选择,所以的//值在编译期间就可以计算出来。在vc中,n的取值都大于等于32,这样就可//以直接调整使用乘法结果的高位。这个值常被称为魔数或幻数。

01171338  mov         ecx,dword ptr ds:[117303Ch]

0117133E  mov         eax,88888889h  //魔数

01171343  imul        dword ptr [a]

01171346  add         edx,dword ptr [a]

01171349  sar         edx,3

0117134C  mov         eax,edx

0117134E  shr         eax,1Fh

01171351  add         eax,edx

01171353  push        eax

01171354  mov         dword ptr [a],eax

01171357  call        dword ptr ds:[1173024h]

//

a = a / 11;

cout << a;

0117135D  mov         ecx,dword ptr ds:[117303Ch]

01171363  mov         eax,2E8BA2E9h  //魔数

01171368  imul        dword ptr [a]

0117136B  sar         edx,1

0117136D  mov         eax,edx

0117136F  shr         eax,1Fh

01171372  add         eax,edx

01171374  push        eax

01171375  mov         dword ptr [a],eax

01171378  call        dword ptr ds:[1173024h]

//变量除以常量(常量值为负的非2的幂)

a = a / -15;

cout << a;

0099137E  mov         ecx,dword ptr ds:[99303Ch]

00991384  mov         eax,77777777h

00991389  imul        dword ptr [a]

0099138C  sub         edx,dword ptr [a]

0099138F  sar         edx,3

00991392  mov         eax,edx

00991394  shr         eax,1Fh

00991397  add         eax,edx

00991399  push        eax

0099139A  mov         dword ptr [a],eax

0099139D  call        dword ptr ds:[993024h]

//

a = a / -11;

009913A3  mov         eax,0D1745D17h

009913A8  imul        dword ptr [a]

009913AB  sar         edx,1

009913AD  mov         eax,edx

009913AF  shr         eax,1Fh

cout << a;

009913B2  mov         ecx,dword ptr ds:[99303Ch]

009913B8  add         eax,edx

009913BA  push        eax

009913BB  mov         dword ptr [a],eax

009913BE  call        dword ptr ds:[993024h]

//常量除以常量

a = 18 / 15;

cout << a;

//编辑期间直接计算出结果

01171393  mov         ecx,dword ptr ds:[117303Ch]

01171399  push        1

0117139B  mov         dword ptr [a],1

011713A2  call        dword ptr ds:[1173024h]

//变量除以变量

a = a / b;

//变量a和b的值不确定,所以编译期间不能进行优化,而直接使用idiv除法指令

011713A8  mov         eax,dword ptr [a]

011713AB  cdq

011713AC  idiv        eax,dword ptr [b]

cout << a;

011713AF  mov         ecx,dword ptr ds:[117303Ch]

011713B5  mov         dword ptr [a],eax

011713B8  push        eax

011713B9  call        dword ptr ds:[1173024h]

system("pause");

011713BF  push        117319Ch

011713C4  call        dword ptr ds:[11730C4h]

return 0;

}

011713CA  mov         ecx,dword ptr [ebp-4]

return 0;

}

...............略


除数为非2的幂总结:


mov eax,魔数

imul ......

sar edx,......

mov reg,edx

shr reg,1fh

add edx,reg

;此后直接使用edx的值,eax弃而不用


当遇到左边指令序列时,基本可以判定是除法优化后的代码,其除法原型为变量a除以常量b,imul可表明是有符号计算,其操作数是优化前的被除数a。接下来统计右移的总次数以确定公式中的n值i,然后使用公式d=,将魔数代入公式求解常量除数b的近似值,四舍五入取整后,即可恢复除法原型。


mov eax,魔数

;这里的reg表示通用寄存器

mul reg

sub reg,edx

shr reg,1

add reg,edx

shr reg,A;这句或许没有,如果没有,则n值为1,否则这里的A就是n-1的值。

;此后直接使用reg的值,eax弃而不用。


如果遇到左边的指令序列,基本可以判定是除法优化后的代码。其除法原型为a除以常量b,mul表明是无符号计算,其操作数是优化前的被除数a,接下来统计右移的总次数以确定公式中的n值,然后使用公式b=将魔数代入公式求解常量除数b,即可恢复除法原型。


mov eax,魔数(大于7FFFFFFFH)

imul reg

add edx,reg

sar edx,......

mov reg, edx

shr reg,1fh

add edx,reg

;此后直接使用edx的值。


当遇到左边的指令序列时,基本可以断定是除法优化后的代码,其除法原型为a除以常量b,imul表明是有符号计算,其操作数是优化前的被除数a,接下来统计右移的总次数以确定公式中n的值,然后使用公式b=,将魔数代入公式求解常量除数b,即可恢复除法原型。


除数为负的非2的幂总结


mov eax,魔数(大于7FFFFFFFH)

imul reg

sar edx,......

mov reg,edx

shr reg,1FH

add edx,reg

;此后直接使用edx的值


如果遇到左边的指令序列,基本可以判定是除法优化后的代码,其除法原型为a除以常量b,imul可表明是有符号计算,其操作数是优化前的被除数a,由于魔数取值小于等于7FFFFFFFH,而imul和sar之间有sub指令来调整乘积,故可认定除数为负,且魔数为补码形式。接下来统计右移的总次数以确定公式中n的值,然后使用公式|b|=,将魔数代入公式求解常量除数|b|,即可恢复除法原型。


mov eax,魔数(小于等于7FFFFFFFH)

imul reg

sub edx,reg

sar edx,......

mov reg,edx

shr reg,1FH

add edx,reg

;此后直接使用edx的值


如果遇到左边的指令序列,基本可以判定是除法优化后的代码,其除法原型为a除以常量b,imul可表明是有符号计算,其操作数是优化前的被除数a,由于魔数取值大于7FFFFFFFH,而imul和sar之间未见任何调整代码,故可认定除数为负,且魔数为补码形式。接下来统计右移的总次数以确定公式中n的值,然后使用公式|b|=,将魔数代入公式求解常量除数|b|,即可恢复除法原型。

时间: 2024-10-06 07:56:59

C++反汇编学习笔记(五)各种算数运算的工作形式(2)的相关文章

Caliburn.Micro学习笔记(五)----协同IResult

Caliburn.Micro学习笔记(五)----协同IResult 今天说一下协同IResult 看一下IResult接口 /// <summary> /// Allows custom code to execute after the return of a action. /// </summary> public interface IResult { /// <summary> /// Executes the result using the specif

angular学习笔记(五)-阶乘计算实例(1)

<!DOCTYPE html> <html ng-app> <head> <title>2.3.2计算阶乘实例1</title> <meta charset="utf-8"> <script src="../angular.js"></script> <script src="script.js"></script> </

NLTK学习笔记(五):分类和标注词汇

[TOC] 词性标注器 之后的很多工作都需要标注完的词汇.nltk自带英文标注器pos_tag import nltk text = nltk.word_tokenize("And now for something compleyely difference") print(text) print(nltk.pos_tag(text)) 标注语料库 表示已经标注的标识符:nltk.tag.str2tuple('word/类型') text = "The/AT grand/J

Linux System Programming 学习笔记(五) 进程管理

1. 进程是unix系统中两个最重要的基础抽象之一(另一个是文件) A process is a running program A thread is the unit of activity inside of a process the virtualization of memory is associated with the process, the threads all share the same memory address space 2. pid The idle pro

java之jvm学习笔记五(实践写自己的类装载器)

java之jvm学习笔记五(实践写自己的类装载器) 课程源码:http://download.csdn.net/detail/yfqnihao/4866501 前面第三和第四节我们一直在强调一句话,类装载器和安全管理器是可以被动态扩展的,或者说,他们是可以由用户自己定制的,今天我们就是动手试试,怎么做这部分的实践,当然,在阅读本篇之前,至少要阅读过笔记三. 下面我们先来动态扩展一个类装载器,当然这只是一个比较小的demo,旨在让大家有个比较形象的概念. 第一步,首先定义自己的类装载器,从Clas

WEB前端学习笔记 五

接web前端学习笔记第四篇,此篇为web学习笔记 五,在此感谢您的采集和转发,但请注明文章出自网知博学. 2.0.3  html标签的属性格式 现在我们知道了两个双标签分别是,标题标签:<h1> - <h6>.和段落标签:<p></p>还知道了一个换行的单标签:<br />,现在我们给<p></p>标签添加一个属性,来改变段落是右对齐,还是左对齐,还是居中. 如上图,<p>标签中的 align(中文就是排列的意

小猪的数据结构学习笔记(五)

小猪的数据结构学习笔记(五) 线性表之--循环链表                           --转载请注明出处:coder-pig 循环链表知识点归纳: 相关代码实现: ①判断是否为空表: ②单循环链表的存储结构 其实和单链表的结构是一样的! /*定义循环链表的存储结构*/ typedef struct Cir_List { int data; struct Cir_List *next; }Lnode; ③初始化循环单链表 代码如下: //1.循环链表的初始化 //表示一个元素,如

python之list(学习笔记五)

python之list(学习笔记五) Python内置的一种数据类型是列表:list.list是一种有序的集合,可以随时添加和删除其中的元素. 比如,列出公司里同事的名字,就可以用一个list表示: >>> worker = ['wtf','laotan','xiaoxian'] >>> worker ['wtf', 'laotan', 'xiaoxian'] 变量 worker 就是一个list.用 len() 函数可以获得list元素的个数: >>>

Boost Thread学习笔记五

多线程编程中还有一个重要的概念:Thread Local Store(TLS,线程局部存储),在boost中,TLS也被称作TSS,Thread Specific Storage.boost::thread库为我们提供了一个接口简单的TLS的面向对象的封装,以下是tss类的接口定义: class tss{public:    tss(boost::function1<void, void*>* pcleanup);    void* get() const;    void set(void*