程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 函數調用的過程stack動態分析

函數調用的過程stack動態分析

編輯:C++入門知識

一段代碼的stack調用分析: 下面分析的代碼: [cpp]   /*   * =====================================================================================   *   *       Filename:  stack.c   *   *    Description:  gdb 棧的使用,對棧的分析過程   *   *        Version:  1.0   *        Created:  2013年02月10日 13時48分02秒   *       Revision:  none   *       Compiler:  gcc   *   *         Author:  LeoK,    *   Organization:     *   * =====================================================================================   */   #include <stdlib.h>   #include <stdio.h>   #include <ctype.h>   #include <stdlib.h>   #define     MAX     (1UL<<20)      typedef unsigned long long u64;   typedef unsigned int u32;      u32 max_addend = MAX;   u64 sum_till_MAX(u32 n)   {       u64 sum;       n++;       sum = n;              if (n < max_addend)       {           sum += sum_till_MAX(n);       }       return sum;   }      int main(int argc, char** argv)   {       u64 sum = 0;       if (argc == 2 && isdigit(*(argv[1])))           max_addend = strtoul(argv[1], NULL, 0);       if (max_addend >= MAX || max_addend == 0)       {           fprintf(stderr, "Invalid number is specidied\n");           return 1;       }   www.2cto.com     sum = sum_till_MAX(0);       printf("sum(0..%lu) = %llu\n", max_addend, sum);       return 0;   }   圖1 main函數的匯編代碼 其中main調用了sum_till_MAX 步驟1:圖1 movl $0x0, (%esp),這個匯編代碼就是main 調用sum_till_MAX的准備工作. 主要完成的就是stack.c:51行,把0函數參數傳進來(代碼是圖2). 圖2 執行完步驟1此時的棧如下,因為程序執行的時候都是邏輯地址,所以棧地址就假設開始為0x8fff0000開始 Address    Content    Expain 0x8fff0000  0x0       $esp指向這裡 0x8ffefffc   ???       內容random 0x8ffefff8   ???       內容random 0x8ffefff4   ???       內容random 0x8ffefff0   ???       內容random 0x8ffeffec   ???       內容random 0x8ffeffe8   ???       內容random 0x8ffeffe4   ???       內容random 0x8ffeffe0   ???       內容random 圖3 步驟1完成之後棧的內容 注意:如果函數是多參數的,那麼參數的入棧順序是從右向左入棧,such as int sum(int a, int b, int c) 這個函數的入棧順序是push c =>push b=> push a這個做的原因可能是函數執行可變參數的原因吧 步驟2 main函數調用call sum_till_MAX這個函數首先把eip壓棧,eip就是程序的執行的下一個地址,此時的stack如圖4 Address    Content       Expain 0x8fff0000  0x0          push 0 0x8ffefffc   0x0804858d   寄存器eip  esp指向這裡 0x8ffefff8   ???          內容random 0x8ffefff4   ???          內容random 0x8ffefff0   ???          內容random 0x8ffeffec   ???          內容random 0x8ffeffe8   ???          內容random 0x8ffeffe4   ???          內容random 0x8ffeffe0   ???          內容random 圖4步驟2完畢stack情況 下面進入到sum_till_MAX函數 sum_till_MAX的反匯編代碼如下: 圖5sum_till_MAX函數匯編代碼 步驟1 push %ebp把調用sum_till_MAX函數的ebp進行壓棧,恢復上一層棧幀的時候使用,此時棧如下: Address    Content       Expain 0x8fff0000  0x0          push 0 0x8ffefffc   0x0804858d   寄存器eip  0x8ffefff8   $ebp         上一個棧幀的棧基址 $esp指向這裡 0x8ffefff4   ???          內容 random 0x8ffefff0   ???          內容random 0x8ffeffec   ???          內容random 0x8ffeffe8   ???          內容random 0x8ffeffe4   ???          內容random 0x8ffeffe0   ???          內容random 步驟2 mov %esp ,  %ebp這段代碼表示把ebp指向esp也是就是地址0x8ffefff4地址。 步驟3 sub $0x28 ,  %esp表示把esp指針指向0x8ffefff4-0x28=0x8FFEFFCC,也就是為函數內部開辟新的占空間,是2*16+8=40個字節。 此時棧如下: Address    Content       Expain 0x8fff0000  0x0          push 0 0x8ffefffc   0x0804858d   寄存器eip  0x8ffefff8   $ebp         上一個棧幀的棧基址 0x8ffefff4   ???          $ebp指向這裡 0x8ffefff0   ???          內容random 0x8ffeffec   ???          內容random … … … 0x8ffeffcc   ???          esp指向這裡   步驟4 addl $0x1, 0x8(%ebp)這段代碼是把0拿出來(%ebp+0x8),進行++ 步驟5 mov 0x8(%ebp), %eax 把變量n放到eax寄存器中 步驟6 mov 0x0 , %edx 把寄存器edx清零 步驟7 mov %eax , -0x10(%ebp)這個是sum =n 把n賦值給sum 步驟21 leave指令為刪除棧幀的執行,它執行與1和2相反的處理,以釋放以前的棧。 步驟22 ret 為子程序返回指令,將棧中保存的返回地址POP到程序計數寄存器中,將控制權返回給調用者.

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved