匯編一個簡單的C程序引發的思考

如果不思考,單純地做做試驗,此次實驗很簡單,但這幾句簡簡單單的代碼卻包括了底層的機制:如參數是如何傳遞的,堆棧是如何增長的,各個寄存器的作用又是怎樣的。

實驗截圖如下,不是很復雜。

2514111487474604488-wm.png

2514111487425283904-wm.png

2514111487404404260-wm.png

刪除指導匯編器和鏈接器的命令(即是那些以.開頭的),得到真正對我們分析匯編代碼有用的這一部分。

匯編代碼:

g:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
addl $3, %eax
popl %ebp
ret

f:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl 8(%ebp), %eax
movl %eax, (%esp)
call g
leave
ret

main:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl $8, (%esp)
call f
addl $1, %eax
leave
ret

C語言代碼:

int g(int x)
{
  return x + 3;
}

int f(int x)
{
  return g(x);
}

int main(void)
{
  return f(8) + 1;
}

這個程序中有3層調用,main函數調用f(),f()調用g(),
main函數運行。
程序是這樣運行的,每個函數都有屬于自己的堆棧,這一段堆棧叫做棧幀,在32位機上由ebp(幀指針)和esp(棧指針)來劃定范圍。

main函數執行的時候,先把自己ebp的值保存下來,然后,再將ebp賦值為esp,這樣便開始了一個新的棧幀,此時ebp和esp指向了同一處,而這個內存單元里面保存的是ebp的值,esp便開始了對棧幀大小的修改。

為什么要保存ebp的值呢,在函數運行的過程中,ebp一般是不會被修改的,當然,除了下面這兩句:
pushl %ebp
movl %esp, %ebp

這兩句匯編代碼巧妙地只用了一個ebp寄存器就成功地區分開兩個函數的棧幀,因為它保存著上一個函數的esp的值,ebp的位置又固定不變。

之前講過,為了區分開每個函數的棧幀,需要保存ebp和esp,因為在每個函數的執行過程中,想獲取當前棧幀的數據,而esp又是變化的,無法把esp當作可靠的參考,此時之前保存的ebp就派上了用場,因為ebp恒定指向此棧幀的最開始。

更為有意思的是以ebp作為參考這種機制在32位機中參數的傳遞有著重要的意義,接下來在g()函數執行的過程中,就可以看到這樣設計的妙處

接下來的

subl $4, %esp
movl $8, (%esp)

是為調用f()準備好參數,參數的壓棧順序是從右向左壓棧,分別是參數n參數n-1,直到參數1。本次只有一個參數,故只保存了立即數8到棧中。

有一點是需要記住的,只有32位系統才有棧幀的概念,并且只能通過棧來傳遞參數,而64位機則是主要通過寄存器傳參,只有當寄存器不夠用才使用棧,這樣帶來的好處就是效率更高。

調用f()函數call f肯定會做一件事情,即將返回地址addl $1, %eax指令的地址壓棧。f()函數運行的時候,同樣的道理,保存當前的ebp值,設定ebp的指向。
subl $4, %esp,為壓棧做準備。

movl 8(%ebp), %eax
movl %eax, (%esp)```
則是通過對ebp的帶偏移量的寄存器間接尋址(***基址+偏移量***)找到main函數保存的參數值。因為堆棧是向下增長,那么ebp+4,指向的是上個函數的ret地址,ebp+8則指向的是我們保存的參數8。`movl 8(%ebp), %eax`將8保存到自己的堆棧中去。然后調用g()函數。

***不過我覺得如果使用GCC匯編的時候,優化等級調高,那么,完全沒必要浪費這2條指令,因為本身f()函數什么都沒做,只是負責傳遞參數給g()而已,那么直接利用g()的ebp便可尋址到傳入的參數。***
*其實,可能直接把g()函數給優化掉了吧?*

g()函數中的形成棧幀的前兩句不再多解釋,`movl 8(%ebp), %eax`是把傳入的參數8存儲到eax中,接下來的`addl $3, %eax`則把3加到eax中,`popl %ebp`則是恢復上個函數的ebp,為ret做準備。
`ret`又做了什么呢?`ret`相當于`pop %eip`,恢復eip的值,即調用者的下一條語句。在這個代碼中,eip被賦值為f()函數中leave指令的地址,同時由eax返回結果11。

接下來到了f()中的`leave`,也就相當于

movl %ebp,%esp
popl %ebp

第一條把ebp的值賦值給esp,原因在于在當前的棧幀中ebp保存的是當前棧幀的esp值(還記得`movl %esp, %ebp`嗎?),esp指向的地方實際保存著ebp,`popl %ebp`則把保存的ebp彈出來(`pushl %ebp`),然后ret指令彈出eip,返回eax到main函數。
main函數中,把1加到eax上,重復同樣的動作,整個程序結束。
最后的結構大概是這樣:


![Paste_Image.png](http://upload-images.jianshu.io/upload_images/4811496-1f8e875869ae3bbb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

至于說GCC堅持的x86編程指導防止,也就是說一個函數使用的所有棧空間必須是16字節的整數倍(包括保存的%ebp值的4個字節和返回值的4個字節),在這個代碼中并未體現出來,不知道是不是因為GCC比較新的緣故。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,967評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,273評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,870評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,742評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,527評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,010評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,108評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,250評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,769評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,656評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,853評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,371評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,103評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,472評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,717評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,487評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,815評論 2 372

推薦閱讀更多精彩內容