stack of gcc

棧是向下生長的,%esp記錄着棧頂,%ebp記錄着當前的棧禎

# 以下是主調函數
_start:
   push $3                # 函數參數
   push $2               # 函數參數
   call func               # 調用函數
   addl $8, %esp      # 刪除參數佔用的堆棧空間

# 參數入棧後,執行call指令,call指令做兩件事:
#    1.將當前call指令的下一條指令的地址入棧
#    2.修改%eip = function_addr,i.e. 讓%eip等於被調函數的入口地址

.func:
   pushl %ebp              # 將_start中的%ebp棧禎入棧   create stack frame
   movl  %esp, %ebp   # 將.func的棧禎保存到 ebp中
                                  # i.e. %ebp 保存的永遠是當前函數的棧禎

|->subl  $8,   %esp   # 爲local variable 申請兩個局部變量空間,可能程序中使用兩次pushl
|
|  .....
|      | 12(%ebp)  | 就是第二個參數
|      |  8(%ebp)  | 就是第一個參數
|      |  4(%ebp)  | 是調用.func的_start函數中的addl $8, %esp的地址,i.e. 函數返回地址 
|      |  %ebp     |  是調用func之前的ebp
|      |  -4(%ebp) | 第一個局部變量
|      |  -8(%ebp) | 第二個局部變量 %esp
|   .....
|
|->addl  $8,   %esp    # 釋放兩個局部變量佔用的棧內存,與前面的subl $8, %esp對應

   movl ..., %eax        # 設置返回值
   movl %ebp, %esp  # 將%esp設置爲%ebp,這樣下一步popl時
                                # 能把調用func前的%ebp彈出來
   popl  %ebp            # 將%ebp恢復爲調用func 前的%ebp
                                #  destory stack frame

   ret                        # ret指令與call指令是對應的
                               # ret 指令相當於popl %eip指令,經過popl後,
                               # %esp指向的是調用.func的_start函數中的
                               # addl 8, %esp的地址

注意觀察:.func開頭的兩行  與 .func 的倒數2、3行是對應的

 

as     -o x.o   --gstabs+    x.s

ld      -o x                           x.o

發佈了43 篇原創文章 · 獲贊 5 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章