Chinaunix首页 | 论坛 | 博客
  • 博客访问: 9605
  • 博文数量: 5
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 50
  • 用 户 组: 普通用户
  • 注册时间: 2015-03-08 18:47
文章分类
文章存档

2015年(5)

我的朋友
最近访客

分类: C/C++

2015-03-08 23:14:04

0 前言    
    在初学编程语言时,一般都从C语言开始入手。 但看似语法简单,逻辑清晰易读的C代码如何在计算机上工作呢。我们进行如下实验来做一个初步分析。                                                                                     

1 C语言源码

点击(此处)折叠或打开

  1. int g(int x)
  2. {
  3.   return x + 3;
  4. }
  5.  
  6. int f(int x)
  7. {
  8.   return g(x);
  9. }
  10.  
  11. int main(void)
  12. {
  13.   return f(8) + 1;
  14. }
如上述代码所示,我们通过阅读代码,发现上述代码通过多层函数调用,经过计算得到了结果。但在计算机上是如何完成这次计算的呢?
                                                                              
2 汇编




3 分析
从汇编代码逐行分析可以得到,当调用栈最长的时候(即从main调用了f再调用了g时),栈区内容如下图所示。
   
我们根据上图,结合汇编代码,来进行分析。
1) enter 进入函数
    pushl %ebp            ;保存本函数调用者函数的堆栈顶     注:课件中的初始%ebp位置不合适 ,main前面依然有函数调用,所以不太可能跟%esp在此时重叠。               
    movl  %esp %ebp   ;更新%ebp,保存本函数的堆栈顶                     
2) 取出调用函数提供的参数 (以f函数为例)
    subl  $4 %esp
    movl  8(%ebp), %eax   ;x86结构通过堆栈而不是寄存器传参(? 编译优化会不会改变传参方式? ),本行获取调用者传递的参数。                               
    movl  %eax, (%esp)     ;这里%eax寄存器进行了“中转”,看似所有传参都是会从stack中取到%eax中。                                                                                        
3) 构建临时变量 (以main函数为例)                                        
    subl  $4, %esp     
    movl  $8,(%esp)    ;实际上相当于把临时变量 8压栈。 
   注:main函数写的比较简单,不能算构建临时变量,直接通过f(8)进行函数调用,并没有构建变量。 如果构建临时变量并传参的话,汇编了一下,情况比较复杂,超出了本题目范围,就不在本文描述了。 
4)  进行计算(以g函数为例)   
    addl  $3, %eax       ;就是计算,没什么好说的,返回值写到%eax中。                                                        
5) return 退出函数
     movl %ebp %esp  
     popl %ebp    ;与enter相对,%esp还原到上一个函数的栈底, %ebp还原到上一个函数栈顶。                                                          
    
4 结论 
通过上一节的分析,我们总结出, 
程序的执行的过程就是函数调用与执行完毕的过程,伴随着堆栈的压入与弹出。

每个函数的执行大体分为几个步骤:
函数进入(保存上一个函数的%ebp,  更新 %ebp %esp   )       --->  
参数获取(通过%ebp寻找压栈的位置)     --->
构建临时变量(一般用于计算结果保存,或调用其他函数)  --->
函数计算 --->
计算结果返回                             
   

                 
作者:胡川         
原创作品转载请注明出处
《Linux内核分析》MOOC课程     
阅读(461) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

nemonic272015-03-15 20:50:19

栈划分画错了。