函数调用的过程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++ ,