从源码到可执行程序的步骤

以下内容源于朱有鹏《物联网大讲堂》课程的学习整理,以及网页http://mp.weixin.qq.com/s/_iVrUtA-jgE8XAR-vKYcww的学习整理。如有侵权,请告知删除。


一、总结

从源码到可执行程序的步骤:预编译、编译、汇编、链接。前三个宏观上为编译,但可以细分为三者。

  • 预编译    :      预编译器执行,譬如C中的宏定义、注释等由预编译器处理。
  • 编译        :      编译器来执行,把源码.c .h等变成汇编文件。
  • 汇编 :      汇编器来执行,将.S变成机器码.o文件。
  • 链接        :      链接器来执行,把各个.o文件中的各个段,按照一定规则(链接脚本来指定)累积在一起,形成可执行文件。
  • strip        :      strip是把可执行程序中的符号信息给拿掉,以节省空间。(Debug版本和Release版本);
  • objcopy  :      由可执行程序生成可烧录的镜像bin文件。


二、C语言的编译、链接过程细述

编译,就是把文本形式源代码翻译为机器语言形式的目标文件的过程。

链接,是把目标文件、操作系统的启动代码和用到的库文件进行组织,形成最终生成可执行代码的过程

编译过程细分为预编译、编译、汇编三个阶段

1、预编译阶段

预处理阶段,在正式的编译阶段之前进行。

  • 预处理阶段将根据已放置在文件中的预处理指令来修改源文件的内容。如#include指令就是一个预处理指令,它把头文件的内容添加到.cpp文件中。
  • 这个在编译之前修改源文件的方式提供了很大的灵活性,以适应不同的计算机和操作系统环境的限制。
  • 一个环境需要的代码跟另一个环境所需的代码可能有所不同,因为可用的硬件或操作系统是不同的。
  • 在许多情况下,可以把用于不同环境的代码放在同一个文件中,再在预处理阶段修改代码,使之适应当前的环境。


主要是以下几方面的处理:

  • 宏定义指令,如 #define a  b。对于这种伪指令,预编译所要做的是将程序中的所有a用b替换,但作为字符串常量的 a则不被替换。还有 #undef,则将取消对某个宏的定义,使以后该串的出现不再被替换。
  • 条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif等。这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。预编译程序将根据有关的文件,将那些不必要的代码过滤掉。
  • 头文件包含指令,如#include "FileName"或者#include <FileName>等。在头文件中一般用伪指令#define定义了大量的宏(最常见的是字符常量),同时包含有各种外部符号的声明。采用头文件的目的主要是为了使某些定义可以供多个不同的C源程序使用。因为在需要用到这些定义的C源程序中,只需加上一条#include语句即可,而不必再在此文件中将这些定义重复一遍。预编译程序将把头文件中的定义统统都加入到它所产生的输出文件中,以供编译程序对之进行处理。包含到c源程序中的头文件可以是系统提供的,这些头文件一般被放在 /usr/include目录下。在程序中#include它们要使用尖括号(< >)。另外开发人员也可以定义自己的头文件,这些文件一般与c源程序放在同一目录下,此时在#include中要用双引号("")。
  • 特殊符号,预编译程序可以识别一些特殊的符号。例如在源程序中出现的LINE标识将被解释为当前行号(十进制数),FILE则被解释为当前被编译的C源程序的名称。预编译程序对于在源程序中出现的这些串将用合适的值进行替换。
预编译程序所完成的基本上是对源程序的“替代”工作。经过此种替代,生成一个没有宏定义、没有条件编译指令、没有特殊符号的输出文件。这个文件的含义同没有经过预处理的源文件是相同的,但内容有所不同。下一步,此输出文件将作为编译程序的输出而被翻译成为机器指令。


