函数调用的过程stack动态分析
一段代码的stack调用分析:
下面分析的代码:
图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到程序计数寄存器中,将控制权返回给调用者.