青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

posts - 319, comments - 22, trackbacks - 0, articles - 11
  C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

1 什么是堆棧

編譯器一般使用堆棧實現(xiàn)函數(shù)調(diào)用。堆棧是存儲器的一個區(qū)域,嵌入式環(huán)境有時需要程序員自己定義一個數(shù)組作為堆棧。Windows為每個線程自動維護一個堆棧,堆棧的大小可以設(shè)置。編譯器使用堆棧來堆放每個函數(shù)的參數(shù)、局部變量等信息。

函數(shù)調(diào)用經(jīng)常是嵌套的,在同一時刻,堆棧中會有多個函數(shù)的信息,每個函數(shù)占用一個連續(xù)的區(qū)域。一個函數(shù)占用的區(qū)域被稱作幀(frame)。

編譯器從高地址開始使用堆棧。 假設(shè)我們定義一個數(shù)組a[1024]作為堆棧空間,一開始棧頂指針指向a[1023]。如果棧里有兩個函數(shù)a和b,且a調(diào)用了b,棧頂指針會指向函數(shù)b的幀。如果函數(shù)b返回。棧頂指針就指向函數(shù)a的幀。如果在棧里放了太多東西造成溢出,破壞的是a[0]上面的東西。

在多線程(任務(wù))環(huán)境,CPU的堆棧指針指向的存儲器區(qū)域就是當前使用的堆棧。切換線程的一個重要工作,就是將堆棧指針設(shè)為當前線程的堆棧棧頂?shù)刂贰?/p>

不同CPU,不同編譯器的堆棧布局、函數(shù)調(diào)用方法都可能不同,但堆棧的基本概念是一樣的。

2 函數(shù)調(diào)用約定

函數(shù)調(diào)用約定包括傳遞參數(shù)的順序,誰負責(zé)清理參數(shù)占用的堆棧等,例如 :

 參數(shù)傳遞順序誰負責(zé)清理參數(shù)占用的堆棧
__pascal從左到右調(diào)用者
__stdcall從右到左被調(diào)函數(shù)
__cdecl從右到左調(diào)用者

調(diào)用函數(shù)的代碼和被調(diào)函數(shù)必須采用相同的函數(shù)的調(diào)用約定,程序才能正常運行。在Windows上,__cdecl是C/C++程序的缺省函數(shù)調(diào)用約定。

在有的cpu上,編譯器會用寄存器傳遞參數(shù),函數(shù)使用的堆棧由被調(diào)函數(shù)分配和釋放。這種調(diào)用約定在行為上和__cdecl有一個共同點:實參和形參數(shù)目不符不會導(dǎo)致堆棧錯誤。

不過,即使用寄存器傳遞參數(shù),編譯器在進入函數(shù)時,還是會將寄存器里的參數(shù)存入堆棧指定位置。參數(shù)和局部變量一樣應(yīng)該在堆棧中有一席之地。參數(shù)可以被理解為由調(diào)用函數(shù)指定初值的局部變量。

3 例子:__cdecl和__stdcall

不同的CPU,不同的編譯器,堆棧的布局可能是不同的。本文以x86,VC++的編譯器為例。

VC++編譯器的已經(jīng)不再支持__pascal, __fortran, __syscall等函數(shù)調(diào)用約定。目前只支持__cdecl和__stdcall。

采用__cdecl或__stdcall調(diào)用方式的程序,在剛進入子函數(shù)時,堆棧內(nèi)容是一樣的。esp指向的棧頂是返回地址。這是被call指令壓入堆棧的。下面是參數(shù),左邊參數(shù)在上,右邊參數(shù)在下(先入棧)。

如前表所示,__cdecl和__stdcall的區(qū)別是:__cdecl是調(diào)用者清理參數(shù)占用的堆棧,__stdcall是被調(diào)函數(shù)清理參數(shù)占用的堆棧。

由于__stdcall的被調(diào)函數(shù)在編譯時就必須知道傳入?yún)?shù)的準確數(shù)目(被調(diào)函數(shù)要清理堆棧),所以不能支持變參數(shù)函數(shù),例如printf。而且如果調(diào)用者使用了不正確的參數(shù)數(shù)目,會導(dǎo)致堆棧錯誤。

通過查看匯編代碼,__cdecl函數(shù)調(diào)用在call語句后會有一個堆棧調(diào)整語句,例如:

    a = 0x1234;
    b = 0x5678;
    c = add(a, b);

對應(yīng)x86匯編:

    mov dword ptr [ebp-4],1234h
    mov dword ptr [ebp-8],5678h
    mov eax,dword ptr [ebp-8]
    push eax
    mov ecx,dword ptr [ebp-4]
    push ecx
    call 0040100a
    add esp,8
    mov dword ptr [ebp-0Ch],eax


__stdcall的函數(shù)調(diào)用則不需要調(diào)整堆棧:

    call 00401005
    mov dword ptr [ebp-0Ch],eax

