摘要:主要谈谈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. 【17.76%】【codeforces round 382C】Tennis Championship

    time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...

  2. In partitioned databases, trading some consistency for availability can lead to dramatic improvements in scalability.

    In partitioned databases, trading some consistency for availability can lead to dramatic improvement ...

  3. 实现在 .net 中使用 HttpClient 下载文件时显示进度

    在 .net framework 中,要实现下载文件并显示进度的话,最简单的做法是使用 WebClient 类.订阅 DownloadProgressChanged 事件就行了. 但是很可惜,WebC ...

  4. matlab gabor 滤波器

    0. gabor 基本原理 1. matlab 内置对 gabor 的支持 gabor:Create Gabor filter or Gabor filter bank g = gabor(wavel ...

  5. WPF制作Logo,很爽,今后在应用程序中加入Logo轻松,省事!

    原文:WPF制作Logo,很爽,今后在应用程序中加入Logo轻松,省事! 这是效果: XAML代码:<Viewbox Width="723.955078" Height=&q ...

  6. OpenCV 图像白平衡算法(相机自动白平衡)

    彩色相机内部有三个CCD电子耦合元件,分别用来感受红绿蓝三中颜色的光线,默认情况下,三个颜色的感光电路信号的放大比例是1:1:1的.在理想的拍摄环境下,纯白色的RGB分量按照1:1:1的比例放大之后, ...

  7. sklearn、theano、TensorFlow 以及 theras 的理解

    sklearn ⇒ 机器学习算法和模型: theras theano TensorFlow 1. 理解模型以及函数,参数返回值的实际意义 一定要注意模型的构造函数,接收的参数列表,以及该模型本身所要解 ...

  8. WPF 圆角textbox

    原文:WPF 圆角textbox 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/a771948524/article/details/9245965 ...

  9. WPF3D绘图的基础

    原文:WPF3D绘图的基础 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/m0_37591671/article/details/69487096 ...

  10. WinRAR 5.50 简体中文正式版发布(20多项改进)

    感谢ikimi的投递 流行好用的压缩工具,支持鼠标拖放及外壳扩展,完美支持 ZIP 档案,内置程序可以解开 CAB.ARJ.LZH.TAR.GZ.ACE.UUE.BZ2.JAR.ISO 等多种类型的压 ...