zoukankan      html  css  js  c++  java
  • 分析一个C语言程序生成的汇编代码-《Linux内核分析》Week1作业

    署名信息

    郭春阳 原创作品转载请注明出处 :《Linux内核分析》MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 
    

    C源码

    这里为了防止重复,修改了部分源码

    int g(int x)
    {
      return x + 99;
    }
    
    int f(int x)
    {
      return g(x);
    }
    
    int main(void)
    {
      return f(22) + 36;
    }
    

    运行 gcc -S -o foo.s -m32 foo.c后,生成的汇编代码为:

    g:
    	pushl	%ebp
    	movl	%esp, %ebp
    	movl	8(%ebp), %eax
    	addl	$99, %eax
    	popl	%ebp
    	ret
    f:
    	pushl	%ebp
    	movl	%esp, %ebp
    	pushl	8(%ebp)
    	call	g
    	addl	$4, %esp
    	leave
    	ret
    main:
    	pushl	%ebp
    	movl	%esp, %ebp
    	pushl	$22
    	call	f
    	addl	$4, %esp
    	addl	$36, %eax
    	leave
    	ret
    

    分析代码运行过程

    首先进入main函数:

    `pushl	 %ebp, movl %esp, %ebp`两行代码,将ebp压入栈,  
    然后esp的值赋给ebp,这里esp的值先减4,ebp指向与esp相同的位置  
    以上指令相当于enter,进入了一个新的函数调用栈  
    将22压入栈(这里其实是定义接下来调用的f的形参int x,并赋值)  
    调用f,这里先保存eip(PC计数器)的值入栈,esp的值-4,然后将f的地址赋给eip  
    

    进入f函数:

    执行enter的两条指令,进入新的函数调用栈(同上)  
    将ebp向前8个字节位置的值(main中压栈的22)压栈,esp-4  
    这里是定义g的形参并赋值  
    调用g,eip先压栈,然后eip变为g的地址
    

    进入g函数:

    首先执行enter的两条指令,进入新的调用栈(同上)  
    `movl	8(%ebp), %eax` 首先寻址,将f中压栈的数(也就是g的形参x),赋给eax  
    `addl	$99, %eax` eax中得值+99,对应C语句 x + 99  
    `popl	%ebp` 这里因为g中没有开辟新的栈空间(esp的值没有变化),所以这句和leave语句等价  
    执行完,这一句,ebp恢复到之前的值(f中得状态)  
    执行ret,其实是执行popl eip,将栈中保存的eip的值,赋给eip  
    此时ebp、esp和eip均恢复到调用f中得状态
    退出g,返回值保存在eax中  
    

    回到f函数:

    `addl    $4, %esp`  esp+4,因为前面进行了pushl开辟新的变量,所以这里需要丢弃栈顶  
    之后执行leave 和 ret,恢复esp、ebp、eip的值,同上
    f仅仅返回g的返回值,这里不改动eax,里面保存着g的返回值
    

    回到main函数:

    `addl    $4, %esp`丢弃栈顶,原因是上面进行push,定义了新的变量  
    ` addl    $36, %eax` f(22)的返回值+36,相当于C中得 f(22) + 36
    main函数leave ret 返回上一层 
    gcc中应该为__libc_start_main,它可以接收到main的返回值,在eax中
    

    注意点

    1.C中的函数,是先定义形参并赋值,然后才进入该函数代码  
    2.函数调用中占用的栈空间,不仅仅包括局部变量,还包括22这种常量  
    3.每次函数调用,都执行enter,这条指令的效果相当于开辟了一个新的空栈  
    4.call调用函数时,eip保存的是call的下一条指令  
    

    博客截图

    实验环境是在Ubuntu 14.10 32bit,在mac OS X上远程登录  
    

    对计算机工作流程的认识

    图灵机可以执行某些特定操作 
    通用图灵机可以执行传给它的指令  
    现在计算机采用冯诺依曼体系结构,将程序和数据均存储在内存中,只需要程序员编写计算机可以识别的代码即可,计算机会将这些代码编译为可执行的指令。
  • 相关阅读:
    Virt-install用法:
    kvm笔记
    配置centos7解决 docker Failed to get D-Bus connection 报错
    linux系统下的用户文件句柄数限制
    Linux下如何通过命令检查网卡是否插上网线
    data命令详解
    cron job 里面,如何让脚本半分钟运行一次?
    bash编程之循环控制:
    bash编程之case语句,函数
    0129集训授课——面向对象思想(一):封装与抽象
  • 原文地址:https://www.cnblogs.com/inevermore/p/4321181.html
Copyright © 2011-2022 走看看