2、编译、优化阶段

  • 经过预编译得到的输出文件中,只有常量;如数字、字符串、变量的定义,以及c语言的关键字,如main,if,else,for,while,{,}, +,-,*,\等等。
  • 编译程序的工作就是通过词法分析和语法分析,在确认所有的指令都符合语法规则之后,将其翻译成等价的中间代码表示或汇编代码。
  • 优化处理是编译系统中一项比较艰深的技术。它涉及到的问题不仅同编译技术本身有关,而且同机器的硬件环境也有很大的关系。
  • 优化一部分是对中间代码的优化。这种优化不依赖于具体的计算机。主要的工作是删除公共表达式、循环优化(代码外提、强度削弱、变换循环控制条件、已知量的合并等)、复写传播,以及无用赋值的删除,等等。
  • 另一种优化则主要针对目标代码的生成而进行的。这种类型的优化同机器的硬件结构密切相关,最主要的是考虑是如何充分利用机器的各个硬件寄存器存放的有关变量的值,以减少对于内存的访问次数。另外,如何根据机器硬件执行指令的特点(如流水线、RISC、CISC、VLIW等)而对指令进行一些调整使目标代码比较短,执行的效率比较高,也是一个重要的研究课题。

3、汇编

汇编实际上指把汇编语言代码翻译成目标机器指令的过程。
  • 对于被翻译系统处理的每一个C语言源程序,都将最终经过这一处理而得到相应的目标文件.o。
  • 目标文件中所存放的也就是与源程序等效的目标的机器语言代码。
  • 目标文件由段组成。
  • 通常一个目标文件中至少有两个段
  • 代码段:该段中所包含的主要是程序的指令。该段一般是可读和可执行的,但一般却不可写。
  • 数据段:主要存放程序中要用到的各种全局变量或静态的数据。一般数据段都是可读,可写,可执行的。

UNIX环境下主要有三种类型的目标文件
  • 可重定位文件:其中包含有适合于其它目标文件链接来创建一个可执行的或者共享的目标文件的代码和数据。
  • 共享的目标文件:这种文件存放了适合于在两种上下文里链接的代码和数据。第一种是链接程序可把它与其它可重定位文件及共享的目标文件一起处理来创建另一个 目标文件;第二种是动态链接程序将它与另一个可执行文件及其它的共享目标文件结合到一起,创建一个进程映象。
  • 可执行文件:它包含了一个可以被操作系统创建一个进程来执行之的文件。汇编程序生成的实际上是第一种类型的目标文件。对于后两种还需要其他的一些处理方能得到,这个就是链接程序的工作了。

4、链接过程

  • 由汇编程序生成的目标文件并不能立即就被执行,其中可能还有许多没有解决的问题。例如,某个源文件中的函数可能引用了另一个源文件中定义的某个符号(如变量或者函数调用等);在程序中可能调用了某个库文件中的函数,等等。所有的这些问题,都需要经链接程序的处理方能得以解决。
  • 链接程序的主要工作就是将有关的目标文件彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体。
根据开发人员指定的同库函数的链接方式的不同,链接处理可分为两种:
(1)静态链接
  • 在这种链接方式下,函数的代码将(从其所在地静态链接库中)被拷贝到最终的可执行程序中。
  • 该程序在被执行时,这些代码将被装入到该进程的虚拟地址空间中。
  • 静态链接库实际上是一个目标文件的集合,其中的每个文件含有库中的一个或者一组相关函数的代码。
(2) 动态链接
  • 在此种链接方式下,函数的代码被放到称作是动态链接库或共享对象的某个目标文件中。
  • 链接程序做的工作,只是在最终的可执行程序中记录下共享对象的名字以及其它少量的登记信息。
  • 在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚地址空间。
  • 动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。
对于可执行文件中的函数调用,可分别采用动态链接或静态链接的方法。
  • 使用动态链接能够使最终的可执行文件比较短小,并且当共享对象被多个进程使用时能节约一些内存,因为在内存中只需要保存一份此共享对象的代码。
  • 但并不是使用动态链接就一定比使用静态链接要优越。在某些情况下动态链接可能带来一些性能上损害。



4、gcc中的编译细节


Linux使用的gcc编译器把以上的几个过程进行捆绑,使用户只使用一次命令就把编译工作完成。下图是gcc代理的编译过程:
 

