Chinaunix首页 | 论坛 | 博客
  • 博客访问: 347160
  • 博文数量: 167
  • 博客积分: 2867
  • 博客等级: 少校
  • 技术积分: 1306
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-12 00:08
文章分类

全部博文(167)

文章存档

2017年(10)

2016年(5)

2015年(9)

2014年(10)

2013年(5)

2012年(17)

2011年(110)

2010年(1)

我的朋友

分类: LINUX

2013-11-21 18:28:45

简单的写一下,这几天看的成果,参考了他人的文章,有几个写的很不错
给出一个简单的例子。

===para.c===
#include  

void test(int a)  
{  
        (a)++;  
        return;  
}  
int main(int argc, char *argv[])  
{  
        int a = 2;  
        test(a);  
        return 0;  
}  

使用$>gcc -S para.c
编译生汇编文件para.s
  1         .file   "para.c"
  2         .text
  3         .globl  test
  4         .type   test, @function
  5 test:
  6 .LFB0:
  7         .cfi_startproc
  8         pushl   %ebp
  9         .cfi_def_cfa_offset 8
 10         .cfi_offset 5, -8
 11         movl    %esp, %ebp
 12         .cfi_def_cfa_register 5
 13         addl    $1, 8(%ebp)
 14         popl    %ebp
 15         .cfi_def_cfa 4, 4
 16         .cfi_restore 5
 17         ret
 18         .cfi_endproc
 19 .LFE0:
 20         .size   test, .-test
 21         .globl  main
 22         .type   main, @function
 23 main:
 24 .LFB1:
 25         .cfi_startproc
 26         pushl   %ebp                
 27         .cfi_def_cfa_offset 8
 28         .cfi_offset 5, -8
 29         movl    %esp, %ebp
 30         .cfi_def_cfa_register 5
 31         subl    $20, %esp
 32         movl    $2, -4(%ebp)
 33         movl    -4(%ebp), %eax
 34         movl    %eax, (%esp)
 35         call    test
 36         movl    $0, %eax
 37         leave
 38         .cfi_restore 5
 39         .cfi_def_cfa 4, 4
 40         ret
 41         .cfi_endproc
 42 .LFE1:
 43         .size   main, .-main
 44         .ident  "GCC: (GNU) 4.6.1 20110908 (Red Hat 4.6.1-9)"
 45         .section        .note.GNU-stack,"",@progbits

先从汇编看,从main开始,26~29行,大家应该比较熟悉,汇编函数标准的程序开头
 26         pushl   %ebp                //堆栈基地址入栈,每个函数都会有自己的局部变量,我觉得这里的目的在于使每个函数都有
                                                    //自己独立的栈空间,这样就不会互相干扰,这一句的作用就是保存该函数前面使用的堆栈
                                                    //环境,main函数其实没什么特别,它也是被别人调用的,因此也要做这些保存工作
 27         .cfi_def_cfa_offset 8
 28         .cfi_offset 5, -8
 29         movl    %esp, %ebp    //把当前堆栈顶指针作为当前函数的堆栈基地址

 31         subl    $20, %esp        //在堆栈里面预留一些空间来存放局部变量
 32         movl    $2, -4(%ebp)   //这里的 a 是局部变量,把 2 赋值给a 存放在(%ebp - 4)的堆栈里
 33         movl    -4(%ebp), %eax  //把 a 的值 放到寄存器 %eax里面
 34         movl    %eax, (%esp)      //再把 a 的值放到当前堆栈顶,这个是为什么呢?
35         call    test                         //调用test 函数
 36         movl    $0, %eax              //return 0
 37         leave

接下来看test函数的汇编代码:
  8         pushl   %ebp                   //同前面讲过的main函数,这里是保存main函数的堆栈基地址指针
  9         .cfi_def_cfa_offset 8
 10         .cfi_offset 5, -8
 11         movl    %esp, %ebp       //当前函数的基地址设为%esp
 12         .cfi_def_cfa_register 5
 13         addl    $1, 8(%ebp)        //这里是我猜测的啊,从main函数32,33,34行可以知道,有三个地方存放变量a的数值,其中
                                                      //32行是存放main函数的局部变量a,33行是存放 调用函数实参的,34行这个就看不明白了。
                                                      //而此处,为什么是8(%ebp)呢,画一个图就很清楚了,其中隐藏的一点就是call调用时,也会
                                                      //做一次入栈操作,目的是保存eip的指针,即函数返回后需要执行的下一条指令的地址。这里就占用站哟
                                                       //4个字节,然后,test函数开始处需要保存%ebp,又占用4个字节,当前的%ebp加8个字节
                                                      //正好到了34行的地址处,这里存放着a = 2
 14         popl    %ebp                   //%ebp出栈
 15         .cfi_def_cfa 4, 4
 16         .cfi_restore 5
 17         ret                                   //函数返回,%eip出栈
阅读(1189) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~