實驗環境:visual c++ 6.0
實驗目的:通過組合語言分析一個簡單的c程式在程式執行時的記憶體配置情況
/*******mymain.cpp*********/
1: #include<stdio.h>
2: int main()
3: {
4: int x=1;
5: printf("Hello Canney\n");
6: return0;
7: }
/*******mymain.asm*********/
1: #include<stdio.h>
2: int main()
3: {
00410950 push ebp
00410951 mov ebp,esp
00410953 sub esp,44h // esp=esp-0x40,分配棧空間給局部變數。移動單位為位元組
00410956 push ebx
00410957 push esi
00410958 push edi
00410959 lea edi,[ebp-44h]
0041095C mov ecx,11h
00410961 mov eax,0CCCCCCCCh
00410966 rep stos dword ptr [edi]
4: int x=1;
00410968 mov dword ptr [ebp-4],1
5: printf("Hello Canney\n");
0041096F push offset string"Hello Canney\n" (0042601c) //字串常量,存放在0x0042201c(.rodata地區)
00410974 call printf (00401080) //調用printf函數,函數入口在0x00401060
00410979 add esp,4
6: return0;
0041097C xor eax,eax //eax=0,清空eax
7: }
0041097E pop edi
0041097F pop esi
00410980 pop ebx
00410981 add esp,44h
00410984 cmp ebp,esp
00410986 call __chkesp (004011b0) //檢查棧是否被破壞
0041098B mov esp,ebp
0041098D pop ebp
0041098E ret //棧頂字單元出棧,其值賦給IP寄存器。即實現了一個程式的轉移,將棧頂字單元儲存的位移地址
補充知識:
1.32位機器8個通用寄存器
①資料寄存器
資料寄存器主要用來儲存運算元和運算結果等資訊,從而節省讀取運算元所需佔用匯流排和訪問儲存空間的時間。32位CPU有4個32位的通用寄存器EAX、EBX、ECX和EDX。對低16位元據的存取,不會影響高16位的資料。這些低16位寄存器分別命名為:AX、BX、CX和DX,它和先前的CPU中的寄存器相一致。
4個16位寄存器又可分割成8個獨立的8位寄存器(AX:AH-AL、BX:BH-BL、CX:CH-CL、DX:DH-DL),每個寄存器都有自己的名稱,可獨立存取。程式員可利用資料寄存器的這種“可分可合”的特性,靈活地處理字/位元組的資訊。寄存器AX和AL通常稱為累加器(Accumulator),用累加器進行的操作可能需要更少時間。累加器可用於乘、除、輸入/輸出等操作,它們的使用頻率很高;寄存器BX稱為基地址寄存器(BaseRegister)。它可作為儲存空間指標來使用;寄存器CX稱為計數寄存器(CountRegister)。在迴圈和字串操作時,要用它來控制迴圈次數;在位操作中,當移多位時,要用CL來指明移位的位元;
寄存器DX稱為資料寄存器(DataRegister)。在進行乘、除運算時,它可作為預設的運算元參與運算,也可用於存放I/O的連接埠地址。在16位CPU中,AX、BX、CX和DX不能作為基址和變址寄存器來存放儲存單元的地址,但在32位CPU中,其32位寄存器EAX、EBX、ECX和EDX不僅可傳送資料、暫存資料儲存算術邏輯運算結果,而且也可作為指標寄存器,所以,這些32位寄存器更具有通用性。
②變址寄存器
32位CPU有2個32位通用寄存器ESI和EDI。其低16位對應先前CPU中的SI和DI,對低16位元據的存取,不影響高16位的資料。寄存器ESI、EDI、SI和DI稱為變址寄存器(IndexRegister),它們主要用於存放儲存單元在段內的位移量,用它們可實現多種儲存空間運算元的定址方式,為以不同的地址形式訪問儲存單元提供方便。變址寄存器不可分割成8位寄存器。作為通用寄存器,也可儲存算術邏輯運算的運算元和運算結果。它們可作一般的儲存空間指標使用。在字串操作指令的執行過程中,對它們有特定的要求,而且還具有特殊的功能。
③指標寄存器
32位CPU有2個32位通用寄存器EBP和ESP。其低16位對應先前CPU中的SBP和SP,對低16位元據的存取,不影響高16位的資料。寄存器EBP、ESP、BP和SP稱為指標寄存器(PointerRegister),主要用於存放堆棧記憶體儲單元的位移量,用它們可實現多種儲存空間運算元的定址方式,為以不同的地址形式訪問儲存單元提供方便。指標寄存器不可分割成8位寄存器。作為通用寄存器,也可儲存算術邏輯運算的運算元和運算結果。它們主要用於訪問堆棧內的儲存單元,並且規定:
(1)BP為基指標(BasePointer)寄存器,用它可直接存取堆棧中的資料;
(2)SP為堆棧指標(StackPointer)寄存器,用它只可訪問棧頂。
2.rep和stos指令
rep指令的目的是重複其後的指令.ECX的值是重複的次數. rep可以是任何字串指令(CMPS, LODS, MOVS,SCAS, STOS)的首碼. rep能夠引發其後的字串指令被重複, 只要ecx的值不為0, 重複就會繼續. 每一次字串指令執行後, ecx的值都會減小.
stos指令的作用是將eax中的值拷貝到edi指向的地址.如果設定了direction flag, 那麼edi會在該指令執行後減小, 如果沒有設定direction flag, 那麼edi的值會增加.
stos((store into String),意思是把eax的內容拷貝到目的地址。用法:stos dst,dst是一個目的地址,例如:stos dword ptres:[edi]。dword ptr首碼告訴stos,一次拷貝雙字(32個位元組)的資料到目的地址。為什麼一次非要拷貝雙字呢?這和eax寄存器有關,到底神馬關係,慢慢道來…
執行stos之前必須往eax(32為寄存器)放入要拷貝的資料。中,eax的內容是cccccccc,不用說都明白int3中斷。這段代碼是初始化堆棧和分配局部變數用的,往分配好的局部變數空間放入int3中斷的原因是:防止該空間裡的東東被意外執行。