首页 > 其他 > 详细

程序声明周期

时间:2019-03-28 14:56:21      阅读:116      评论:0      收藏:0      [点我收藏+]
1、基本过程 
    1) 编写源代码
    2) 编译
    3) 链接
    4) 装载
    5) 执行
 
2、编译阶段
 
2.1 预处理阶段
  • 将#include关键字标示的含有定义(包含文件或头文件)包含到源代码文件中
  • 将#define语句的指定的值转换成常量
  • 在代码中调用宏的位置将宏定义转换成代码
  • 根据#if、#elif 和#endif 指令的位置包含或排除特定部分的代码
 
2.2 语言分析阶段
  • 词法分析:将源代码分割成不可分割的单词
  • 语法分析:将提取出来的单词接成单词序列,并根据编程语言规则验证其顺序是否合理
  • 语义分析:目的是发现符合语法规则的语句是否具有实际意义。比如,将两个整数相加并把结果赋值给一个对象的语句,虽然能通过语法规则的检查,但可能无法通过语义检查
 
2.3 汇编阶段
    编译器会将标准的语言集合转换成特定CPU指令集的语言集合。不同的CPU包含不同的功能性需求,通常包含不同的指令集、寄存器和中断,所以不同的处理器要有不同的编译器对其支持。对于x86处理器体系结构来说,编译器支持两种指令格式,汇编代码会遵循其中一种:
  • AT&T格式
  • Intel格式
 
2.4 优化阶段
    当由源代码文件生成最初版本的汇编代码后,优化过程就开始了,这可以将程序的寄存器使用率最小化。此外,通过分析能够预测出实际上不需要执行的部分代码,并将其删去
 
2.5 代码生成阶段
    生成编译输出目标的阶段,其中每一个目标文件对应一个编译单元。汇编指令(用可读的ASCII码编写)会在此阶段转换成对应机器指令(操作码)的二进制值,并写入目标文件的特定位置
 
2.6 编译过程的局限性
    绝大多数情况下,将源代码翻译成目标文件的过程十分简单:将代码行翻译成特定处理平台运行的机器代码指令,或者为初始化变量预留空间并对这些变量初始化,或者为初始化变量预留空间并用0填充等。
    但这个过程会导致一些问题:虽然源代码被分成多个源代码文件存放,但要组成一个程序,那么他们之间必然存在一定的关联。这些单独存放的代码一般会通过下面方式之一来建立联系:
  • 功能独立的代码之间的函数调用
  • 外部变量
 
3、链接
 
3.1 重定位
    链接过程的第一个阶段仅仅进行拼接,其过程是将分散在单独目标文件中不同类型的节拼接到程序内存映射节中。为了完成该任务,需要将之前预留的空间,也就是节中从0开始的地址范围转换成最终程序内存映射中更具体的地址范围。
 
3.2 解析引用
    需要在链接阶段对引用进行解析,此时链接器需要:
  • 检查拼接到程序内存映射中的节
  • 找出哪些部分代码产生了外部调用
  • 计算该引用的精确地址(在内存映射中的地址)
  • 最后,将机器指令中的伪地址替换成程序内存映射的实际地址,这样就完成了引用的解析
  链接过程的最终结果是二进制可执行文件,其结构布局遵循特定目标平台的可执行文件格式。
  无论实际格式有什么区别,可执行文件总会包含几个合成的节(.text、.data、.bss节以及其他特殊的节),这些节是通过拼接单独的目标文件得到的。
  尤其是,为了解析各个编译单元之间的引用,确保不同部分之间的函数调用与变量访问准确有效,生成代码节(.text)时,不能仅仅简单的拼接目标文件中的节,还需要对链接器进行修改。
 
  main函数看起来是整个程序执行的起点,但却不是程序启动后真正首先执行的代码。
  有一个很重要的细节,可执行文件并不完全是通过编译项目源代码文件生成的,实际上,用于启动程序的一部分非常重要的代码片段是在链接阶段才添加到程序内存映射中的。
链接器通常将这部分代码存放在程序内存映射的起始处,有两种不同形式:
  • crt0是“纯粹”的入口点,这是程序代码的第一部分,在内核控制下执行。
  • crt1是更为现代化的启动例程(startuproutine),可以在main函数执行前与程序终止后完成一些任务

程序声明周期

原文:https://www.cnblogs.com/UniqueSquirrel/p/10614873.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!