关于后缀的反汇编入栈形式

纹枰老妖 2014-05-23 08:27:41
先看c语言的代码:
#include "stdio.h"
void budong(int a);
void main()
{
int i=3;
int g=0;
budong( i++ );
}

void budong(int a )
{
printf("%d",a);
}


它的反汇编代码如图所示:
看哪个红线框内,执行顺序是:
第1步——取出i的值,移动给寄存器eax 。
第2步——取出eax的值,移动到 机器内存为 【ebp-0Ch】 的位置。
第3步——取出【ebp-0Ch】那个个位置里面的值,移动给寄存器ecx 。
第4步——把ecx压入栈里。
相信大家都看的出来,这四个步骤,至少有两步是脱裤子放屁多此一举,比如,完全可以省略成【取出i的值,移动给寄存器eax,然后直接把eax压入栈里,完事。。。就像下面这张图片一样: 其实这个代码唯一的区别就是源代码中的i++变成i】


我想问的是:在调用函数budong时,为什么传递参数是i++时,机器会多运行一些可有可无的步骤【第2步和第3步】?它们的存在有什么意义??
...全文
447 27 打赏 收藏 转发到动态 举报
写回复
用AI写文章
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
纹枰老妖 2014-08-07
  • 打赏
  • 举报
回复
引用 26 楼 lm_whales 的回复:
缺省配置的Debug 版本,按部就班的执行, C,C++语义,没有做优化。 有冗余代码是正常的。 缺省配置的Release 版本才会做优化。 VC缺省配置的Debug 版本,不做优化,严格按照C,C++代码的语义,编译。 从而保证 逻辑正确,语义正确。这是必要的。 这可以保证,不会有其他原因,引出的错误,干扰编译结果。 冗余代码消除,属于编译优化的工作,对Debug 版本,不是必要的。
哈,终于遇到大侠了,谢谢!!
lm_whales 2014-07-18
  • 打赏
  • 举报
回复
缺省配置的Debug 版本,按部就班的执行, C,C++语义,没有做优化。 有冗余代码是正常的。 缺省配置的Release 版本才会做优化。 VC缺省配置的Debug 版本,不做优化,严格按照C,C++代码的语义,编译。 从而保证 逻辑正确,语义正确。这是必要的。 这可以保证,不会有其他原因,引出的错误,干扰编译结果。 冗余代码消除,属于编译优化的工作,对Debug 版本,不是必要的。
赵4老师 2014-05-28
  • 打赏
  • 举报
回复
引用 21 楼 wenpinglaoyao 的回复:
[quote=引用 20 楼 zhao4zhong1 的回复:] Windows Server 2003+VC6 可以运行。 你也可以试试将 DebugBreak();用__asm int 3代替。
编译成功!下面是它们的反汇编代码: 可我还是有两个问题不明白。 1:编译器在这段代码上,还是走了两步废棋。 2:我不明白加上那句【__asm int 3】有什么用。 附言:老是这么叨扰您,都有点不好意思了。。。[/quote] 1:编译器不可能不走废棋。 2:加一句int 3(软件调试断点)指令,方便在浩如烟海的代码中调试执行时,暂停在此条指令处。(实际运行不调试时要去掉这条指令)
纹枰老妖 2014-05-28
  • 打赏
  • 举报
回复
引用 23 楼 zhao4zhong1 的回复:
[quote=引用 21 楼 wenpinglaoyao 的回复:] [quote=引用 20 楼 zhao4zhong1 的回复:] Windows Server 2003+VC6 可以运行。 你也可以试试将 DebugBreak();用__asm int 3代替。
编译成功!下面是它们的反汇编代码: 可我还是有两个问题不明白。 1:编译器在这段代码上,还是走了两步废棋。 2:我不明白加上那句【__asm int 3】有什么用。 附言:老是这么叨扰您,都有点不好意思了。。。[/quote] 1:编译器不可能不走废棋。 2:加一句int 3(软件调试断点)指令,方便在浩如烟海的代码中调试执行时,暂停在此条指令处。(实际运行不调试时要去掉这条指令)[/quote] 赵教主您好,百忙之中还能得到您的回复我很感激。但这个帖子我想晚段时间结。 最后,衷心祝您生活愉快! 【据我所闻,程序猿貌似经常加班,您还能在百忙之中天天来这里给我这些求助的人帮助,是在是令人感动。。。】
纹枰老妖 2014-05-28
  • 打赏
  • 举报
回复
引用 22 楼 fhqdx0012 的回复:
debug模式编译的时候会添加 部分变量或者空闲空间 调试时修改变量 中断等都比较方便 你看这个Release模式下代码 当想添加些指令 或者修改参数时就比较麻烦了 [quote=引用 13 楼 fhqdx0012 的回复:] 这是工程选项 /nologo /ML /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"Release/a.pch" /YX /Fo"Release/" /Fd"Release/" /FD /c 下的效果
[/quote] 不得你承认,您的这款编译器非常先进!首先,它跳过 i 直接把常量3推进栈里;其次,它根本没有顾及变量g的死活,因为【int g=0;】这句根本就没编译 。我说的对吗? 还有,像我这种入门菜鸟,一味纠结于编译上的原理,是不是有点事倍功半?
fhqdx0012 2014-05-28
  • 打赏
  • 举报