(1)预编译
  • 将.c 文件转化成 .i文件;
  • 使用的gcc命令是:gcc –E;
  • 对应于预处理命令cpp;
(2)编译
  • 将.c/.h文件转换成.s文件;
  • 使用的gcc命令是:gcc –S;
  • 对应于编译命令   cc –S
(3)汇编
  • 将.s 文件转化成 .o文件;
  • 使用的gcc 命令是:gcc –c;
  • 对应于汇编命令是  as
(4)链接
  • 将.o文件转化成可执行程序;
  • 使用的gcc 命令是: gcc
  • 对应于链接命令是  ld

 总结起来编译过程就上面的四个过程:预编译、编译、汇编、链接。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/461558.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

win设置壁纸

默认壁纸图片位置&#xff1a; C:\Windows\Web\Wallpaper\Scenes 你可以自己建文件夹&#xff0c;放自己喜欢的桌面壁纸。 设置壁纸&#xff1a; 桌面右键 -> 个性化 然后点击 “桌面背景” -> 可以点击标题选择其下面的所有图片&#xff0c;也可以按 ctrl 选择你想要的…

物理机安装ESXI6.7提示No Network Adapters的解决方案

下载好ESXI6.7.iso镜像&#xff0c;写入U盘后&#xff0c;提示No Network Adapters&#xff0c;找不到网卡驱动。 解决办法&#xff1a;需要重新封装ESXI&#xff0c;将对应的网卡驱动嵌入进来。 1、先下载VMware-PowerCLI-6.5.0和ESXi-Customizer-PS&#xff1a; http://down.…

mysqlslap详解--MySQL自带的性能压力测试工具(转)

本文的参考博客地址为&#xff1a;https://blog.csdn.net/fuzhongfaya/article/details/80943991 和 https://www.cnblogs.com/davygeek/p/5253830.html 本文的目的一方面是自己整理&#xff0c;防止后续忘记&#xff0c;一方面是对参考博客的进行验证. 首先在这里介绍一下常用…

Android Gallery控件使用方法详解

我们今天给大家讲的就是Gallery控件&#xff0c;这个控件在android当中是非常重要的&#xff0c;我们今天就给大家介绍一下3D的Gallery控件是怎么样来实现的。下面我们就来直接看看代码吧。 1.扩展Gallery&#xff1a; public class GalleryFlow extends Gallery { private Cam…

javax.servlet.jsp.JspTagException:

2019独角兽企业重金招聘Python工程师标准>>> Illegal use of <when>-style tag without <choose> as its direct parent 这个错误一般是在jsp页面中非法使用<when>标签 该标签必须是<choose>标签的直接子标签 不能单独是<when>标签 …

c++远征之继承篇——继承的概念、继承时构造函数/析构函数的先后顺序

1、继承的概念 2、继承中&#xff0c;构造函数和析构函数的先后顺序

结对开发:电梯调度(2)

组员&#xff1a;赵天 李金吉 分工&#xff1a;赵天&#xff1a;概要设计与编码。 李金吉&#xff1a;详细设计与调试。 界面&#xff1a; 详细代码&#xff1a; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using Sys…

c++远征之继承篇——继承方式

以下内容源于慕课网&#xff0c;系学习整理而成&#xff0c;如有侵权&#xff0c;请告知删除。 1、公有继承 2、保护继承 3、私有继承

VMware vCenter Server6.5安装及群集配置介绍

借助 VMware vCenterServer&#xff0c;可从单个控制台统一管理数据中心的所有主机和虚拟机&#xff0c;该控制台聚合了集群、主机和虚拟机的性能监控功能。 VMware vCenterServer 使管理员能够从一个位置深入了解虚拟基础架构的集群、主机、虚拟机、存储、客户操作系统和其他关…

[JS性能优化专篇]

为什么80%的码农都做不了架构师&#xff1f;>>> 参考文章&#xff1a;了解 JavaScript 应用程序中的内存泄漏 旧版本的IE和Firefox都存在内存泄漏的问题&#xff0c;而且会一直持续到浏览器关闭。现在可以使用 Google Chrome 中的 Heap Profiler 来诊断内存问题。 …

