代码编织梦想

程序编译过程


version : v1.0 「2022.7.28」 最后补充

author: Y.Z.T.


简介: 简单记录程序的编译过程




⭐️ 目录




1️⃣ 编译流程

程序的整个编译流程大致分成几个阶段:

  • 预处理 : 将预处理指令进行处理 , 预处理器将源文件(.c) 经过预处理变成 文件(.i )
  • 编译 : 编译器调用解析工具 , 将预处理后的源文件( .i )编译成汇编文件( .s)
  • 汇编 : 这是也是编译的第二阶段 , 通过汇编器将汇编文件( .s) 汇编成可重定位的目标文件( .o)
  • 链接 : 将各个目标文件( .o)链接成可执行文件( 也是可执行文件的一种 )

程序编译 , 链接流程图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SbSXbHIx-1664787594242)(https://pic1.imgdb.cn/item/633aa48716f2c2beb1e98a0d.png)]



2️⃣ 可执行文件

一个可执行文件通常由一系列不同的段(section)构成:代码段数据段BSS段只读数据段等。

C语言到可执行文件 :

image-20220928114314496

  • 函数翻译成二进制指令放在代码段
  • 初始化的全局变量静态局部变量放在数据段中(.data)
  • 未初始化的全局变量静态变量放在BSS段中(.bss)
  • 程序中定义的一些字符串 , printf函数打印的字符串常量放在**只读数据段( .rodata)**中


3️⃣ 预处理

预处理过程就是 在编译源程序之前 , 先处理源文件中的各种预处理指令


预处理主要包括以下操作 :

  • 头文件展开:#include包含的头文件内容展开到当前位置 , 并删除#include
  • 宏展开: 展开所有的宏定义,并删除#define
  • 条件编译: 根据宏定义条件,选择要参与编译的分支代码,其余的分支丢弃。
  • 删除注释
  • 添加行号和文件名标识: 编译过程中根据需要可以显示这些信息。
  • 保留#pragma命令: 该命令会在程序编译时指示编译器执行一些特定行为。


4️⃣ 编译

汇编过程主要包括以下步骤 :

  • 词法分析

  • 语法分析

  • 语义分析

  • 中间代码生成

  • 汇编代码生成

  • 目标代码生成



4.1 词法分析

词法分析主要用来解析C程序语句 , 词法分析一般会通过词法扫描器从左到右 , 将源程序分解为一系列不能再分解的记号单元–token。


常见token

  • C语言的各种关键字: int,floatfor,whilebreak等。
  • 用户定义的各种标识符: 函数名变量名标号等。
  • 字面量: 数字字符串等。
  • 运算符: C语言标准定义的40多个运算符。
  • 分隔符: 程序结束符分号、for循环中的等

示例:

sum = a + b / c;

如上所示:

  • 经过词法分析后 分解成 sum ,=, a ,+, b, /, c,; 八个token
  • 如果程序出现中文符号圆角\半角字符 等 ,程序就会在这个阶段发错编译错误


4.2 语法分析

语法分析主要是对前一阶段产生的token序列进行解析, 看是否能构建成一个语法上正确的语法短语(程序、语句、表达式等)。


说明:

  • 词法分析语法分析工具在对token序列分析过程中, 如果发现不能构建语法上正确的语句或表达式,就会报语法错误: syntax error
  • 如果程序语句后 少了结束分号循环中少了分号 ,就会在此阶段产生编译错误


4.3 语义分析

语义分析主要对语法分析输出的各种表达式、语句进行检查,看看有没有错误。


例如 :

  • 传递给函数的实参与函数声明的形参类型不匹配,
  • 使用了一个未声明的变量
  • 除数为零了;
  • break在循环语句或switch语句之外出现了,
  • 在循环语句之外发现了continue语句等


4.4 生成中间代码

说明:

  • 中间代码是一维线性结构 , 类似伪代码
  • 通过中间代码 , 可以很容易的将中间代码翻译成汇编代码

示例:

int main(void)
{
    int sum = 0;
    int a = 2;
    int b = 1;
    int c = 1;
    sum = a + b / c;
    return 0;
}

转换为中间代码三地址码:

main ()
{
    int D.4227;
    int D.4228;
    
    {
        int sum;
        int a;
        int b;
        int c;
        
        sum = 0;
        a= 2;
        b= 1;
        C= 1;
        D.4227 = b / c;
        sum =D.4227 + a;
        D.4228 = 9;
        return D.4228;
    }
    D.4228 = 0;
    return D.4228;
}

中间代码转换为 汇编代码:

MOV R0, #2		
MOV R1, #1
MOV R2, #1
DIV R3, R1, R2		; R3 = R1 / R1
ADD R0 RO.R3		; R0 = R0 + R3
  • 将变量变量a、b、c分别放到寄存器R0、R1、R2中,
  • 临时变量D.4427使用R3代替,然后使用ADD命令完成累加。


4.5 汇编过程

  • 汇编器主要是 将汇编代码翻译成对应的二进制指令;
  • 同时生成一些必要的信息 , 以section的形式组装到目标文件中

汇编过程:

image-20220928233023855



5️⃣ 链接过程

  • 编译器在编译一个项目时,是以C源文件为单位进行编译的,每一个源文件编译生成一个对应的目标文件(.o)
  • 但这些单独的目标文件(.o)是不可执行的 , 属于可重定位的目标文件;
  • 它们要经过链接器重定位链接之后,才能组装成一个可执行的目标文件a.out。
  • 链接器将各个目标文件组装在一起后, 重新修改各个目标文件中的变量或函数的地址,这个过程一般称为重定位
  • 链接过程中 , 将各个目标文件分段组装 ; 例如 : 将各个目标文件的代码段放在一起,作为最终生成的可执行文件的代码段; 将各个目标文件的数据段放在一起,作为可执行文件的数据段。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_51330198/article/details/127153883

android应用程序编译过程简述-爱代码爱编程

引言 Android编译过程是指Java代码以及xml等资源文件转变为.apk文件的过程,本文将简单阐述这一过程,但不会深入,建立这一概念,为了更好的学习Android。此文参考了《Android编程权威指南》一书。 编

程序编译的四个过程_hello_hpc的博客-爱代码爱编程_程序编译的四个步骤

编译程序生成可执行文件四个阶段: GCC驱动程序读取源文件.c比如hello.c,并把它翻译成一个可执行目标文件hello,需要经历一下四个阶段,如下图示:   预处理阶段。预处理器(cpp)根据以字符#开头的命令,修改原始的C程序。比如hello.c中第一行的#include<stdio.h>命令告诉预处理器读取系统头文件stdi

qt程序编译过程_lsfreeing的博客-爱代码爱编程_qt 编译

qmake是一个协助简化跨平台进行专案开发的构建过程的工具程式,Qt附带的工具之一 。qmake能够自动生成Makefile、Microsoft Visual Studio 专案文件 和 xcode 专案文件。不管源代

linux程序编译过程_lw_yang的博客-爱代码爱编程_linux编译汇编程序

大家肯定都知道计算机程序设计语言通常分为机器语言、汇编语言和高级语言三类。高级语言需要通过翻译成机器语言才能执行,而翻译的方式分为两种,一种是编译型,另一种是解释型,因此我们基本上将高级语言分为两大类,一种是编译型语言,例如

程序编译的4个过程_肥嘟嘟的左卫门的博客-爱代码爱编程_编译过程

0.引言 hello.c(源程序)是一条高级C语言程序,虽然它是以一种易读的形式,让人们容易理解。但是,它却无法直接驱动硬件CPU直接执行。为了我们编写的hello.c程序可以被执行,驱动硬件电路工作,hello.c程序必须经过一些列处理步骤,将源程序转化为可执行性的目标程序。 而我们知道,机器语言就是处理器可以直接理解(与生俱来就能理解)的编程语言,机

程序编译整个的过程-爱代码爱编程

程序编译的过程 应用程序从用户编写的源文件到内存中执行的进程,大致分为了一下几个阶段:首先编译程序将源代码编译成了多个目标模块,其次通过链接程序将编译好的目标模块,以及所需要的一些库函数链接在一起,形成了完整的装入模块,再通过装入程序将这些装入模块装入内存并执行。   整个程序编译的过程大致如下:   编译:编译的过程就是把用户的源代码编译成

程序编译的详细过程-爱代码爱编程

一、c/c++程序编译过程 C语言的编译连接过程把我们编写的一个c程序(源代码)转换成可以在硬件上运行的程序(可执行文件:win下是.obj,linux下是.so),通过编译和链接两个步骤实现。 为了我们编写的hello.c程序可以被执行,驱动硬件电路工作,hello.c程序必须经过一些列处理步骤,将源程序转化为可执行性的目标程序。 编译:把文本形式源

c语言程序的编译过程-爱代码爱编程

操作系统:ubantu 工具gcc 文件:test.c abner@DESKTOP-M6D2HEN:~/mytest$ cat test.c #include<stdio.h> #define MAXC 3 #define MAXB MAXC + 1 #define MAXA MAXB + 2 int main() {

java编译过程_java 程序编译和运行过程详解-爱代码爱编程

java整个编译以及运行的过程相当繁琐,这里有个简单的例子。 Java程序从源文件创建到程序运行要经过两大步骤: 1、源文件由编译器编译成字节码(ByteCode); 2、字节码由java虚拟机解释运行。因为java程序既要编译同时也要经过JVM的解释运行,所以说Java被称为半解释语言(“semi-interpreted” language)。

程序的编译流程-爱代码爱编程

1.程序的编译过程 程序的编译过程大致可以分为以下几个阶段 2.预处理阶段: 预处理阶段主要发生: 1.头文件的包含 2.清除注释 3.宏的替换 4.处理所有的条件编译指令,如#ifdef #ifndef #endif等,也就是带#那些 5.保留#pargma指令 下面我么来看一段代

oc程序编译过程-爱代码爱编程

.m文件编写代码-》编译生成o文件-》链接其他关联的.o文件生成可执行编译程序a.out 命令 只编译不进行链接生成xx.o文件(只要包含函数声明就可以): cc -c xx.m 链接生成可执行文件默认生成a.out(要链接函数的定义,oc默认不会链接系统的库,要手动链接) cc xx.o 用到其他库: cc xx.o -framework xxx 一步

C++程序编译过程-爱代码爱编程

C++程序编译过程 1.编译流程图2.预处理3.编译4.汇编5.链接 1.编译流程图 2.预处理 编译器将C程序的头文件编译进来,还有宏的替换,可以用gcc的参数-E来参看。 主要处理源代码文件中的以“#”开头的预编译指令。处理规则见下 1、删除所有的#define,展开所有的宏定义。 2、处理所有的条件预编译指令,如“#if”、

C语言编译过程-爱代码爱编程

C语言编译过程 C程序编译步骤gcc编译过程分步编译一步编译查找程序所依赖的动态库 C程序编译步骤 C代码编译成可执行程序经过4步: (1)预处理:宏定义展开、头文件展开、条件编译等,同时将代码中的注释删除,这里并不会检查语法 (2)编译:检查语法,将预处理后文件编译生成汇编文件 (3)汇编:将汇编文件生成目标文件(二进制文件) (4)链接:

程序的编译过程(简述)-爱代码爱编程

目录 前言 1. 编译的流程 2. 预编译 3. 编译 4. 汇编 5. 链接 前言 对于一个C程序,通常的开发环境都是流行的集成开发环境(IDE) ,例如Visual Studio、devc++等。通常在IDE内部集成了编译器和链接器,以至于我们不需要关注编译和链接的细节,只需要注意编程语言的语法正确性就可以写成能成功运行的代码,这

qt 学习(四) —— qrc资源文件介绍与使用_万俟淋曦的博客-爱代码爱编程

Qt工程分组中,除了Headers、Sources、Forms外,还有一个文件夹Resources,只有当工程中有图片、音频等资源文件时才会用到。 首先将资源文件存放到工程目录下的文件夹中,然后添加.qrc文件,方法如下:

cesium学习七:使用callbackproperty更新entity_小何又沐风的博客-爱代码爱编程

一、前言 本学习流程到目前为止已经学习了点、线、多边形、棱柱、椭球等几何体的绘制,这些都是比较常见的,当然Cesium提供的几何体不止上述几种,还有很多,使用方式基本相同,参数除了几何数据外,绘制参数大同小异,所以其他的几

c/c++程序的编译过程_c++ 编译过程-爱代码爱编程

我们拿到一个.c或者是.cpp源文件,它是怎么样一步步的变化成一个机器可执行文件的呢?程序的一般编译流程主要包括四大部分:预处理、编译、汇编和链接。下面讲解这四步的具体工作,带你了解源文件到可执行文件是怎样生成的。