最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語(yǔ)言詳盡圖解函數(shù)棧幀的創(chuàng)建和銷(xiāo)毀實(shí)現(xiàn)

 更新時(shí)間:2022年05月06日 14:56:21   作者:利刃Cc  
我們知道c語(yǔ)言中函數(shù)都是被調(diào)用的,main函數(shù)里面能調(diào)用其他函數(shù),其實(shí)main函數(shù)也是被別的函數(shù)調(diào)用的,下面通過(guò)本文給大家分享c語(yǔ)言函數(shù)棧幀的創(chuàng)建和銷(xiāo)毀過(guò)程,一起看看吧

注:本文章所使用的編譯器是VS2010,由于不同編譯器的函數(shù)棧幀與銷(xiāo)毀略有差異,所以具體細(xì)節(jié)請(qǐng)讀者自行實(shí)踐!

常見(jiàn)寄存器

寄存器有:eax、ebx、ecx、edx、edi、esi、ebp、esp

其中 ebp 和 esp 是用來(lái)維護(hù)函數(shù)棧幀的,他們里面存放的是地址。

他們維護(hù)的是某個(gè)正在被調(diào)用的函數(shù)。通常我們又稱 ebp 為棧底指針,稱 esp 為棧頂指針

基本的匯編語(yǔ)言知識(shí)

push:壓棧

pop:出棧

mov:若有變量a,b,則把b的值賦給a

ret:返回主程序

call:調(diào)用子程序

add:相加

sub:相減

lea:裝入有效地址

具體實(shí)現(xiàn)

我們用一個(gè)簡(jiǎn)單的例子來(lái)展示:

#include<stdio.h>
int Add(int x,int y)
{
    int z=0;
    z=x+y;
    return z;
}
int main()
{
    int a=0;
    int b=20;
    int c=0;
    c=Add(a,b);
    printf("%d\n",c);
    return 0;
}

注:每一個(gè)函數(shù)調(diào)用都會(huì)在棧區(qū)創(chuàng)建一個(gè)空間

我們?cè)谶@里假設(shè)從下到上是高地址到低地址的方向

通過(guò)我們上述介紹的ebp和esp,我們把他們添加上去后的效果則為:

那么有一個(gè)問(wèn)題:main函數(shù)是誰(shuí)調(diào)用的?

為了解決這個(gè)問(wèn)題,我們打開(kāi)編譯器然后進(jìn)行調(diào)試,打開(kāi)調(diào)用堆棧功能

發(fā)現(xiàn)這里居然有兩個(gè)函數(shù),一個(gè)是 __tmainCRTStartup(),還有一個(gè)是mainCRTStartup()。通過(guò)頭文件的查找,發(fā)現(xiàn)了以下的關(guān)系:

main函數(shù)被__tmainCRTStartup()調(diào)用,而__tmainCRTStartup()被mainCRTStartup()調(diào)用。所以,我們?cè)诜峙淇臻g時(shí),要為_(kāi)_tmainCRTStartup函數(shù)以及mainCRTStartup函數(shù)分配一塊空間。

接下來(lái)開(kāi)始通過(guò)反匯編來(lái)觀察棧幀空間分配:

通過(guò)我們之前的了解,在開(kāi)辟main之前先開(kāi)辟了__tmainCRTStartup,所以我們來(lái)為其分配空間:

先來(lái)看前三步,分別是push:壓棧和mov:賦值和sub:減法

第一步把ebp放到了棧頂,然后在壓棧同時(shí)esp會(huì)自動(dòng)向上追蹤棧頂,所以esp向上移動(dòng)一個(gè),第二步是將esp賦給ebp,所以ebp指針指向棧頂,第三步是esp指針的地址減少0E4h(八進(jìn)制),所以esp指向了上面某一塊位置,然后將中間這塊空間騰出來(lái)讓給了main函數(shù),而開(kāi)辟的大小取決于編譯器。

效果如下:

接下來(lái)push三次

接下來(lái)的四步:lea這步操作就是讓[ebp-0E4h]這個(gè)值放入edi內(nèi),然后通過(guò)觀察我們可以發(fā)現(xiàn),此時(shí)放入新值后的edi所指向的就是對(duì)應(yīng)在進(jìn)行push三個(gè)寄存器ebx、esi、edi操作前的esp的位置,然后將39h賦給ecx,0CCCCCCCCh賦給eax,然后第四步就是將edi地址向下的39h個(gè)dword中全部放入0CCCCCCCCh。

這些步驟就開(kāi)辟了main函數(shù)!看接下來(lái)的代碼:

將10放到了ebp-8的位置,也就是ebp向上八個(gè)字節(jié)的位置,然后將20放到ebp-20的 位置,將0放到ebp-32的位置,如圖:

接下來(lái)是add函數(shù)的反匯編代碼:

這里把ebp-20也就是b的值放到了eax中,然后壓棧。接著把ebp-8也就是a 的值放到了ecx中,然后壓棧。

然后就是call就跳到了add這個(gè)函數(shù)的地址處去,注意,該處call后進(jìn)行一個(gè)壓棧操作,將add后面一步的地址放在該棧位:

這種做法是為了調(diào)用完add后返回時(shí)需要找回原來(lái)的地址,所以需要在此處壓一個(gè)地址,以便add跳回時(shí)尋址,才能往下執(zhí)行。接下來(lái)才是add函數(shù)的內(nèi)容:

前幾步的操作是為了給add函數(shù)開(kāi)辟空間,這和開(kāi)辟main函數(shù)是一樣的,所以這里略過(guò):

接下來(lái)就是將0賦給ebp-8的位置,然后把ebp+8也就是剛才傳參過(guò)來(lái)的x,放到eax里,然后把ebp+12就是形參y與eax相加,最后把eax放到ebp-8也就是z的位置:

最后看這個(gè):

首先ebp-8也就是z放到eax,這樣子就防止銷(xiāo)毀add后數(shù)據(jù)也沒(méi)了。

然后就是edi、esi、ebx的pop,然后把esp移到ebp的位置,最后彈出ebp。

最后是ret。我們知道,當(dāng)運(yùn)行完call指令后會(huì)跳轉(zhuǎn)到下面的代碼繼續(xù)執(zhí)行,這個(gè)時(shí)候就可以知道當(dāng)時(shí)存的call指令下一條指令地址的用處了,而ret就是讓其退出后執(zhí)行這一操作的代碼。

ret執(zhí)行完后會(huì)pop,于是esp又會(huì)+4,向下移動(dòng),如圖:

然后回到main函數(shù)

繼續(xù)執(zhí)行以下步驟將eax里面的值(就是之前算出的30),mov放入到[ebp-20h]的位置里(也就是放入c中)。

接下來(lái)程序運(yùn)行完后就是main函數(shù)的銷(xiāo)毀,與之前Add函數(shù)銷(xiāo)毀步驟大致相同,就不再贅述了。

關(guān)于棧幀創(chuàng)建與銷(xiāo)毀的問(wèn)答題

