從一段代碼的彙編看計算機的工做原理

朱宇軻 + 原創做品轉載請註明出處 + 《Linux內核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000linux

/*-------------------------------------如下內容是課堂筆記,咿呀咿呀呦!------------------------------------------*/框架

本課主要對計算機的運行原理和彙編語言進行了簡單的介紹。函數

馮若依曼體系結構即存儲程序計算機,也就是將程序寫在內存中,由CPU經過總線從內存中讀取一條條程序,根據程序的內容執行具體的步驟。spa

如圖所示指針

CPU在讀取指令時,經過寄存器IP來指向下一條指令(若是是32位系統,則爲EIP)code

CPU的寄存器分爲通用寄存器、段寄存器、狀態寄存器blog

四種尋址方式:內存

movl %eax,%edx     edx=eax                          寄存器尋址class

movl $0x123,%edx  edx=0x123                       當即尋址原理

movl 0x123,%edx    edx=*(int32_t*)0x123        直接尋址

movl (%ebx),%edx   edx=*(int32_t*)ebx           間接尋址

movl 4(%ebx),%edx  edx=*(int32_t*)(ebx+4)    變址尋址

瞭解pushl、popl、call 0x1234五、ret命令

注意:IP寄存器通常不能隨便修改,只能經過call、ret等命令更改!

函數的返回值默認使用EAX寄存器存儲返回給上一級函數

    

/*-------------------------如下內容是實驗分析,咿呀咿呀呦!------------------------------------------*/

     首先寫下這麼一段C程序:

 1 //linux.c
 2 int g(x)
 3 {
 4     return x+3;
 5 }
 6 int f(x)
 7 {
 8     return g(x);
 9 }
10 int main()
11 {
12     return f(10)+1;
13 }

  在Linux的環境中輸入以下指令:

gcc –S –o linux.s linux.c -m32

  而後打開linux.s,就能夠看到咱們彙編後的代碼(直接上截圖了)

 

   將裏面以「.」開頭的行去掉(這是爲連接用的),獲得彙編後的代碼:

 1 g:
 2     pushl   %ebp
 3     movl    %esp, %ebp
 4     movl    8(%ebp), %eax
 5     addl    $3, %eax
 6     popl    %ebp
 7     ret
 8 f:
 9     pushl   %ebp
10     movl    %esp, %ebp
11     subl    $4, %esp
12     movl    8(%ebp), %eax
13     movl    %eax, (%esp)
14     call    g
15     leave
16     ret
17 main:
18     pushl   %ebp
19     movl    %esp, %ebp
20     subl    $4, %esp
21     movl    $10, (%esp)
22     call    f
23     addl    $1, %eax
24     leave
25     ret

   接下來咱們來分析一下改程序具體的流程。

  程序一開始,CPU的IP寄存器指向彙編代碼的第18行,假設堆棧在內存中的地址分別爲0,1,2,3……堆棧基指針寄存器(EBP)和堆棧頂指針寄存器(ESP)均指向堆棧段0處。

  第18~21行首先爲main函數開闢新的內存區域,以後將傳的參數10入棧,此時堆棧段以下所示:

  

  而後程序調用call 函數,將IP入棧,IP指向代碼第9行f處。

  在f函數的代碼處,首先爲f函數開闢新的內存區域,接着將傳入的參數10賦值給EAX,並將EAX入棧,此時堆棧段內存以下圖:

  程序在此調用call進入g函數。在g函數中,一樣先是開闢內存空間,而後將參數傳給EAX,並將EAX的值加上3。

  以後將EBP出棧,並調用ret命令。此時IP從新指向f函數call以後的命令,堆棧內存的狀況以下:

  

  以後就是不斷的調用leave與ret命令,跳出當前的內存區域,回到上一級函數的內存區域中,並將EAX的值加3,直到跳出main函數,至此程序結束。

  從上面的分析中,我以爲能夠概括出如下幾點:

  1.計算機的運行流程確是遵循馮諾依曼框架,CPU將內存中的代碼和數據讀取到本身的寄存器中,再根據一條條命令調用寄存器進行進一步的操做。

  2.在進入每個程序以前,CPU都會將上一級的EIP和EBP壓棧,至關於爲新的函數從新開闢了一段新的內存空間,直到退出函數的時候纔將它們出棧。與此同時,將函數的返回值保存在EAX中。

  3.CPU的各個寄存器都有不一樣的分工,如EIP指向要執行的代碼,EAX存儲返回值等。它們貫穿於整個程序執行流程,本身寫程序時通常不要輕易改動。

相關文章
相關標籤/搜索