函數(shù)

    int __cdecl add(int a, int b)
    {
    return a+b;
    }

產(chǎn)生以下匯編代碼(Debug版本):

    push ebp
    mov ebp,esp
    sub esp,40h
    push ebx
    push esi
    push edi
    lea edi,[ebp-40h]
    mov ecx,10h
    mov eax,0CCCCCCCCh
    rep stos dword ptr [edi]
    mov eax,dword ptr [ebp+8]
    add eax,dword ptr [ebp+0Ch]
    pop edi
    pop esi
    pop ebx
    mov esp,ebp
    pop ebp
    ret // 跳轉(zhuǎn)到esp所指地址,并將esp+4,使esp指向進入函數(shù)時的第一個參數(shù)

再查看__stdcall函數(shù)的實現(xiàn),會發(fā)現(xiàn)與__cdecl函數(shù)只有最后一行不同:

    ret 8 // 執(zhí)行ret并清理參數(shù)占用的堆棧

對于調(diào)試版本,VC++編譯器在“直接調(diào)用地址”時會增加檢查esp的代碼,例如:

    ta = (TAdd)add; // TAdd定義:typedef int (__cdecl *TAdd)(int a, int b);
    c = ta(a, b);

產(chǎn)生以下匯編代碼:

    mov [ebp-10h],0040100a
    mov esi,esp
    mov ecx,dword ptr [ebp-8]
    push ecx
    mov edx,dword ptr [ebp-4]
    push edx
    call dword ptr [ebp-10h]
    add esp,8
    cmp esi,esp
    call __chkesp (004011e0)
    mov dword ptr [ebp-0Ch],eax

__chkesp 代碼如下。如果esp不等于函數(shù)調(diào)用前保存的值,就會轉(zhuǎn)到錯誤處理代碼。

    004011E0 jne __chkesp+3 (004011e3)
    004011E2 ret
    004011E3 ;錯誤處理代碼

__chkesp的錯誤處理會彈出對話框,報告函數(shù)調(diào)用造成esp值不正確。 Release版本的匯編代碼要簡潔得多。也不會增加 __chkesp。如果發(fā)生esp錯誤,程序會繼續(xù)運行,直到“遇到問題需要關(guān)閉”。

3 補充說明

函數(shù)調(diào)用約定只是“調(diào)用函數(shù)的代碼”和被調(diào)用函數(shù)之間的關(guān)系。

假設(shè)函數(shù)A是__stdcall,函數(shù)B調(diào)用函數(shù)A。你必須通過函數(shù)聲明告訴編譯器,函數(shù)A是__stdcall。編譯器自然會產(chǎn)生正確的調(diào)用代碼。

如果函數(shù)A是__stdcall。但在引用函數(shù)A的地方,你卻告訴編譯器,函數(shù)A是__cdecl方式,編譯器產(chǎn)生__cdecl方式的代碼,與函數(shù)A的調(diào)用約定不一致,就會發(fā)生錯誤。

以delphi調(diào)用VC函數(shù)為例,delphi的函數(shù)缺省采用__pascal約定,VC的函數(shù)缺省采用__cdecl約定。我們一般將VC的函數(shù)設(shè)為__stdcall,例如:

    int __stdcall add(int a, int b);

在delphi中將這個函數(shù)也聲明為__stdcall,就可以調(diào)用了:

    function add(a: Integer; b: Integer): Integer;
    stdcall; external 'a.dll';

