x86架构调用栈分析

 以一个简单求阶乘的代码为例:

 1 #include <stdio.h>
 2 
 3 unsigned int fact(unsigned int n)
 4 {
 5     if (n == 0)
 6         return 1;
 7     return n * fact(n - 1); 
 8 }
 9 
10 int main(void)
11 {
12     int c = 0;
13     
14     c = fact(5);
15 
16     return c;
17 }
View Code

 其反汇编:

(gdb) disassemble main
Dump of assembler code for function main:
   0x080483bb <+0>:    push   %ebp
   0x080483bc <+1>:    mov    %esp,%ebp
   0x080483be <+3>:    and    $0xfffffff0,%esp
   0x080483c1 <+6>:    sub    $0x20,%esp
   0x080483c4 <+9>:    movl   $0x0,0x1c(%esp)
   0x080483cc <+17>:    movl   $0x5,(%esp)
   0x080483d3 <+24>:    call   0x8048394 <fact>
   0x080483d8 <+29>:    mov    %eax,0x1c(%esp)
   0x080483dc <+33>:    mov    0x1c(%esp),%eax
   0x080483e0 <+37>:    leave  
   0x080483e1 <+38>:    ret    
End of assembler dump.
(gdb) disassemble fact
Dump of assembler code for function fact:
   0x08048394 <+0>:    push   %ebp
=> 0x08048395 <+1>:    mov    %esp,%ebp
   0x08048397 <+3>:    sub    $0x18,%esp
   0x0804839a <+6>:    cmpl   $0x0,0x8(%ebp)
   0x0804839e <+10>:    jne    0x80483a7 <fact+19>
   0x080483a0 <+12>:    mov    $0x1,%eax
   0x080483a5 <+17>:    jmp    0x80483b9 <fact+37>
   0x080483a7 <+19>:    mov    0x8(%ebp),%eax
   0x080483aa <+22>:    sub    $0x1,%eax
   0x080483ad <+25>:    mov    %eax,(%esp)
   0x080483b0 <+28>:    call   0x8048394 <fact>
   0x080483b5 <+33>:    imul   0x8(%ebp),%eax
   0x080483b9 <+37>:    leave  
   0x080483ba <+38>:    ret  
View Code

fact函数中栈如下:

   |  args          | 参数列表

     |  return addr   | 返回地址,即fact函数的下一条指令地址 

ebp->|  original ebp  | main函数中的栈帧指针

... 

esp->|                          |

因此,只要得到当前ebp, 那么(ebp)就是上一次函数调用的ebp, (ebp + 4)就是返回地址, (ebp + (i + 2) * 4)就是第i(i = 0, 1, 2...)个参数. 

 1 void backtrace(int level)
 2 {
 3     unsigned int *ebp = 0, *eip = 0, args[4] = {0};
 4     int i = 0, times = 0;  
 5     if (level < 0)
 6         level = 0x7fffffff;
 7 
 8     // get ebp
 9     __asm__ __volatile__(
10         "mov %%ebp, %0	
"
11         : "=m"(ebp)
12     );  
13     eip = (unsigned int *)ebp[1]; // get eip and args
14     for (i = 0; i < 4; i++)
15         args[i] = ebp[i + 2]; 
16 
17     while (*ebp != NULL && times < level) 
18     {   
19         printf(" ebp:0x%08x eip:0x%08x args:0x%08x 0x%08x 0x%08x 0x%08x
",
20                 ebp, eip, args[0], args[1], args[2], args[3]);
21         ebp = (unsigned int *)ebp[0]; // get ebp
22         eip = (unsigned int *)ebp[1];
23         for (i = 0; i < 4; i++)
24             args[i] = ebp[i + 2]; 
25         times++;
26     }   
27 }
原文地址:https://www.cnblogs.com/ym65536/p/4180544.html