[Linux核心分析第一周課程] 由C語言程式的彙編表示觀察CPU寄存器與記憶體的互動

來源:互聯網
上載者:User

標籤:語言   機器   賦值   回退   cal   rem   刪除   抽象   alt   

孟寧《Linux核心分析》第一周實驗

Zou Le

原創作品轉載請註明出處。

課程資訊:

《Linux核心分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000

 

---------------------------實驗本文---------------------------

本實驗在實驗樓64位LIinux虛擬機器下進行。

C代碼如下:

int increment5(int x) {  return x + 5;}int solve(int x) {  return increment5(x) - 2;}int main(void) {  return solve(2017);}

 

C程式的執行邏輯為:以main函數為入口,調用solve函數,字面值2017作為solve函數的參數,在solve函數中執行調用increment5函數,increment5函數接受2017,並加上5,返回solve函數再減去2,最後回到main函數返回該值。

 

通過同目錄下-S和-m32參數得到的彙編代碼main.s,將彙編代碼中以’.’開頭的行刪除後得到的代碼如下:

 

increment5:    pushl   %ebp    movl    %esp, %ebp    movl    8(%ebp), %eax    addl    $5, %eax    popl    %ebp    retsolve:    pushl   %ebp    movl    %esp, %ebp    pushl   8(%ebp)    call    increment5    addl    $4, %esp    subl    $2, %eax    leave    retmain:    pushl   %ebp    movl    %esp, %ebp    pushl   $2017    call    solve    addl    $4, %esp    leave    ret

 

實驗如下:

 

 

 

由教材CSAPP第三章可知,記憶體為單個過程(函數)分配的那部分棧稱為棧幀。最頂端的棧幀由兩個指標界定,分別為%ebp指向棧底,%esp指向棧頂,每次push命令都會讓%esp減去4(記憶體中棧向下增長),然後在新的地址寫入值。pop則先讀出當前%esp位置的值,再將棧減去4。

 

----------------程式運行時記憶體棧的變化描述---------------

首先給出帶行號的代碼作為基準。

本彙編代碼執行的過程為:

可以觀察到每次調用函數,首先執行的命令為

    pushl   %ebp

    movl    %esp, %ebp

若記憶體中main函數入口時esp和ebp都指向第0格。則這兩行代碼所做的事情就是將第0格的資訊儲存到第1格,然後將棧的原點ebp挪到第1格,以第1格作為本過程的棧底。

第20行,所做的事情為將字面值2017寫入第2格,此時ebp指向第1格,esp指向第2格。

第21行,call命令將eip=22的命令寫入第3格,然後令eip=9。

第9行和第10行,進入solve函數,先建立棧幀:將main函數的棧底資訊(棧底=1)儲存到第4格,然後以第4格作為本過程的棧底。注意到,此時8(%ebp)指向的是第2格,即solve函數的參數。對於單參數的函數,往往進入新函數後,其參數所在的位置就是8(%ebp),%ebp本身儲存了上一個(要返回的函數)的棧底資訊,再往前一格儲存了eip指標要返回的位置。

第11行,esp再次增加四,在第5格寫入字面值2017。

第12行,call命令將eip=13儲存到第6格,然後令eip=2。

第2行和第3行,建立棧幀,將slove函數的棧底資訊(棧底=4)儲存到第7格,然後以第7格作為本函數的棧底。8(%ebp)隨即指向第5格的值,即2017。

第4行,將第5格的值2017寫入eax寄存器中。

第5行,將eax中的值增加5。

第6行,將第7格(棧底=4)的資訊賦值給ebp,即又讓ebp指向第4格,同時esp回退1,指向第6格。

第7行,ret的語意為 popl %eip,即此時esp指向第6格,內容為eip指向13。該命令修改eip指向第13行,並使得esp回退到第5格。

第13行,將esp再回退1格,指向第4格。(此時棧頂和棧低都是第4格)。注意到,每次call命令後都會跟一個addl $4, %esp。在本例子中,均為回退掉為call函數所準備的單個函數參數。

第14行,%eax中減去2。

第15行,leave指令。leave指令的語意為先movl %ebp, %esp,然後popl %ebp。本行中%ebp儲存的資訊為main函數的棧底(第1格),合起來的作用為讓%ebp重新指向main函數的棧底1,並且esp指向第3格(eip=22)。

第16行,ret。此行令eip重新回到main函數,程式的第22行,同時esp回退到第2格。

第22行,將esp回退一格,回到第1格。

第23行,令棧底等於0,棧頂也等於0。

第24行程式結束,%eax中儲存最後的結果。

具體記憶體資訊和ebp、esp變化如下所示:

 

 

 

 

由上述過程可知,相比於進階語言如C語言,組合語言有很大一部分繁瑣的底層的函數調用,傳值的資訊。如我們所說的函數調用棧,是通過儲存上級函數繼續執行的地址和上級函數的原來的棧地址後,建立新的棧底來完成的。

通過本次實驗,我對32位彙編中常出現的8(%ebp)和leave+ret有了“感覺”,感受到了C語言相對於彙編所做的抽象工作的重要性,也對程式的機器級表示有了初步的認識。

[Linux核心分析第一周課程] 由C語言程式的彙編表示觀察CPU寄存器與記憶體的互動

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.