C++ 反汇编初探

本文探讨了C++中运算符优先级及其求值顺序的相关问题,通过具体实例分析了算术运算符、递增递减运算符及输出运算符在不同编译器下的表现。

因为想到昨天一道笔试题:


    char *s = "Apple";
    cout <<s+2;

记得算术运算符 + 号比移位运算符 << 的优先级高,可是当时笔试时脑袋很乱,以为会输出'A'+2 ...剩下的就不说了。上机调试了一下,应该是 指针s+2,然后cout 打印 字符串。这么说。


由此在网上看到一个关于运算符++、--优先级的问题(现在看来,依靠未定义的运算顺序来计算是无意义的),先看一题:

   int i = 1;
   cout << i++ << "," << i-- <<endl;

输出结果 0,1?为什么。我最开始认为按后缀运算符计算方法,起码也该是 i++ 返回 1(此后i=2)、i-- 返回2(此后i=1),但是结果显然和我预料的不一样。此处在 CSDN 的bbs帖子往楼下扫视,得知 cout 是对象,<< 是与它相关的运算符重载函数, “函数”两个字很重要,它表明 ① 一般参数从右至左求值(求值顺序编译器相关,不要依赖这样的求值顺序); ② 函数有返回值。cout<< 的返回值是 (*this),也就是调用者 cout, 这使得运算符 << 像 = 一样可以被连续使用。写成标准的函数调用显示更明显 cout.operator<<(i++).operator<<(i--),与赋值运算符一样,都是从左至右的调用(求值)顺序,那么先用 i=1计算 i-- (返回值为1,但 i 减为0)传参, 然后用 i=0 计算 i++(返回值0)。


再看一题:

    int i=3;
    cout << i++ * ++i + i-- * --i;

由于运算符本身的优先级,使得:

         i++ * ++i + i-- * --i 完全等价于 ( (i++)*(++i))+((i--)*(--i))

我个人认为是 3*5 + 5*3 =30(从左至右求值),于是上机调试,vs 2008 给的结果是 18,也就是 3*3 + 3*3 =18(先求前缀表达式的值++i、--i,则i增1减1不变,整个表达式的值求完后,再求后缀表达式的值),而在 codeblocks 下调试(MinGW gdb 调试器)输出的是 30 。当然后来在 VC++ 6下调试是25, Linux 32 位也是25。

VS 2008 反汇编:

     ret = i++ * ++i + i-- * --i;
004113B5  mov         eax,dword ptr [i]
004113B8  add         eax,1
004113BB  mov         dword ptr [i],eax
004113BE  mov         ecx,dword ptr [i]
004113C1  sub         ecx,1
004113C4  mov         dword ptr [i],ecx
004113C7  mov         edx,dword ptr [i]
004113CA  imul        edx,dword ptr [i]
004113CE  mov         eax,dword ptr [i]
004113D1  imul        eax,dword ptr [i]
004113D5  add         eax,edx
004113D7  mov         dword ptr [ret],eax
004113DA  mov         ecx,dword ptr [i]
004113DD  sub         ecx,1
004113E0  mov         dword ptr [i],ecx
004113E3  mov         edx,dword ptr [i]
004113E6  add         edx,1
004113E9  mov         dword ptr [i],edx

 VC++ 6 汇编:

        ret = i++ * ++i + i-- * --i;
0040156F   mov         eax,dword ptr [ebp-8]
00401572   add         eax,1
00401575   mov         dword ptr [ebp-8],eax
00401578   mov         ecx,dword ptr [ebp-8]
0040157B   imul        ecx,dword ptr [ebp-8]
0040157F   mov         edx,dword ptr [ebp-8]
00401582   sub         edx,1
00401585   mov         dword ptr [ebp-8],edx
00401588   mov         eax,dword ptr [ebp-8]
0040158B   imul        eax,dword ptr [ebp-8]
0040158F   add         ecx,eax
00401591   mov         dword ptr [ebp-4],ecx
00401594   mov         ecx,dword ptr [ebp-8]
00401597   sub         ecx,1
0040159A   mov         dword ptr [ebp-8],ecx
0040159D   mov         edx,dword ptr [ebp-8]
004015A0   add         edx,1
004015A3   mov         dword ptr [ebp-8],edx

 

  codeblocks:

 ret = i++ * ++i + i-- * --i;

0x0040135D    mov    -0xc(%ebp),%eax
0x00401360    lea    0x1(%eax),%edx
0x00401363    mov    %edx,-0xc(%ebp)
0x00401366    addl   $0x1,-0xc(%ebp)
0x0040136A    imul   -0xc(%ebp),%eax
0x0040136E    mov    %eax,%ecx
0x00401370    mov    -0xc(%ebp),%eax
0x00401373    lea    -0x1(%eax),%edx
0x00401376    mov    %edx,-0xc(%ebp)
0x00401379    subl   $0x1,-0xc(%ebp)
0x0040137D    imul   -0xc(%ebp),%eax
0x00401381    add    %ecx,%eax
0x00401383    mov    %eax,-0x10(%ebp)


*gcc 编译器优化的汇编代码里没有继续处理后续的 i++、i--,可能是因为编译器检测到此条语句以后 i 没有再被使用,所有没有后续计算。

值得一提的是,codeblocks 用的是 GCC 编译器,GCC编译器是 Unix/Linux 标准,使用的汇编语言语法格式与Intel的手册有很大不同,Unix/Linux采用AT&T汇编格式作为汇编语言的语法格式。
         如果想了解AT&T汇编可以参考文章:Linux AT&T 汇编语言开发指南

首先关于 [评价可免费] 的严重声明: 一、评价=评论加评价(评星星); 二、评价必须是下载完了该资源后的评价,没下载就评论无效; 三、如果正确评价了,返还积分可能需要等等,系统需要反应下。呵呵 评论时记得要评分。然后会返回给你花费的分再加1分.理论上有十分就可以下载完所有的资源了。一般人我不告诉他。 MFC 程序逆向 – 消息篇(上) 作者:szdbg Email:szdbg@sina.com 前言: 记得前一段时间,我刚接触软件破解和逆向这一行时,对于一些软件不知从何处跟踪按钮消息,试了好多方法,就是断 不下来,在系统模块中经常转得晕头转向,而一无所获。 MFC 程序是一种常见类型的程序,我静下心来,潜心研究了一下MFC 消息流程。弄清原委之后,一切豁然开朗,发现跟 踪MFC 程序和消息处理原来是如此。。。,跟踪按钮事件处理也由此变得特别简单。 于是,我将这些研究整理成文,以备后忘。并希望大家有所帮助,失误之处,请高手指正。 的确, .Net之类的程序必定是大势所趋,不过,就目前来说,MFC程序在软件市场还是占有重要的一席之地,所以,了解它,对于逆向和破解此类程序还是很有必要的. MFC之所以显的复杂,就在于它隐藏了它的消息的处理机制,可以说, 程序员基本上不需要懂得它的消息处理过程,就可以写出一套满足应用的软件来.这有好有坏,好的是大大简化了程序员写程序的过程,坏的一方面是,给一般程序员留下了一个迷团: 我只知道这样做,而不知道为什么这样做.心里老是觉得不踏实.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值