回复
debug模式编译的时候会添加 部分变量或者空闲空间 调试时修改变量 中断等都比较方便 你看这个Release模式下代码 当想添加些指令 或者修改参数时就比较麻烦了
引用 13 楼 fhqdx0012 的回复:
这是工程选项 /nologo /ML /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"Release/a.pch" /YX /Fo"Release/" /Fd"Release/" /FD /c 下的效果
赵4老师 2014-05-27
  • 打赏
  • 举报
回复
程序员的常识之一:不要将程序源代码或项目或exe放在桌面这种复杂(多半带空格和汉字且在防火墙或杀毒软件严密控制的C盘上)的目录下。
纹枰老妖 2014-05-27
  • 打赏
  • 举报
回复
引用 20 楼 zhao4zhong1 的回复:
Windows Server 2003+VC6
可以运行。
你也可以试试将
DebugBreak();用__asm int 3代替。

编译成功!下面是它们的反汇编代码:
可我还是有两个问题不明白。
1:编译器在这段代码上,还是走了两步废棋。
2:我不明白加上那句【__asm int 3】有什么用。

附言:老是这么叨扰您,都有点不好意思了。。。
赵4老师 2014-05-27
  • 打赏
  • 举报
回复
Windows Server 2003+VC6 可以运行。 你也可以试试将 DebugBreak();用__asm int 3代替。
纹枰老妖 2014-05-27
  • 打赏
  • 举报
回复
引用 18 楼 zhao4zhong1 的回复:
程序员的常识之一:不要将程序源代码或项目或exe放在桌面这种复杂(多半带空格和汉字且在防火墙或杀毒软件严密控制的C盘上)的目录下。


引用 18 楼 zhao4zhong1 的回复:
程序员的常识之一:不要将程序源代码或项目或exe放在桌面这种复杂(多半带空格和汉字且在防火墙或杀毒软件严密控制的C盘上)的目录下。


首先感谢您又教会我一个技能,但其实我的电脑早就是裸机上网了【因为有杀毒软件在,visual就无法开启调试功能,所以我删了杀毒软件】,下面是进程截图:
顺带问一句,您回复的那些源代码,在您的电脑上可以完美运行吗?
赵4老师 2014-05-26
  • 打赏
  • 举报
回复
虽然 凡是人造的东西都有缺陷。 编译器也是人写的,也有缺陷。 但是 永远不要低估编译器的智商。 永远不要拿编译器自动生成的汇编指令序列或P代码序列和人手工逐条写出的汇编指令序列或P代码序列比。 有干这两件事的工夫,不如结合编译原理相关书籍和论文或网页阅读gcc或g++相关源代码。
赵4老师 2014-05-26
  • 打赏
  • 举报
回复
#include <windows.h>
#include <stdio.h>
void budong(int a);
void main()
{
    int i=3;
    int g=0;
    DebugBreak();
    budong( i++ );
}
 
void budong(int a )
{
    printf("%d",a);
}
赵4老师 2014-05-26
  • 打赏
  • 举报
回复
引用 6 楼 wenpinglaoyao 的回复: 引用 5 楼 zhao4zhong1 的回复: DebugBreak The DebugBreak function causes a breakpoint exception to occur in the current process so that the calling thread can signal the debugger and force it to take some action. If the process is not being debugged, the search logic of a standard exception handler is used. In most cases, this causes the calling process to terminate because of an unhandled breakpoint exception. VOID DebugBreak(VOID) Parameters This function has no parameters. Return Values This function does not return a value. QuickInfo Windows NT: Requires version 3.1 or later. Windows: Requires Windows 95 or later. Windows CE: Requires version 1.0 or later. Header: Declared in winbase.h. Import Library: Use kernel32.lib. See Also Debugging Overview, Debugging Functions, DebugActiveProcess 我不会英文,不明白您在说些什么。
纹枰老妖 2014-05-26
  • 打赏
  • 举报
回复
引用 15 楼 zhao4zhong1 的回复:
#include <windows.h>
#include <stdio.h>
void budong(int a);
void main()
{
int i=3;
int g=0;
DebugBreak();
budong( i++ );
}

void budong(int a )
{
printf("%d",a);
}


您好,不知道是不是我机器的原因,对照您的代码,我比葫芦画瓢,依然是一个致命错误,看图片:
赵4老师 2014-05-25
  • 打赏
  • 举报
