探尋Windows NT/2000 Copy On Write機制(http://wecrazy.yeah.net)

來源:互聯網
上載者:User
 探尋Windows NT/2000 Copy On Write機制
            WebCrazy(http://wecrazy.yeah.net) 
                      
    Copy On Write機制是典型的Lazy evaluation實現,現代作業系統如Windows NT/2000,UNIX/Linux的記憶體管理部分大量使用這種機制。本文通過對Windows NT/2000中Copy On Write機製作一深入分析,旨在探尋Windows NT/2000核心態記憶體管理器的幾個重要的資料結構,在繼續以下的討論之前,您務必要明白PDE/PTE、VAD等一些術語(參見我先前的《小議Windows NT/2000分頁機制》與《分析Windows NT/2000堆記憶體與虛擬記憶體組織 》),另外我將述及另幾個與記憶體子系統相關的術語,如Control Area,Subsection,Working Set List,Page Frame Database。下面列出我在本文中用於分析Copy On Write機制的代碼,文中所有的敘述均基於這段代碼。

    // cow.c 
    // Writed by ChenChengQin(tsu00@263.net )

    #include <stdio.h>
    #include <string.h>

    #define BUFSIZE 10

    #pragma data_seg(".seg_cow")
    char data[BUFSIZE]={'A','A','A','A','A','A','A','A','A','/0'};
    #pragma data_seg()
    #pragma comment(linker, "/SECTION:.seg_cow,RWC")

    void main(int argc,char *argv[])
      {
       int i;
       if (argc>1){
         //memset(data,'B',BUFSIZE);
         __asm int 3;
         for(i=0;i<BUFSIZE;i++) 
            data[i]='B';
         data[BUFSIZE-1]='/0';
       }
       printf("%s",data);

       getchar();
      }

    非常簡單的一段代碼,使用如下指令編譯:

        cl /Zi /Fa cow.c

    運行一個執行個體(別退出):
        c:>cow
        AAAAAAAAAA

    使用SoftICE看看cow.exe映像在記憶體中的分布:

        :addr cow
        :map32 cow
        Owner     Obj Name  Obj#  Address        Size      Type
        cow       .text     0001  001B:00401000  00006BB8  CODE  RO
        cow       .rdata    0002  0023:00408000  000005C8  IDATA RO
        cow       .data     0003  0023:00409000  00002EC4  IDATA RW
        cow       .idata    0004  0023:0040C000  00000633  IDATA RW
        cow       .seg_cow  0005  0023:0040D000  0000010C  IDATA RW
        cow       .reloc    0006  0023:0040E000  000006B2  IDATA RO

        //查看.seg_cow段(虛擬位址0x40d000)的首地址的PTE,詳見《小議Windows NT/2000分頁機制 》
        :dd c0000000+1*1000+d*4 l 10
        0023:C0001034 003F9225  00000000  00000000  00C3C067      %.?.........g...
                      --------
                          |
                          |_cow.exe進程.seg_cow段首地址的PTE

    SoftICE的page命令可以dump出這個PTE的屬性,如下所示:

       :page 40d000
       Linear     Physical   Attributes
       0040D000   003F9000   P   A U R

    不過這裡列出的Attributes並沒有指出.seg_cow的Copy On Write屬性,因為X86的PTE的低12位(0-11),即屬性位並沒有指出這個屬性,但Microsoft(當然不僅僅Microsoft)使用了這12位中的保留的系統(OS)位,下面是這一DWORD值在Windows 2000的具體格式:

       struct   _HARDWARE_PTE_X86 (sizeof=4)
       +0 bits0-0 Valid
       +0 bits1-1 Write
       +0 bits2-2 Owner
       +0 bits3-3 WriteThrough
       +0 bits4-4 CacheDisable
       +0 bits5-5 Accessed
       +0 bits6-6 Dirty
       +0 bits7-7 LargePage
       +0 bits8-8 Global
       +0 bits9-9 CopyOnWrite
       +0 bits10-10 Prototype
       +0 bits11-11 reserved
       +0 bits12-31 PageFrameNumber
    
    從上的PTE為003F9225的值可以看出0x40d000的唯讀、CopyOnWrite屬性。唯讀屬性是實現CopyOnWrite的保證,這樣X86才能在另一個cow執行個體試圖寫.seg_cow段時raise一個0eh(頁故障)中斷(陷阱),讓Windows處理這個Copy On Write操作。基於這個原理,我即運行cow的另一個執行個體,跟蹤Copy On Write機制:

    c:>cow 1(設定一個參數,讓cow試圖更新.seg_cow段)

    我在代碼中設定了int 3指令讓softice在i3here設定為on狀態時讓softice啟用。然後使用bpint e指令讓softice捕獲0eh中斷。i386在raise 0e中斷時將發生頁故障的虛擬位址儲存於CR2寄存器中。Windows 2000頁故障處理入口KiTrap0E就是根據這個地址製作cow進程.seg_cow的副本,並替代第二個cow執行個體工作集(Working List,這兒只指進程工作集,未牽涉系統工作集)的原始頁面,實現CopyOnWrite的目的。我並不準備將KiTrap0E的彙編代碼列於此,只是講一講Windows尋找CR2指定的地址的屬性的步驟,Windows 2000中由MiQueryAddressState過程實現。KiTrap0E當然也會調用MiQueryAddressState。

    1、首先檢查0x40d000(由CR2指定)的PDE。由MiDoesPdeExistAndMakeValid實現。
    2、檢查PTE。
    3、查頁框資料庫(PFN,Page Frame Database,由核心結構陣列變數MmPfnDatabase指定)
    4、根據PFN中工作集索引尋找Working Set List Entry(Working Set基址由核心變數_MmWsle指出),這一步驟由核心常式MiLocateWsle完成。
    5、然後根據Wsle的屬性(也是前12位)尋找MmProtectToValue數組,以獲得使用者態可以理解的格式。即在winnt.h中定義的PAGE_WRITECOPY、PAGE_READWRITE等等。

    步驟3至5其實也實現了物理地址至線性地址的轉換,當然這個是在這個地址Present的前提下。這也是為什麼Windows 2000使用如此複雜且繁瑣的結構來管理記憶體子系統。確切的說我並沒有談到PFN的PteAddress成員(下面i386kd輸出可以看到),這些都是使用分頁檔案(pagefile.sys,通過ProtoPTE,即原型PTE實現的),共用記憶體塊等的基礎。David Solomon的書《Inside Windows NT,2nd Edition》有四種PFN形態的具體結構等等其他很多詳細的說明。

    下面是i386kd的分析,其實根據上面我給定的一些核心變數SoftICE也可以看出些東西。不過遠沒有i386kd來的容易。

    // cow.exe 進程ID(ClientID)=4ac
    kd> !process 4ac
    !process 4ac
    Searching for Process with Cid == 4ac
    PROCESS ff605d60  SessionId: 0  Cid: 04ac    Peb: 7ffdf000  ParentCid: 04a0
        DirBase: 017bc000  ObjectTable: ff610f88  TableSize:  12.
        Image: cow.exe
        VadRoot ff624168 Clone 0 Private 37. Modified 0. Locked 0.
               .
               .
               .
    //轉換40d000至物理地址,取得PFN。
    //SoftICE中使用Page命令
    kd> !vtop 017bc000 40d000
              --------
                 |_DirBase(見!process輸出)
        !vtop 017bc000 40d000
        Pdi 1 Pti d                         //輸出PDE與PTE
        0040d000 00a6e000 pfn(00a6e)        //輸出PFN

    //查PfnDatabase
    //Softice中:
    //   dd @MmPfnDatabase+a6e*18 (每一PFN項佔用0x18位元組)
    kd> !pfn a6e
    !pfn a6e
        PFN 00000A6E at address FFB8EA50
        flink       00000097  blink / share count 00000001  pteaddress E151E1B4
        reference count 0001                                 color 0
        restore pte 056B04B0  containing page        002AF3  Active      P
        Shared

    /*
      查MmWsle
      SoftICE中:
         :dd @MmWsle+97*4 l 10
         0023:C05028FC 0040DF29  000006A0  00510C09  000009B0      ).@.......Q.....
                       --------
                          |_0040D000是不是PFN為A6E的Virtual Address
    */
    kd> !wsle 4ac
    !wsle 4ac

    // KPEB中的VmWorkingSetList成員(Windows 2000 Server Build 2195中位移0f0處,值為C0502000)指出Working Set List
    // 見《Windows 2000核心KPEB/KTEB詳細結構 》

    Working Set @ c0502000   
        Quota:          2f  FirstFree:       22  FirstDynamic:          4
        LastEntry       ad  NextSlot:        16  LastInitialized      257
        NonDirect       1e  HashTable: c06f3000  HashTableSize:       200
               .
               .
               .

    這些i386kd指令已經較清楚的指出以上5個步驟。但要理解Copy On Write還必須對Section(使用者態的FileMapping)對象有一基本的理解。在使用NtCreateSection/NtOpenSection(CreateFileMapping/OpenFileMapping間接使用這些常式)等時,Windows 2000一般會在VAD這個自平衡的二叉樹中插入一個節點。(我在《分析Windows NT/2000堆記憶體與虛擬記憶體組織 》中詳細介紹過VAD)。SoftICE在使用query指令dump VAD樹時有一成員MMCI(記憶體管理結構),她指向的是Control Area。如下所示:

    // SoftICE輸出
    :query cow
    Address Range      Flags     MMCI      PTE       Name
    00010000-00010000  C4000001
               .
               .
               .
    00400000-0040E000  07100005  FF62FD48  E11EBF80  cow.exe
                                 --------
                                    |_Control Area
               .
               .
               .

    其實我們使用i386kd的!memusage可以dump出系統中所有的Control Area:

    kd> !memusage
     loading PFN database
     loading (99% complete)
             Zeroed:     15 (    60 kb)
               Free:      0 (     0 kb)
            Standby:   1274 (  5096 kb)
           Modified:    686 (  2744 kb)
     ModifiedNoWrite:      1 (     4 kb)
       Active/Valid:  14380 ( 57520 kb)
         Transition:     11 (    44 kb)
            Unknown:      0 (     0 kb)
              TOTAL:  16367 ( 65468 kb)
     Building kernel map
     Finished building kernel map

     Control Valid Standby Dirty Shared Locked PageTables  name
               .
               .
               .
     ff62fd48    32      0     0     0     0     0  mapped_file( cow.exe )            
     --------
         |_Control Area與上面SoftICE的MMCI一致
               .
               .
               .

     i386kd的ca命令可以看出一個Control Area結構:

     kd> !ca ff62fd48

     ControlArea @ff62fd48
       Segment:    e11ebf48    Flink              0   Blink:               0
       Section Ref        1    Pfn Ref            8   Mapped Views:        1
       User Ref           2    Subsections        7   Flush Count:         0
       File Object ff684288    ModWriteCount      0   System Views:        0
       WaitForDel         0    Paged Usage       a0   NonPaged Usage      120
       Flags (10000a0) Image File HadUserReference

        File: /Desktop/hack/cow.exe

     Segment @ e11ebf48:
        Base address        0  Total Ptes         f  NonExtendPtes:        f
        Image commit        5  ControlArea ff62fd48  SizeOfSegment: f000
        Image Base          0  Committed          0  PTE Template:   54f1c30
        Based Addr     400000  ProtoPtes   e11ebf80  Image Info:    e11ebfc0

     Subsection 1. @ ff62fd80
        ControlArea: ff62fd48  Starting Sector 0 Number Of Sectors 8
        Base Pte     e11ebf80  Ptes In subsect        1 Unused Ptes          0
        Flags              15  Sector Offset          0 Protection           1
         ReadOnly CopyOnWrite
               .
               .
               .

    由ca命令的輸出結果可以看出這個Control Area有7個子領域(Subsection),限於篇幅我刪掉部分輸出結果,你可以將所有結果與SoftICE的map32指令輸出比較比較。Control Area中實際上所有Subsection結構均是使用線性結構組織,每個Subsection在Windows 2000 Server Build 2195中佔用0x20位元組。所以SoftICE可以很容易的分析所有的這些。

    需要指出的是不僅僅Section對象使用Control Area,她在Windows 2000中也由SECTION_OBJECT_POINTERS結構使用:

    typedef struct _SECTION_OBJECT_POINTERS {
        PVOID DataSectionObject;    //Control Area
        PVOID SharedCacheMap;
        PVOID ImageSectionObject;   //Control Area
    } SECTION_OBJECT_POINTERS;

    而每一個FILE_OBJECT都有SECTION_OBJECT_POINTERS成員(見ntddk.h)。這個機制是Windows 2000裝載可執行檔、檔案IO操作(看到DataSectionObject與ImageSectionObject了嗎?)的關鍵所在。只有熟悉這些結構,才可能真正初步明白Copy On Write機制。剩下的只有你自己多研究研究了。

    關於cow.exe,我還有兩點要說明的是:
    1、cow.c使用#pragma comment(linker, "/SECTION:.seg_cow,RWC")顯式的指出.cow_seg段的Copy On Write屬性,實際上在Windows NT/2000中這種共用屬性是預設存在的。可執行檔的映射、可讀可寫的資料都被預設設為Copy On Write屬性,您可以使用Jeffrey Richter的VMMAP驗證這種說法。
    2、Windows NT/2000使用可執行檔名(ImageName)用於識別這種程式多個執行個體間使用Copy On Write共用記憶體,對於有不同檔案名稱的可執行檔,即便其內容完全一致,這種機制也不起作用,而用分別映射Section對象替之。

    所有以上討論的都沒有找到Microsoft的Full Documented,所有以上討論的也只是在我初步分析Windows 2000後得到的,有什麼技術問題需要交流的,歡迎賜教(tsu00@263.net)!

參考資料:
      1.David Solomom《Inside Windows NT,2nd Edition》

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.