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.pswp.cn/news/449620.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/449620.shtml
英文地址,請注明出處:http://en.pswp.cn/news/449620.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

保存tushare所有股票數據,并對漲停進行分析

import tushare as ts import pandas as pd import time import os import datetime # 指定自己要存放文件的絕對路徑 os.chdir(E:/) pd.set_option(expand_frame_repr, False) now_time datetime.date.today() # 從tushare獲取指定日期 def get_today_all_ts(date):date_now …

重命名 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 選擇文本&…

java操作elasticsearch實現前綴查詢、wildcard、fuzzy模糊查詢、ids查詢

1、前綴查詢&#xff08;prefix&#xff09; //prefix前綴查詢Testpublic void test15() throws UnknownHostException {//1、指定es集群 cluster.name 是固定的key值&#xff0c;my-application是ES集群的名稱Settings settings Settings.builder().put("cluster.name&…

tushare查看a股是否跌到位

#%%#獲取上證指數歷史行情數據#獲取上證指數歷史行情數據 import tushare as ts import pandas as pd # 設置token&#xff0c;只需要在第一次調用或者token失效時設置 # 設置完成后&#xff0c;之后就不再需要這一個命令了 ts.set_token() pro ts.pro_api() df_daily pro.in…

為什么我要轉載文章?

在csdn上很多年&#xff0c;學習了許多&#xff0c;也教了人許多&#xff0c;但最近&#xff0c;大家發現&#xff0c;我轉載了大量文章&#xff0c;而很少原創文章&#xff0c;真正的有水平且自己一個字一個字敲鍵盤出來的&#xff0c;1000字要三四個小時&#xff0c;如果包含…

Docker 從Dockerfile 構建鏡像 :build 命令的用法

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 Dockerfile 創建完成后&#xff0c;可以使用 docker build 命令根據 Dockerfile 構建一個鏡像。 1. 首先準備好 Dockerfile : 2. 執行構…

(翻譯).NET應用架構

.NET應用架構 Kalyan Bandarupalli著&#xff0c;hystar翻譯 這個系列文章將幫助.NET開發人員與架構師使用最新的.NET技術設計高效的.NET應用。關于應用架構這方面雖然已有很多文章與書籍&#xff0c;但是對于設計人員理解應用設計的最佳的原則與實踐仍然是具有挑戰性的。這篇…

activity idea編寫bpmn流程文件

idea 的bpmn插件支持不好&#xff0c;1、畫流程圖&#xff0c;注意排他網關流程的條件&#xff0c;2、復制一份xml文件出來&#xff0c;頭部替換&#xff1a;<?xml version"1.0" encoding"UTF-8"?> <definitions xmlns"http://www.omg.org…

tushare寫三因子模型

CAPM模型經歷了大量的實證和應用之后&#xff0c;有證據表明&#xff0c;市場風險溢酬并不能充分解釋個別風險資產的收益率。于是很多研究者開始探索其他的因素&#xff0c;比如公司市值、PE、杠桿比例、賬面市值比等。Fama和French兩個人對于各種因素進行了全面的組合分析&…

Duplicate entry ‘XXX‘ for key

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 報錯如題&#xff1a;Duplicate entry XXX for key 意思是說有唯一約束&#xff0c;所以不能重復。 而我的情況是&#xff0c;有兩個表…

list c++template

以一個現成的模板實現了線性表的順序結構實現&#xff0c;VC6.0調試OK 請大家以開源的方式來完善這個算法 &#xff0c;以跟貼方式來添加代碼 請大家往這個下面繼續添加完整的可以運行的線性表的順序結構實現代碼 /* 線性表的順序結構實現&#xff0c;數組C實現法&#xff0c;V…

聊聊composer.lock

composer.lock 即鎖定文件 其中會存在項目中所有的依賴包&#xff0c;方便協同合作時都得到同樣的以來版本 composer install 命令從當前目錄讀取 composer.json 文件&#xff0c;處理依賴關系&#xff0c;并把依賴安裝到 vendor 目錄下。 如果當前目錄下存在 composer.lock 文…

如何保證MongoDB的安全性?

上周寫了個簡短的新聞《MongoDB裸奔&#xff0c;2億國人求職簡歷泄漏&#xff01;》&#xff1a; 根據安全站點HackenProof的報告&#xff0c;由于MongoDB數據庫沒有采取任何安全保護措施&#xff0c;導致共計202,730,434份國人求職簡歷泄漏。然后很多人評論說MongoDB躺槍了。 …

LXC是什么

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。Linux Container容器是一種內核虛擬化技術&#xff0c;可以提供輕量級的虛擬化&#xff0c;以便隔離進程和資源。LXC為Linux Container的簡…

C++ 標準庫 vector list map使用方法

[cpp] view plaincopyList&#xff08;鏈表&#xff09; List將元素按順序儲存在鏈表中. 與 向量(vectors)相比, 它允許快速的插入和刪除&#xff0c;但是隨機訪問卻比較慢.list對象函數 assign() 給list賦值 back() 返回最后一個元素 begin() 返回指向第一個元素的迭代器…

導航守衛

導航守衛 to 準備跳轉到哪個頁面 from 從哪個頁面中離開 next 函數 全局守衛 router.beforeEach((to,from,next) > {if(to.path /login || to.path /register){    next();}else{    alert(先登錄)    next(/login)} }) 組件守衛 data () {  return{   …

Django中使用Pagination的分頁范例源碼

將做工程過程重要的內容做個珍藏&#xff0c;下面代碼內容是關于Django中使用Pagination的分頁范例的代碼。 from django.core.paginator import Paginatorobjects [john, paul, george, ringo]p Paginator(objects, 2) p.count4p.num_pages2p.page_range[1, 2] page1 p.pag…

Docker:集裝箱式“運輸”在軟件上的實現

Docker是由PaaS提供商dotCloud在2013年年初創建的一款開源應用引擎&#xff0c;Docker可以自動將任何應用打包成輕量、可移植、自包涵的容器引擎。開發者構建的應用可以一次構建全平臺運行&#xff0c;包括本地開發機器&#xff0c;生產環境&#xff0c;虛擬機和云等。 Docker基…

CAMP選股

挑選五只股票&#xff1a;萬科A、中國平安、貴州茅臺、萬華化學和科大訊飛&#xff0c;然后我們以滬深300作為市場基準。import pandas as pd import tushare as ts # 獲取數據 pro ts.pro_api() wanke pro.daily(ts_code000002.SZ, start_date20170101) pingan pro.daily(t…