一个简单C程序的汇编代码分析

几个重要的寄存器

eip - 用于存放当前所执行的指令地址

esp - 栈(顶)指针寄存器

ebp - 基址(栈底)指针寄存器

简单的C程序

 1 int g(int x)
 2 {
 3   return x + 10;
 4 }
 5 
 6 int f(int x)
 7 {
 8   return g(x);
 9 }
10 
11 int main(void)
12 {
13   return f(7) + 5;
14 }

汇编代码分析

 1 g:
 2  pushl %ebp
 3  movl %esp, %ebp
 4 ;下面两条指令的含义是:将传入的参数7和10相加并保存在寄存器eax中
 5  movl 8(%ebp), %eax
 6  addl $10, %eax
 7  popl %ebp
 8  ret
 9 f:
10  pushl %ebp
11  movl %esp, %ebp
12  subl $4, %esp
13 ;下面两句指令的含义是:将参数7保存到函数f的栈帧中
14  movl 8(%ebp), %eax
15  movl %eax, (%esp)
16  call g
17  leave
18  ret
19 
20 main:
21  pushl %ebp
22  movl %esp, %ebp
23  subl $4, %esp
24  movl $7, (%esp)
25  call f
26  addl $5, %eax
27  leave
28  ret

针对上面的汇编代码,我们有如下的图例分析

一个简单C程序的汇编代码分析_第1张图片

说明:

  • 在执行call指令时,eip的所指向的指令是addl $5, %eax

  • call 指令等价于,将eip中的地址压栈保存,然后将函数f第一条指令(pushl %ebp)的地址放到eip中。

  • pushl、popl、leave、ret和call指令的等价指令如下
    pushl %eax ;将eax中的值压栈保存
    <=>
    subl $4, %esp
    movl %eax, (%esp)
    popl %eax      
       <=>    
    movl (%esp), %eax
    addl $4, %esp
    call 0x12345
    <=>
    pushl %eip(*)
    movl $0x12345, %eip(*)
    ret ; 将栈顶值弹出放到eip中,此时eip中的值便是将要执行的指令的地址
    <=>
    popl %eip(*)
    leave ;恢复所调用程序的堆栈
    < =>
    movl %ebp, %esp
    popl %ebp
    enter ;与leave指令的操作相反
    <=>
    pushl %ebp
    movl %esp, %ebp

你可能感兴趣的:(代码)