結論:
1.esp指向棧頂存有數據的那個單元(而不是下一個單元)
2.在函數中臨時變量是存在棧頂和棧底之間的,包括參數在內。通常我們說通過棧傳遞參數,參數入棧的操作並不是push,而是movl 參數 0xXX(%esp)。
3.call函數時。返回地址保存到棧頂。是使用push指令的,會修改esp的值(-4)
4.在被調用函數的開頭push ebp。保存原來棧底,也要修改esp的值(-4)。新的ebp指向存放老的ebp的位置。然後,利用add size esp爲被調用函數開闢棧空間。
5.在被調用函數中,取傳遞來的參數也是通過mov 0xXX(%ebp) 實現。
圖 1
例子程序反彙編代碼:
1.看int i=5,j=6;的彙編碼
使用的是%esp+0x14.這個位置是在ebp和esp之間
2.使用棧傳遞參數.在sum = add(i,j)下面四行
(1)從j所在位置取出值,存入eax中,mov 0x18(%esp),%eax //可知,先是最右邊的參數
(2)將eax中的值放入棧頂的前一個位置,因爲只有兩個參數,所以右邊的參數放在棧頂前一個位置即可,如果是三個參數,就再往前放一個位置。
(3)同(1),取出j所在位置存放的值
(4)將該值放到棧頂單元。
圖2
3.在被調用函數中取參數:
這是對被調用函數的單步調試,i是參數.執行li = i時.我們看到執行了兩條彙編語句:mov 0x8(%ebp),%eax 和 mov %eax,-08(%ebp).
從圖2中我們看到,i是函數調用中的第一個參數。根據參數調用時的順序,最左邊的參數最後入棧。然後是返回地址,再之後是保存舊的ebp的值。之後,新的ebp指向保存舊的ebp值的那個位置。見圖1.所以新的ebp+8就是取得了第一個參數。同理,新的ebp+0xc就是取得了第二個參數。取來之後,通過eax把它放到li所表示的位置中。完成參數傳遞,賦值到被調用函數中的局部變量中。
圖3