因為考慮到可能被其它語言的程序調(diào)用,不少API采用__stdcall的調(diào)用約定。

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            久久久人成影片一区二区三区观看| 欧美福利视频网站| 老司机精品福利视频| 欧美中文在线视频| 久久精品国产第一区二区三区| 午夜精品久久久久久久久| 午夜天堂精品久久久久| 亚洲欧美视频一区二区三区| 欧美一区二区高清| 老巨人导航500精品| 亚洲福利专区| 亚洲高清资源| 在线亚洲精品福利网址导航| 亚洲欧美制服中文字幕| 久久久久九九视频| 欧美风情在线观看| 欧美激情 亚洲a∨综合| 国产精品国产三级国产专区53| 欧美综合国产精品久久丁香| 亚洲另类黄色| 一区二区激情| 一区二区三区四区蜜桃| 国产一区久久久| 国产精品久久久久久久久久尿| 免费久久99精品国产| 久久尤物视频| 亚洲免费视频网站| 激情亚洲网站| 99综合精品| 久久琪琪电影院| 亚洲毛片在线| 久久久777| 国产精品国产一区二区| 亚洲第一精品夜夜躁人人爽 | 亚洲中字黄色| 久久综合久久久| 一区二区三区欧美视频| 欧美aa在线视频| 狠狠色狠狠色综合日日小说| 亚洲一区二区黄色| 亚洲日本欧美| 麻豆成人精品| 国产一区二区中文字幕免费看| 亚洲综合视频网| 999亚洲国产精| 欧美另类亚洲| 99pao成人国产永久免费视频| 免费观看不卡av| 久久国产加勒比精品无码| 国产精品一区二区在线| 亚洲一区二区三区免费观看 | 国产精品久久久999| 亚洲精品乱码久久久久久蜜桃91| 久久先锋影音av| 欧美一乱一性一交一视频| 国产精品久久久亚洲一区| 99热在这里有精品免费| 欧美激情国产高清| 美女任你摸久久| 在线色欧美三级视频| 久热综合在线亚洲精品| 久久久99久久精品女同性| 国产有码在线一区二区视频| 欧美影片第一页| 国产色爱av资源综合区| 亚洲视频每日更新| 亚洲激情电影中文字幕| 蜜臀99久久精品久久久久久软件| 韩国一区二区三区在线观看 | 性欧美18~19sex高清播放| 99视频在线观看一区三区| 欧美国产一区二区在线观看| 99pao成人国产永久免费视频| 亚洲精品一二三区| 欧美揉bbbbb揉bbbbb| 亚洲免费一级电影| 午夜精品视频在线观看| 激情另类综合| 亚洲日本va午夜在线电影| 欧美日韩在线视频观看| 亚洲欧美日韩国产一区二区| 亚洲免费一在线| 在线欧美福利| 99riav久久精品riav| 国产模特精品视频久久久久 | 久久综合中文字幕| 亚洲精品日日夜夜| 一区二区三区视频在线 | 永久免费精品影视网站| 亚洲破处大片| 国产农村妇女毛片精品久久麻豆 | 欧美黄色一区二区| 欧美日韩色婷婷| 欧美一区二区在线播放| 久久香蕉精品| 亚洲制服av| 久久一二三四| 亚洲午夜精品国产| 久久亚洲精品一区| 篠田优中文在线播放第一区| 免费成人在线视频网站| 午夜在线成人av| 欧美高清视频免费观看| 久久成人18免费网站| 欧美精品在欧美一区二区少妇| 久久久91精品国产| 欧美日韩免费精品| 欧美成熟视频| 国产中文一区二区| 亚洲午夜在线视频| av成人免费在线观看| 久久国产手机看片| 亚洲午夜一区二区| 欧美成人精品一区二区三区| 欧美在线电影| 欧美视频不卡中文| 亚洲经典在线| 久热精品视频在线| 一本色道久久综合亚洲精品不卡| 国内精品视频一区| 中文av一区特黄| 亚洲免费观看在线观看| 久久久久国产精品午夜一区| 欧美亚洲免费电影| 欧美日韩伦理在线免费| 亚洲成人在线视频播放| 国产精品萝li| 亚洲免费成人| 日韩视频在线免费观看| 欧美成人精品不卡视频在线观看| 久久人人爽人人爽爽久久| 国产精品日韩欧美一区二区三区 | 亚洲国产专区| 91久久精品美女高潮| 久久综合九色99| 牛牛影视久久网| 在线精品视频一区二区| 久久视频免费观看| 美日韩精品免费| 亚洲成人中文| 欧美大片在线观看一区| 亚洲国产毛片完整版| 日韩写真在线| 欧美日韩人人澡狠狠躁视频| 日韩亚洲欧美在线观看| 亚洲一区综合| 国产啪精品视频| 久久精品视频在线看| 欧美国产专区| 夜夜嗨网站十八久久| 欧美日韩性视频在线| 一区二区三区高清在线| 欧美一站二站| 亚洲缚视频在线观看| 欧美激情视频在线播放 | 男人的天堂亚洲| 日韩午夜av| 欧美一区二区三区在线观看| 精品成人一区二区三区| 欧美极品在线视频| 一区二区三区国产在线| 欧美制服丝袜| 最新日韩在线视频| 国产精品久久久对白| 久久久xxx| 亚洲精品国产精品国自产在线 | 伊人色综合久久天天| 免费一级欧美片在线播放| 亚洲毛片在线| 久久久久欧美精品| 99在线|亚洲一区二区| 国产精品免费在线| 久久综合导航| 亚洲视频免费在线| 欧美一区激情| 精品成人一区二区三区四区| 欧美激情一区二区久久久| 亚洲一区二区三区激情| 欧美国产亚洲另类动漫| 久久久噜噜噜久噜久久 | 伊人精品在线| 欧美日韩中文精品| 久久精品伊人| 一本色道久久综合亚洲精品高清| 老鸭窝91久久精品色噜噜导演| 一本色道久久88综合亚洲精品ⅰ | 久久久免费精品| 日韩视频中文字幕| 欧美 日韩 国产精品免费观看| 亚洲视频一起| 亚洲韩国青草视频| 国产日韩欧美中文在线播放| 欧美日韩国产成人在线| 老司机午夜精品| 亚洲在线中文字幕| 亚洲人成艺术| 欧美1区2区3区| 久久久伊人欧美| 亚洲专区在线| 一本大道久久a久久综合婷婷|