• 程序是怎么运行的?


         也许我们习惯了在IDE环境中敲代码、执行程序,只需一个键就能完成从编译、汇编、链接到显示结果的所有工作。。

    那么你有没有疑惑过,当你执行一个简单的C程序时,它内部到底发生了什么呢?下面我们就从汇编语言的层面上来分析一下程序运行的全过程。

         假设我写了一个简单的a+b的程序:
         接下来我把它编译成汇编代码。注意:在Unix/Linux下使用的是AT&T格式的汇编语言,而Dos/Windows下是Intel风格的汇编。这两者在语法格式上还是有很大的不同的。由于这里是在Linux系统上编译的,所以产生的是AT&T格式的汇编。
    将上面的代码保存为main.c。下面对main.c进行编译:
     
    1. gcc –S –o main.s main.c -m32
     
         这里的-S表示输出汇编代码(如果不加的话就直接生产目标文件了)。后面的-m32表示生成32位的汇编代码。
    执行这条命令后,产生了如下汇编代码main.s:
         注意:生成的汇编代码会有一些其它的信息,这里我把它们删了,我们只分析和我们的C代码密切相关的部分。
         我们知道,系统会为每个进程分配一个堆栈空间(关于进程的堆栈空间的详细介绍请参考《Unix环境高级编程》):
         程序中的变量包括函数调用占用的都是栈的空间,它的地址是向下递减的。那么初始化栈假设是这样的:
         这里为了简化问题,假设栈底地址为100,由于地址向下递减,所以依次是96,92,88.....
    %ebp和%esp是寄存器,其中%ebp存放的是栈底指针,而%esp存放的是栈顶指针。
     
         首先从main函数开始执行:
    pushl %ebp      
         表示把%ebp寄存器中的内容压入堆栈,这时%esp就指向地址96处了(栈顶指针自动减4,因为是按32位寻址的。。)。
    movl %esp,%ebp
         表示将栈顶指针赋值给栈底指针,那么这时%ebp就是96了。
    subl $24,%esp
         将栈顶指针减去24,这时%esp指向72.
    movl $1,-12(%ebp)
    movl $2,-8(%ebp)
         这两条指令表示把立即数1和2分别放置到(%ebp)减去12和减去8的位置上。
    movl -8(%ebp),%eax
    movl %eax,4(%esp)
         表示把2赋给%eax,然后再放置在(%esp)+4的位置上。下面两天指令也相同。发现没?这里就是在给函数add()传递参数呢。。
         此时,栈的情况如下:
         接下来执行:
    call add
         call指令开始调用add函数,它的作用相当于下面两天指令:
    pushl %eip
    movel add %eip
         其中%eip寄存器存放的是当前执行的指令的地址。这里调用了call以后,相当于把当前指令的地址压入栈中,此时%esp指向68,然后把add函数要执行的指令的地址赋给%eip。
         接下来开始执行add函数中的指令,流程和上面的一样。
         这时又用pushl %ebp把栈底指针入栈,你可能会有疑问,为什么每次调用一个函数都需要把%ebp入栈呢?其实你会发现,当add函数执行到后来,有一个popl %ebp指令,这个指令相当于把原来入栈的%ebp又恢复原值了,这个时候的%ebp指向的就是main函数的栈底了(相当于又回到main函数的环境了)。当然add函数里还有一个ret,ret指令代表popl %eip,就是把原来的%eip有恢复原值了,这样代码执行流就回到了main函数中调用add函数的下一条指令了。
     
         当main函数执行完movl %eax,-4(%ebp)后,开始执行leave,leave指令相当于如下两条指令:
    mov %ebp,%esp
    pop %ebp
         发现了吗?这里相当于恢复调用main函数之前的栈情况了,借着执行ret后就回到原先的指令流了。这时候栈就恢复到最开始的状态啦。。简单吧?关于函数调用过程中栈空间的变化情况现在了解一点了吗?
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    String
    Map和Set
    js的栈与堆
    js的私有属性
    随便谈一谈原型
    前端页面优化提速
    nth-child和nth-of-type
    重复输出字符串
    闭包
    mongodb内嵌文档的查询
  • 原文地址:https://www.cnblogs.com/yudao/p/4364124.html
Copyright © 2020-2023  润新知