摘要:主要谈谈vc里面函数调用汇编成汇编代码的情形,首先针对之前的一个小程序,说说vc编译器的优化。

例子程序:

#include <iostream>
using namespace std;
int main(int argc, char* argv[]) 

 int i=10; 
 int a = i; 
 cout << "i=" << a << endl;

//下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道 
 __asm  
 { 
  mov dword ptr [ebp-4], 20h 
 } 
 int b = i; 
 cout << "i=" << b << endl;

return 0;
}

这段代码很简洁,但汇编代码可不简洁,首先看看release模式下的汇编代码概况:

……

; 14   : 
; 15   :  //下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道 
; 16   :  __asm  
; 17   :  { 
; 18   :   mov dword ptr [ebp-4], 20h

mov DWORD PTR [ebp-4], 32   ; 00000020H

; 19   :  } 
; 20   :  int b = i; 
; 21   :  cout << "i=" << b << endl;

push 10     ; 0000000aH
 push OFFSET FLAT:??_C@_02HDOK@i?$DN?$AA@ ; `string'
 push OFFSET FLAT:?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A ; std::cout
 call ??6std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@PBD@Z ; std::operator<<
 add esp, 8
 mov ecx, eax
 call ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z ; std::basic_ostream<char,std::char_traits<char> >::operator<<
 mov esi, eax
 push 10     ; 0000000aH
 mov ecx, esi
 call ?put@?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV12@D@Z ; std::basic_ostream<char,std::char_traits<char> >::put
 mov ecx, DWORD PTR [esi]
 xor edi, edi

……

调用cout前面,直接一个push 10,这是函数调用前压参数的过程,压了个常数在里面,呵呵,其实i已经被修改了,但是编译器不知道,以为i仍然是10,顾做了优化,压参压了常量在里面。

再看看debug模式下的汇编代码情况:

16:       __asm
17:       {
18:           mov dword ptr [ebp-4], 20h
004017DE   mov         dword ptr [ebp-4],20h
19:       }
20:       int b = i;
004017E5   mov         edx,dword ptr [ebp-4]
004017E8   mov         dword ptr [ebp-0Ch],edx
21:       cout << "i=" << b << endl;
004017EB   push        offset @ILT+195(std::endl) (004010c8)
004017F0   mov         eax,dword ptr [ebp-0Ch]
004017F3   push        eax
004017F4   push        offset string "i=" (0046c01c)
004017F9   push        offset std::cout (00477a10)
004017FE   call        @ILT+640(std::operator<<) (00401285)
00401803   add         esp,8
00401806   mov         ecx,eax

b = i,赋值这句成了从i的地址去取值送往b了,

mov         edx,dword ptr [ebp-4]
mov         dword ptr [ebp-0Ch],edx

注意release版本是没有这两句的,所以现在b取值就是肯定正确的了,后面压参的时候,也把b地址指向的值压入了堆栈,呵呵,这也是之前说的为什么两个版本下运行结果不同的原因。

把这个程序稍加修改,开始我们下面的函数调用汇编浅析:

#include <iostream>

using namespace std;

int ChangNum(int, int);
int main(int argc, char* argv[]) 

 int i=10; 
 int a = i; 
 cout << "i=" << a << endl;

//下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道 
 __asm  
 { 
  mov dword ptr [ebp-4], 20h 
 } 
 int b = i; 
 cout << "i=" << b << endl; 
 ChangNum(50, 100);

return 0;
}

int ChangNum(int nParam, int nW)
{
 int i = 10; 
 int a = i; 
 cout << "i=" << a << endl;

__asm  
 { 
  mov dword ptr [ebp - 4], 20h
  mov dword ptr [ebp + 12], 0h 
 } 
 int b = i; 
 cout << "i=" << b << endl;

return 0;
}

主要看看函数调用那段的汇编代码:

1、函数调用点汇编代码:

23:       ChangNum(50, 100);
00401824   push        64h
00401826   push        32h
00401828   call        @ILT+590(ChangNum) (00401253)
0040182D   add         esp,8
分别是两个参数入栈,call这句有两个作用,下一行地址入栈,同时进行函数调用,最后一句是恢复栈空间,两个整型参数每个四字节,所以esp堆栈指针要加上8字节。

2、函数体中的汇编代码:

004018C0   push        ebp
004018C1   mov         ebp,esp
004018C3   sub         esp,4Ch
004018C6   push        ebx
004018C7   push        esi
004018C8   push        edi
004018C9   lea         edi,[ebp-4Ch]
004018CC   mov         ecx,13h
004018D1   mov         eax,0CCCCCCCCh
004018D6   rep stos    dword ptr [edi]
30:       int i = 10;
004018D8   mov         dword ptr [ebp-4],0Ah
31:       int a = i;
004018DF   mov         eax,dword ptr [ebp-4]
004018E2   mov         dword ptr [ebp-8],eax
32:       cout << "i=" << a << endl;
004018E5   push        offset @ILT+195(std::endl) (004010c8)
004018EA   mov         ecx,dword ptr [ebp-8]
004018ED   push        ecx
004018EE   push        offset string "i=" (0046c01c)
004018F3   push        offset std::cout (00477a10)
004018F8   call        @ILT+645(std::operator<<) (0040128a)
004018FD   add         esp,8
00401900   mov         ecx,eax
00401902   call        @ILT+250(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004010ff)
00401907   mov         ecx,eax
00401909   call        @ILT+475(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011e0)
33:
34:       __asm
35:       {
36:           mov dword ptr [ebp - 4], 20h
0040190E   mov         dword ptr [ebp-4],20h
37:           mov dword ptr [ebp + 12], 0h
00401915   mov         dword ptr [ebp+0Ch],0
38:       }
39:       int b = i;
0040191C   mov         edx,dword ptr [ebp-4]
0040191F   mov         dword ptr [ebp-0Ch],edx
40:       cout << "i=" << b << endl;
00401922   push        offset @ILT+195(std::endl) (004010c8)
00401927   mov         eax,dword ptr [ebp-0Ch]
0040192A   push        eax
0040192B   push        offset string "i=" (0046c01c)
00401930   push        offset std::cout (00477a10)
00401935   call        @ILT+645(std::operator<<) (0040128a)
0040193A   add         esp,8
0040193D   mov         ecx,eax
0040193F   call        @ILT+250(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004010ff)
00401944   mov         ecx,eax
00401946   call        @ILT+475(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011e0)
41:
42:       return 0;
0040194B   xor         eax,eax
43:   }
0040194D   pop         edi
0040194E   pop         esi
0040194F   pop         ebx
00401950   add         esp,4Ch
00401953   cmp         ebp,esp
00401955   call        __chkesp (00406df0)
0040195A   mov         esp,ebp
0040195C   pop         ebp
0040195D   ret
ebp入栈,然后将esp的值传给ebp,现在ebp是指向此时的堆栈了,注意后面除了函数返回前,ebp的值一直是固定的,通过这种机制来访问参数和局部变量,esp减少了一个比较大的值,留给局部变量使用的,然后是通用寄存器入栈,接着就是实际的工作的代码了,这里就不说了,到那个return后面再看,是通用寄存器出栈,esp恢复,ebp出栈,ret回到函数调用的下一条指令。

http://blog.csdn.net/magictong/article/details/3447982

VC 函数调用的 汇编代码 浅析的更多相关文章

  1. 浅析VS2010反汇编 VS 反汇编方法及常用汇编指令介绍 VS2015使用技巧 调试-反汇编 查看C语言代码对应的汇编代码

    浅析VS2010反汇编 2015年07月25日 21:53:11 阅读数:4374 第一篇 1. 如何进行反汇编 在调试的环境下,我们可以很方便地通过反汇编窗口查看程序生成的反汇编信息.如下图所示. ...

  2. 32位汇编第三讲,RadAsm,IDE的配置和使用,以及汇编代码注入方式

    32位汇编第三讲,RadAsm,IDE的配置和使用,以及汇编代码注入方式 一丶RadAsm的配置和使用 用了怎么长时间的命令行方式,我们发现了几个问题 1.没有代码提醒功能 2.编写代码很慢,记不住各 ...

  3. Mosquitto pub/sub服务实现代码浅析-主体框架

    Mosquitto 是一个IBM 开源pub/sub订阅发布协议 MQTT 的一个单机版实现(目前也只有单机版),MQTT主打轻便,比较适用于移动设备等上面,花费流量少,解析代价低.相对于XMPP等来 ...

  4. 分析一个C语言程序生成的汇编代码-《Linux内核分析》Week1作业

    署名信息 郭春阳 原创作品转载请注明出处 :<Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 C源码 这 ...

  5. 在汇编代码中调用C函数

    对于ARM体系来说,不同语言撰写的函数之间相互调用(mix calls)遵循的是 ATPCS(ARM-Thumb Procedure Call Standard),ATPCS主要是定义了函数呼叫时参数 ...

  6. for循环产生的Cortex-M3汇编代码的一个奇怪现象

    最近比较一下KEIL和IAR两个编译器产生的代码,基于Cortex-M3处理器的,然后发现了一几个奇怪的地方. 很简单的一个C的for循环 void fun_for_add_65535(void) { ...

  7. C函数调用与栈--代码真相

    前面详细的说了,C函数调用的过程中,栈的变化情况的原理部分,这里在看一下汇编代码的真正的实现. 有关前面的那一片博客,主要记住的就是函数调用时栈的变化,4+3+2的步骤: (1)设置栈帧边界 (2)开 ...

  8. VS2005混合编译ARM汇编代码-转

    原文地址:http://blog.csdn.net/annelcf/article/details/5468093 公司HW team有人希望可以给他们写一个在WinCE上,单独读写DDR的工具,以方 ...

  9. 第一周:通过汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的

    姓名:吕松鸿 学号:20135229 ( *原创作品转载请注明出处*) ( 学习课程:<Linux内核分析>MOOC课程http://mooc.study.163.com/course/U ...

随机推荐

  1. 不要放弃使用border-box

    不知道有多少老前端像我这样,在项目中很少使用box-sizing这个属性值.因为CSS2.1中只有content-box这一种盒子模式,在CSS3还没有流行的时候,大家在工作中大量基于这种盒子模式写C ...

  2. Qt 元对象系统(Meta-Object System)(不管是否使用信号槽,都推荐使用)

    Qt 元对象系统(Meta-Object System) Qt的元对象系统基于如下三件事情: 类:QObject,为所有需要利用原对象系统的对象提供了一个基类. 宏:Q_OBJECT,通常可以声明在类 ...

  3. hexo从零配置next全纪录

    1.按照官网按照hexo: 2.下载next(目前使用的是最新发布版本6.4.1),解压后重命名为next,放在hexo工程themes目录下: 3.网站配置文件_config.yml中,改成them ...

  4. Android 升级下载 它们的定义Updates 兼容版本

    Android 更新模块 它们的定义Update 写这个总结是由于在项目中碰到了Android系统兼容的BUG   Android项目原本使用的是API提供的下载方法   例如以下: Download ...

  5. 强烈推荐node包colors

    库链接:colors 在你的 node.js 控制台中获取颜色

  6. 线性方程组的求解(C++)

    1. 最佳求解方案 Most efficient way to solve a system of linear equations 求解形如 Ax=b 的最佳方式 将 A 分解为三角矩阵,A=M1⋅ ...

  7. 给 Web 开发人员推荐的通用独立 UI 组件(一)(按钮很不错)

    现代 Web 开发在将体验和功能做到极致的同时,对于美观的追求也越来越高.在推荐完图形库之后,再来推荐一些精品的独立 UI 组件.这些组件可组合在一起,形成美观而交互强大的 Web UI . 给 We ...

  8. 学习vi和vim编辑(4):高速移动定位

    平时.第一步是编辑文本需要做将光标移动到需要编辑.因此,根据需要,将光标移动到目标数字键来编辑文本的速度在一定程度上. 一篇文章.主要介绍怎样高速移动光标. 依据屏幕来移动: 在一个有几千行文本的文件 ...

  9. 重构qDebug()<<,使log输出到文件

    重构qDebug()<<,使log输出到文件 #include <QProcessEnvironment> #include <QDateTime> #includ ...

  10. wpf版权限管理

    之前做的权限管理是基于Mvc的Web项目,模型.仓储及业务层次分明,6月中旬开始使用这套之前完成的底层架构开发Wpf版本的权限管理软件(后续将成熟企管系统进行抽象业务加入到该版本中,向企管系统靠近) ...