当前位置:编程学习 > C/C++ >>

函数调用的过程stack动态分析

一段代码的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.zzzyk.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到程序计数寄存器中,将控制权返回给调用者.
补充:软件开发 , C++ ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,