回复
DebugBreak The DebugBreak function causes a breakpoint exception to occur in the current process so that the calling thread can signal the debugger and force it to take some action. If the process is not being debugged, the search logic of a standard exception handler is used. In most cases, this causes the calling process to terminate because of an unhandled breakpoint exception. VOID DebugBreak(VOID) Parameters This function has no parameters. Return Values This function does not return a value. QuickInfo Windows NT: Requires version 3.1 or later. Windows: Requires Windows 95 or later. Windows CE: Requires version 1.0 or later. Header: Declared in winbase.h. Import Library: Use kernel32.lib. See Also Debugging Overview, Debugging Functions, DebugActiveProcess
fhqdx0012 2014-05-25
  • 打赏
  • 举报
回复

这是工程选项
/nologo /ML /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"Release/a.pch" /YX /Fo"Release/" /Fd"Release/" /FD /c
下的效果
fhqdx0012 2014-05-25
  • 打赏
  • 举报
回复
引用 11 楼 wenpinglaoyao 的回复:
[quote=引用 8 楼 fhqdx0012 的回复:] 这是开启大小优化的 反汇编
00401019 a.main        6A 03           push 0x3
0040101B               E8 E5FFFFFF     call a.00401005
00401020               59              pop ecx
00401021               C3              retn
00401022               CC              int3
00401023               CC              int3
00401024 a.budong      FF7424 04       push dword ptr ss:[esp+0x4]
00401028               68 30AA4000     push a.0040AA30                          ; ASCII "%d"
0040102D               E8 07000000     call a.printf
00401032               59              pop ecx
00401033               59              pop ecx
00401034               C3              retn

您的截图不够全面,或者说是不够大,我没有看到调用budong函数之前的反汇编代码【i++的】。[/quote] 这就是完整的反汇编代码
纹枰老妖 2014-05-25
  • 打赏
  • 举报
回复
引用 8 楼 fhqdx0012 的回复:
这是开启大小优化的 反汇编
00401019 a.main        6A 03           push 0x3
0040101B               E8 E5FFFFFF     call a.00401005
00401020               59              pop ecx
00401021               C3              retn
00401022               CC              int3
00401023               CC              int3
00401024 a.budong      FF7424 04       push dword ptr ss:[esp+0x4]
00401028               68 30AA4000     push a.0040AA30                          ; ASCII "%d"
0040102D               E8 07000000     call a.printf
00401032               59              pop ecx
00401033               59              pop ecx
00401034               C3              retn

您的截图不够全面,或者说是不够大,我没有看到调用budong函数之前的反汇编代码【i++的】。
纹枰老妖 2014-05-25
  • 打赏
  • 举报
回复
引用 7 楼 ForestDB 的回复:
我不是大神,不懂汇编也不懂编译原理,这里只就我观察到的东西,说点个人看法: i在[ebp - 4] g在[ebp - 8] 不知LZ有无注意到[ebp - 0Ch],这里只有i和g两个变量,何来的[ebp - 0Ch]? 所以我的解释就是: 这里实际上是int tmp = i;的汇编码,即为了演算i++,编译器生成了一个临时变量tmp,并以此tmp变量来调用函数; 然后单独对i做+1操作。 至于为什么要这么做,因为不懂编译原理,所以无法给出准确的答案, 不过有个猜测,就是这样实现比较容易。 另外看截图这应该是VC6,而且多半是DEBUG版本的;相信这种生成临时变量多半只是一种特定的实现,即换成RELEASE版本就会优化掉,或者换个编译器,就是LZ的想的那种实现。 我有试Mac下的gcc,它就是直接压栈然后自增i。
我相信编译器这样做,肯定有它自己的苦衷,我准备玩两天结贴【对满意答案我还抱一点希望】,莫介意。
dailongzhen 2014-05-25
  • 打赏
  • 举报
回复
引用 7 楼 ForestDB 的回复:
我不是大神,不懂汇编也不懂编译原理,这里只就我观察到的东西,说点个人看法: i在[ebp - 4] g在[ebp - 8] 不知LZ有无注意到[ebp - 0Ch],这里只有i和g两个变量,何来的[ebp - 0Ch]? 所以我的解释就是: 这里实际上是int tmp = i;的汇编码,即为了演算i++,编译器生成了一个临时变量tmp,并以此tmp变量来调用函数; 然后单独对i做+1操作。 至于为什么要这么做,因为不懂编译原理,所以无法给出准确的答案, 不过有个猜测,就是这样实现比较容易。 另外看截图这应该是VC6,而且多半是DEBUG版本的;相信这种生成临时变量多半只是一种特定的实现,即换成RELEASE版本就会优化掉,或者换个编译器,就是LZ的想的那种实现。 我有试Mac下的gcc,它就是直接压栈然后自增i。
比较赞同这种观点!
加载更多回复(7)

21,458

社区成员

发帖
与我相关
我的任务
社区描述
汇编语言(Assembly Language)是任何一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。
社区管理员
  • 汇编语言
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