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

以下内容源于朱有鹏《物联网大讲堂》课程的学习整理,以及网页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,一经查实,立即删除!

相关文章

最近在ST公司的STxp70的dsp平台上开发音频codec模块.

公司最近和ST公司有个DAB的项目, 需要将AACplus,BSAC,MPEG-lay2以及lay3的算法在该dsp平台上 进行优化.这个dsp平台比较的奇怪和TI的以及arm的core不太一样,它有一个基本core以及基本指令集,它的 扩展的一些数学指令集是通过增加一些extension库来实现的.不过优化后的效率还是比…

Eclipse中部分快捷键

这个链接文章介绍的比较全面&#xff1a;http://blog.csdn.net/hevicky/article/details/7239977 我把其中认为对自己有用的几个快捷键整理出来&#xff0c;以便熟悉、使用。 MyEclipse 快捷键1(CTRL) ------------------------------------- Ctrl1 快速修复&#xff08;例如导…

win设置壁纸

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

Makefile中三个自动变量:$^,$@,$<

以下内容源于网络资源的学习与整理&#xff0c;如有侵权请告知删除。 什么叫自动变量呢&#xff1f;就是这种变量会把模式中所定义的一系列的文件自动地挨个取出&#xff0c;直至所有的符合模式的文件都取完。这种自动化变量只应出现在规则的命令中。 以一个例子说明。 OBJS…

win8 软件字体乱码

安装了Win8企业评估版&#xff0c;安装一些软件中文字体显示出粗。进入控制面板&#xff0c;语言->单击左下角的位置链接->弹出的区域当前位置下拉框选择中文即可&#xff0c;最后重启即可。 winq -> search language setup->add language-> location (left bot…

物理机安装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.…

汇编程序、shell脚本与Makefile中的注释方法

一、汇编程序中的注释方法 &#xff08;1&#xff09;可以用或;&#xff08;这里的不是makefile中的静默执行之意&#xff0c;分号是英文状态的分号&#xff09;。 &#xff08;2&#xff09;可以用//或者/* */&#xff08;既然可以用/* */&#xff0c;汇编语言就不用关注单行…

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>标签 …

uboot将命令结构体单独存放在某个代码段的方法

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 1、uboot的链接脚本里有如下代码片段。 __u_boot_cmd_start .;.u_boot_cmd : { *(.u_boot_cmd) } __u_boot_cmd_end .; 2、uboot中将命令结构体单独存放在某个代码段&#xff0c;是通过以下两个宏…

Felix的Nodejs代码风格

Felix的Nodejs代码风格 原文地址&#xff1a;http://nodeguide.com/style.html 这是翻译的关于nodejs编码风格的一片文章&#xff0c;nodejs并没有官方统一的编码风格&#xff0c;但是好的编码风格可以提高代码可读性&#xff0c;既然有人总结了&#xff0c;就可以参照一下。没…

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

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

mysql操作常用技巧

删除一张表的数据&#xff0c;条件在另一张表 delete a from A a,B b where a.telb.tel and a.codeb.code and a.day201808;转载于:https://www.cnblogs.com/JAYIT/p/9720117.html

结对开发:电梯调度(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 来诊断内存问题。 …

jQuery --- grep

返回值:ArrayjQuery.grep(array, callback, [invert]) 概述 使用过滤函数过滤数组元素。 此函数至少传递两个参数&#xff1a;待过滤数组和过滤函数。过滤函数必须返回 true 以保留元素或 false 以删除元素。 参数 array,callback,[invert]Array,Function,BooleanV1.0 array:待…

Simulated Annealing(模拟退火算法)

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