到此這篇關(guān)于C語(yǔ)言詳盡圖解函數(shù)棧幀的創(chuàng)建和銷(xiāo)毀實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)C語(yǔ)言函數(shù)棧幀內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳細(xì)分析c++ const 指針與指向const的指針

    詳細(xì)分析c++ const 指針與指向const的指針

    這篇文章主要介紹了c++ const 指針與指向const的指針的相關(guān)資料,文中示例代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • C語(yǔ)言 二叉樹(shù)的鏈?zhǔn)酱鎯?chǔ)實(shí)例

    C語(yǔ)言 二叉樹(shù)的鏈?zhǔn)酱鎯?chǔ)實(shí)例

    本篇文章主要介紹C語(yǔ)言中二叉樹(shù)的鏈?zhǔn)酱鎯?chǔ),這里提供了一個(gè)實(shí)例代碼進(jìn)行參考,這樣對(duì)二叉樹(shù)的鏈?zhǔn)酱鎯?chǔ)有更深入的了解,希望能幫到學(xué)習(xí)這塊知識(shí)的同學(xué)
    2016-07-07
  • 指針與const限定符的使用分析

    指針與const限定符的使用分析

    本篇文章對(duì)指針與const限定符的使用進(jìn)行了分析介紹。需要的朋友參考下
    2013-05-05
  • C/C++判斷素?cái)?shù)的三種方法

    C/C++判斷素?cái)?shù)的三種方法

    這篇文章主要給大家介紹了C/C++判斷素?cái)?shù)的三種方法,常規(guī)的函數(shù)判斷法,埃氏篩法和歐拉篩法這三種方法,并通過(guò)代碼示例講解的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下
    2023-12-12
  • Qt實(shí)戰(zhàn)案例之如何利用QProcess類(lèi)實(shí)現(xiàn)啟動(dòng)進(jìn)程

    Qt實(shí)戰(zhàn)案例之如何利用QProcess類(lèi)實(shí)現(xiàn)啟動(dòng)進(jìn)程

    這篇文章主要介紹了Qt實(shí)戰(zhàn)案例之如何利用QProcess類(lèi)實(shí)現(xiàn)啟動(dòng)進(jìn)程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-02-02
  • C++實(shí)現(xiàn)LeetCode(28.實(shí)現(xiàn)strStr()函數(shù))

    C++實(shí)現(xiàn)LeetCode(28.實(shí)現(xiàn)strStr()函數(shù))

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(28.實(shí)現(xiàn)strStr()函數(shù)),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C++去除輸入行中空白的方法

    C++去除輸入行中空白的方法

    這篇文章主要介紹了C++去除輸入行中空白的方法,涉及C++針對(duì)數(shù)組的遍歷與替換的相關(guān)使用技巧,需要的朋友可以參考下
    2015-07-07
  • C++ AVLTree高度平衡的二叉搜索樹(shù)深入分析

    C++ AVLTree高度平衡的二叉搜索樹(shù)深入分析

    這篇文章主要介紹了C++ AVLTree高度平衡的二叉搜索樹(shù),二叉搜索樹(shù)雖可以縮短查找的效率,但如果數(shù)據(jù)有序或接近有序二叉搜索樹(shù)將退化為單支樹(shù),查找元素相當(dāng)于在順序表中搜索元素,效率低下
    2023-03-03
  • VC++ 自定義控件的建立及使用方法

    VC++ 自定義控件的建立及使用方法

    這篇文章主要介紹了VC++ 自定義控件的建立及使用方法的相關(guān)資料,十分的詳細(xì),需要的朋友可以參考下
    2015-06-06
  • Qt數(shù)據(jù)庫(kù)應(yīng)用之超級(jí)自定義委托

    Qt數(shù)據(jù)庫(kù)應(yīng)用之超級(jí)自定義委托

    Qt中需要用到自定義委托的情形很多,比如提供下拉框選擇,進(jìn)度條展示下載進(jìn)度啥的,默認(rèn)的單元格是沒(méi)有這些效果的,需要自己?jiǎn)为?dú)用委托的形式來(lái)展示。本文將為大家介紹Qt中如何進(jìn)行超級(jí)自定義委托,需要的可以參考一下
    2022-03-03

最新評(píng)論

修水县| 常州市| 宁安市| 汝阳县| 屯留县| 灌云县| 广德县| 怀集县| 富宁县| 紫云| 浑源县| 台北市| 镇康县| 全南县| 葫芦岛市| 安图县| 鲁甸县| 遂平县| 吴江市| 凤庆县| 平乐县| 陆川县| 横峰县| 五寨县| 潼南县| 泰州市| 天柱县| 芮城县| 宣恩县| 天津市| 澄迈县| 洪洞县| 汤原县| 柘城县| 桦川县| 兴山县| 凤山市| 抚顺县| 慈利县| 冕宁县| 甘谷县|