01程序编译过程分析,预处理,编译,汇编,链接

yumo6661个月前 (05-11)技术文章10

前言

我们大多数开发人员在编写完程序之后都会通过相应的IDE执行编译的操作,将所编写的源代码转换成计算机可以识别并执行的文件。这个从源代码转换成可执行文件的过程有相应的IDE帮助我们完成,很多朋友对于这个过程都不太熟悉,今天我们就一起探讨下可执行文件的生成过程,这个过程又叫做程序的编译与链接。

一:hello word由浅入深

对于程序员开发者来说,hello world程序的编写,大家闭上眼睛都能写出来,今天我们就以hello world为例来探讨一下可执行文件的生成过程,废话不多说,下面就是hello word的源码

#include <stdio.h>

int main()

{

    printf("hello, world\n");

}

上面代码的功能就是输出hello,word。然而计算机不可能直接执行hello world.c下面我们用一张图来讲一下hello world.c是如何被被执行。

从上面的图中,我们大致可以看到,hello.c要想变成计算机可以执行的hello(可执行目标文件)需要经过预处理,编译,汇编,链接等步骤,这些步骤主要是干什么的,有各自有什么作用,我们下面一一进行分析。

二:预处理

首先我们先来看一下预处理的执行命令

– $gcc –E hello.c –o hello.i

– $cpp hello.c > hello.i

预处理执行的功能:

  1. 删除“#define”并展开所定义的宏
  2. 处理所有条件预编译指令,如“#if”,“#ifdef”, “#endif”等
  3. 插入头文件到“#include”处,可以递归方式进行处理
  4. 删除所有的注释“//”和“/* */”
  5. 添加行号和文件名标识,以便编译时编译器产生调试用的行号信息
  6. 保留所有#pragma编译指令(编译器需要用)

经过预编译处理后,得到的是预处理文件(如,hello.i) ,它还是一个可读的文本文件 ,但不包含任何宏定义,上面所说的第3条插入头文件到“include”处,可以理解为将头文件里面的内容进行展开,下面用一张图来进行描述

三:编译

编译过程就是将预处理后得到的预处理文件(如 hello.i)进行词法分析、语法分析、语义分析、优化后,生成汇编代码文件。用来进行编译处理的程序称为编译程序(编译器,Compiler)

编译命令

– $gcc –S hello.i –o hello.s

– $gcc –S hello.c –o hello.s

– $/user/lib/gcc/i486-linux-gnu/4.1/cc1 hello.c

上面3条编译指令表明,我们可以通过.i文件输出汇编文件.s同时也可以直接将.c文件编译成.s文件。第3条指令则是通过编译器直接执行,与前两条执行效果一样。gcc命令实际上是具体程序(如ccp、cc1、as等)的包装命令,用户通过gcc命令来使用具体的预处理程序ccp、编译程序cc1和汇编程序as等

经过编译后,得到的汇编代码文件(如 hello.s)还是可读的文本文件,CPU无法理解和执行它,不要着急,我们接下来看下一步汇编命令的执行过程

四:汇编

首先我们先了解下汇编代码文件(由汇编指令构成)称为汇编语言源程序,其实就是上面编译过程结束之后生成的.s文件,这个文件就是汇编代码文件,改文件是有一条条汇编指令构成,汇编的作用就是讲这一条条汇编指令转换成对应的机器执行。

o 汇编程序(汇编器)用来将汇编语言源程序转换为机器指令序列(机器语言程序)

o 汇编指令和机器指令一一对应,前者是后者的符号表示,它们都属于机器级指令,所构成的程序称为机器级代码,汇编的过程比较简单,只需要将相应的汇编指令翻译成对应的机器指令即可,没有什么复杂的变化。

汇编命令

– $gcc –c hello.s –o hello.o

– $gcc –c hello.c –o hello.o

– $as hello.s -o hello.o (as是一个汇编程序)

汇编结果是一个可重定位目标文件(如,hello.o),其中包含的是不可读的二进制代码,必须用相应的工具软件来查看其内容

五:链接

哇,经过了上面一系列的流程,终于到了最后一步,我们的hello world 终于要完成了,下面我们就来看下最后一步链接的处理吧。

预处理、编译和汇编三个阶段针对一个模块(一个*.c文件)进行处理,得到对应的一个可重定位目标文件(一个*.o文件),但是在程序的编写过程中,我们都是多个.c文件的,这样经过上面的预处理,编译汇编的过程之后我们得到的也是多个.o(可重定位目标文件),但是我们在最终执行的时候是只有一个可执行文件的,这个过程就是连接的目的了。

链接过程将多个可重定位目标文件合并以生成可执行目标文件,大家可以看下最初时候的图,在最后一步连接的过程中,我们不只是要hell.o而且还需要printf.o(代码中含有printf函数),链接就是将这连个.o合并为一个生成可执行目标文件

链接命令

– $gcc –static –o myproc main.o test.o

– $ld –static –o myproc main.o test.o

–static 表示静态链接,如果不指定-o选项,则可执行文件名为“a.out”

相关文章

单片机入门-要从汇编开始(单片机汇编基础知识)

简介单片机是一种集成电路芯片,是采用超大规模集成电路技术把具有数据处理能力的中央处理器CPU、随机存储器RAM、只读存储器ROM、多种I/O口和中断系统、定时器/计数器、显示驱动电路、脉宽调制电路、模...

学习汇编的意义在哪里?(汇编要学到什么程度)

对于编程,一直是我钟情的爱好,可能因为骨子里刻着那种刨根问底的DNA吧。都说懒惰是人类进步的动力,我看也不尽然,因为学习一项新知识必要付出加倍的努力。一开始只是为了摆脱枯燥重复的录入,自学了Pytho...

新手攻略!入门ARM必须要理解的22个常用概念

罗列了关于ARM的22个常用概念。包括一些使用注意事项、ARM启动代码设计、ARM处理器运行模式、ARM体系结构所支持的异常类型和一些基本操作方法等等。01ARM中一些常见英文缩写解释MSB:最高有效...

系统设计硬核知识(1)——操作系统的类型和结构

一、一个观点、两条线索。一个观点:以资源管理的观点来定义操作系统;从资源管理的角度看,操作系统主要是对处理器、存储器、文件、设备和作业进行管理。两条线索:如何管理计算机各类资源、控制程序的执行。现在讲...

嵌入式工程师到底要不要学习ARM汇编指令?

嵌入式工程师到底要不要学习ARM汇编指令?网上搜索这个问题,答案很多,大部分的建议是不要学汇编,只要学C语言。而一口君作为一个十几年经验的驱动工程师,个人认为,汇编语言还是需要掌握的,想要搞精、搞深,...