Simulated Annealing(模拟退火算法)

/* Simulated Annealing(模拟退火算法) 求解旅行商问题(TSP) 网上给的数据是31个省会的坐标&#xff0c;蚁群算法得到的结果是&#xff1a;15378 我算的结果中&#xff0c;最好的一次是&#xff1a;15495 */ #include<iostream> #include<cstdio> #include<cstd…

c++远征之继承篇——隐藏,isa,虚析构函数

一、隐藏 父子关系。成员&#xff08;数据成员或者成员函数&#xff09;同名&#xff1b;此时子类中会隐藏父类中的同名成员。无法函数重载&#xff0c;只会隐藏&#xff01;如果想访问父类中的同名成员&#xff0c;需要 :: 操作。 访问父类同名函数的方法 二、is-a &#xff…

表单元素对齐问题解决方案

之前一直困扰自己的一个问题就是表单内radio、select等的对齐问题&#xff0c;一直以来&#xff0c;都是给提示添加label&#xff0c;然后跟radio等一起浮动&#xff0c;然后再设置margin解决的&#xff0c;但是这样又得另外解决IE6下的双边距问题&#xff0c;搞得自己相当恼。…

(转)动态Entity Framework查询:Dynamic Query 介绍

原文地址&#xff1a;http://www.cnblogs.com/yinzixin/archive/2012/11/30/entity-framework-dynamic-query.html Dynamic Query是一个支持动态Entity Framework查询的库。它的设计初衷是为了减少在管理系统中大量出现的对一个数据集进行查找、排序、分页的这类场景的开发工作…

c++远征之继承篇——多重继承,多继承,虚继承,多继承时的重复定义解决方法

以下内容源于慕课网的学习整理&#xff0c;如有侵权&#xff0c;请告知删除。 1、多重继承 &#xff08;1&#xff09;概念理解 2、多继承 &#xff08;1&#xff09;概念理解 3、虚继承 &#xff08;1&#xff09;问题的引出&#xff1a;多重继承和多继承的结合&#xff0c…

从Pycharm说起

说实话.作为一个Coder.每天在各种IDE中切换编写Code.如果一个IDE Look and Feel总是无形中影响你每天Code Farm的心情.那该是多么不爽的事情.特别是针对本人对IDE总是有一种天生“洁癖感”.每当一们语言或技术在无意中吸引我.或是已经在粗糙的本文编辑器初体验.都会在两到三天体…

JAVA开发工具下载

一、eclipse下载 下载地址&#xff1a;http://www.eclipse.org/downloads/packages/ 点击下载 弹出下载框 压缩包解压后就可以使用 转载于:https://www.cnblogs.com/djlsunshine/p/11373287.html

c++远征之多态篇——虚函数及其实现原理

以下内容源于慕课网的学习整理&#xff0c;如有侵权&#xff0c;请告知删除。 1、多态的定义 简单理解&#xff0c;就是对于同一条命令&#xff0c;不同对象会做出不同的操作。相同对象收到不同消息&#xff0c;或者不同对象收到相同消息时&#xff0c;产生不同的动作。 2、多态…

c++远征之多态篇——纯虚函数和抽象类、接口类

以下内容源于慕课网的学习整理&#xff0c;如有侵权&#xff0c;请告知删除。 1、纯虚函数 没有函数体&#xff1b;0&#xff1b;即只有函数声明&#xff0c;而没有函数定义的虚函数&#xff0c;是纯虚函数。 2、抽象类 概念&#xff1a;含有纯虚函数的类&#xff0c;叫抽象类…

W3 Total Cache+Hacklog Remote Attachment Upyun

2019独角兽企业重金招聘Python工程师标准>>> Hacklog Remote Attachment Upyun 是「荒野无灯」开发的WP插件&#xff0c;可以很方便的配合又拍云使用。通过这个插件&#xff0c;可以在添加媒体的时候上传至又拍云&#xff0c;对速度有极大的提升。 另外&#xff0c;…