• <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>
            理解程序內存一文中我們介紹了普通程序運行時在內存中的布局,下面我們專門針對C++源代碼以WinDbg為工具分析下C++程序的變量存儲模型, 要理解下面的知識,請先看懂理解程序內存一文。

            下面我們嘗試分析C++變量的存儲模型, 我們的測試程序非常簡單:
            #include <iostream>

            using namespace  std;

            const char* global_const_string = "hello world";
            int global_int = 20;
            static int global_static_int = 30;
            int main() 
            {
            static int local_static_int = 100;
            int local_int = 200;
            int* pValue = new int(300);
            cout << global_const_string << global_int 
            << global_static_int << local_static_int 
            << local_int << *pValue;
            delete pValue;
            system("pause");
            return 0;
            }

            可以看到我們上面對程序雖然簡單,但是基本包括了所有的變量類型,包括靜態的,常量的,全局的,本地的,還有new出來的,下面我們依次分析每個變量所屬的存儲區域。

            我們直接用WinDbg以源碼的方式調試我們的測試程序consoleTest.exe.
            首先我們分析下consoleTest.exe模塊的起始地址及內部數據節的分布情況, 通過!address命令:
            *   400000   401000     1000 MEM_IMAGE   MEM_COMMIT  PAGE_READONLY                      Image "ConsoleTest.exe"
            |-  401000   41d000    1c000 MEM_IMAGE   MEM_COMMIT  PAGE_EXECUTE_READ                  Image "ConsoleTest.exe"
            |-  41d000   422000     5000 MEM_IMAGE   MEM_COMMIT  PAGE_READONLY                      Image "ConsoleTest.exe"
            |-  422000   426000     4000 MEM_IMAGE   MEM_COMMIT  PAGE_WRITECOPY                     Image "ConsoleTest.exe"
            |-  426000   427000     1000 MEM_IMAGE   MEM_COMMIT  PAGE_READONLY                      Image "ConsoleTest.exe"
            可以看到consoleTest.exe模塊在內存中的起始地址是0x400000, 接下來可以通過!dh 0x400000分析它內部的數據節分布, 并且最終我們可以得出如下結論:
            地址 400000 - 401000 : PE文件頭,屬性是只讀
            地址 401000 - 41d000 : .text, 屬性是只讀可執行,表示代碼節
            地址 41d000 -  422000 : .rdata, 屬性是只讀, 表示只讀數據
            地址 422000 -  426000 : .data, 屬性是寫入時拷貝,表示可讀寫數據
            地址 426000 - 427000 : .rsrc, 屬性是只讀,表示資源節

            通過!address -f:stack命令我們可以看到:
            0:000> !address -f:stack
              BaseAddr EndAddr+1 RgnSize     Type       State                 Protect             Usage
            -------------------------------------------------------------------------------------------
               40000   13d000    fd000 MEM_PRIVATE MEM_RESERVE                                    Stack [8b0.1d0; ~0]
              13d000   13e000     1000 MEM_PRIVATE MEM_COMMIT  PAGE_READWRITE|PAGE_GUARD          Stack [8b0.1d0; ~0]
              13e000   140000     2000 MEM_PRIVATE MEM_COMMIT  PAGE_READWRITE                     Stack [8b0.1d0; ~0]
            可以看到我們主線程的堆棧起始地址是: 13e000 - 140000

            接下來我們首先分析所有全局變量的存儲區域, 通過x consoletest!global*命令,讓調試器列出所有在consoletest模塊中global開頭的調試符號:
            0:000> x consoletest!global*
            00422000 ConsoleTest!global_const_string = 0x0041d1dc "hello world"
            00422004 ConsoleTest!global_int = 0n20
            00422008 ConsoleTest!global_static_int = 0n30
            004238a0 ConsoleTest!global_locale = 0x00000000
            通過分析我們可以看到我們的3個全局變量global_const_string, global_int, global_static_int全都分布在422000 - 426000之間的.data可讀寫數據節中。
            而global_const_string所指向的內容
            0x0041d1dc "hello world"
            則分布在41d000 -  422000 之間的.rdata只讀數據節中,這個結論也符合我們平時關于全局變量存儲區域的理解。

            下面我們再嘗試分析局部變量的存儲區域,再main函數內部cout的地方設置斷點,然后讓程序運行到此, 然后輸入dv /t /i /v命令查看所有局部變量, 可以看到
            0:000> dv /t /i /v
            prv local  0042200c int local_static_int = 0n100
            prv local  0013ff70 int local_int = 0n200
            prv local  0013ff74 int * pValue = 0x02248ff8
            我們可以看到local_static_int也分布在422000 - 426000之間的.data可讀寫數據節中, 而local_int和pValue則都存儲在13e000 - 140000之間的堆棧區域上。

            而指針pValue所指向的地址0x02248ff8我們可以通過!address 
            0x02248ff8命令來分析, 結果是:
            0:000> !address 0x02248ff8

            Usage:                  Heap
            Allocation Base:        021d0000
            Base Address:           02248000
            End Address:            02249000
            Region Size:            00001000
            Type:                   00020000    MEM_PRIVATE
            State:                  00001000    MEM_COMMIT
            Protect:                00000004    PAGE_READWRITE
            More info:              !heap -p 0x21d1000
            More info:              !heap -p -a 0x2248ff8
            可以看到地址0x02248ff8是在堆(heap)上面。

            通過上面的分析,我們驗證了平時C++書上關于各種類型變量存儲區域的假設,簡單來說就是全局變量和靜態變量會被編譯到可執行文件的數據節(分只讀和可讀寫)中, 非靜態的局部變量則分配在堆棧(stack)上,而new(malloc)出來的內存則分配在堆(heap)上。
            posted on 2012-09-20 21:57 Richard Wei 閱讀(2470) 評論(0)  編輯 收藏 引用 所屬分類: C++
            婷婷综合久久狠狠色99h| 婷婷久久久亚洲欧洲日产国码AV| 国产婷婷成人久久Av免费高清| 久久精品国产清自在天天线| 久久亚洲中文字幕精品有坂深雪| 无码AV中文字幕久久专区| 精品久久久久久国产潘金莲 | 久久综合九色综合网站| 久久精品国产亚洲AV蜜臀色欲| 免费观看久久精彩视频| 精品久久久久久无码中文野结衣| 伊人久久大香线蕉无码麻豆| 99久久国产免费福利| 亚洲中文久久精品无码ww16| 93精91精品国产综合久久香蕉| 久久久久久久综合综合狠狠| 久久国产精品99精品国产| 亚洲欧洲精品成人久久曰影片| 久久不射电影网| 久久久久久无码Av成人影院| 日本WV一本一道久久香蕉| 亚洲国产成人久久综合碰碰动漫3d | 久久精品国产精品亚洲| 久久香蕉超碰97国产精品| 污污内射久久一区二区欧美日韩 | 久久香蕉国产线看观看乱码| 久久笫一福利免费导航 | 久久久久人妻一区二区三区vr| 亚洲国产成人久久综合野外| 伊人久久大香线焦综合四虎| 日韩精品久久久久久久电影蜜臀| 亚洲精品99久久久久中文字幕| 成人精品一区二区久久久| 久久国产亚洲精品无码| 亚洲精品无码久久千人斩| 久久久久久久女国产乱让韩 | 99re这里只有精品热久久 | 国产成人久久精品麻豆一区| 久久精品国产免费| 91精品婷婷国产综合久久| 国产成人无码精品久久久久免费|