是由“编译器驱动”(compiler driver)完成的:

unix> gcc -o hello hello.c

在这里,gcc的编译器驱动程序读取源文件hello.c,

  1. #include <stdio.h>
  2. int main()
  3. {
  4. printf("hello, world/n");
  5. return 0;
  6. }

并把它翻译成一个可执行目标文件hello,这个过程是分为四个阶段完成的。如下图所示,执行这四个阶段的程序(预处理器、编译器、汇编器和链接器)一起构成了编译系统。

预处理阶段:预处理器(cpp)根据以字符#开头的命令(directives),修改原始的C程序。如hello.c中第一行的#include <stdio.h>指令,它告诉预处理器读取系统头文件stdio.h的内容,并把它直接插入到程序文本中去。结果就得到另一个c程序,通常是以.i作为文件扩展名的。

编译阶段:编译器(ccl)将文本文件hello.i翻译成文本文件hello.s,它包括一个汇编语言程序。汇编语言程序中的每一条语句都一种标准的文本格式,确切地描述了一条低级机器语言指令。汇编语言为不同的高级语言的不同编译器提供了通用的输出语言。

汇编阶段:汇编器(as)将hello.s翻译成机器语言指令,再将这些指令打包成一种叫“可重定位”(relocatable)目标程序的格式,并将结果保存在目标文件hello.o中。hello.o文件是一个二进制文件,它的字节编码是机器语言指令而不是字符。如果用文本编辑器打开,看到的将是一群乱码。

链接阶段:hello程序调用了printf函数(标准C库中的一个函数,每个C编译器都提供),printf函数存在于一个名为printf.o的单独的预编译目标文件中,而这个文件必须以某种方式并入到hello.o程序中。链接器(ld) 就负责处理这种并入,结果得到一个可执行目标文件/hello文件(或称为可执行文件)。可执行文件加载到存储器后,由系统负责执行。

原文地址:http://blog.csdn.net/lychee007/article/details/4123130

———————————————————————————————————————————————————————————————————————————————

gcc编译过程

现代编译器常见的编译过程: 
源文件-->预处理-->编译/优化-->汇编-->链接-->可执行文件

对于gcc而言:

第一步 预处理
       命令: gcc -o test.i -E test.c
             或者 cpp -o test.i test.c (这里cpp不是值c plus plus,而是the C Preprocessor)
       结果:  生成预处理后的文件test.i(可以打开后与预处理前进行比对,当然长度会吓你一跳)     
       作用:  读取c源程序,对伪指令和特殊符号进行处理。包括宏,条件编译,包含的头文件,以及一些特殊符号。基本上是一个replace的过程。

第二步 编译及优化
        命令:  gcc -o test.s -S test.i
             或者 /路径/cc1 -o test.s test.i
        结果: 生成汇编文件test.s(可打开后查看源文件生成的汇编码)
        作用: 通过词法和语法分析,确认所有指令符合语法规则(否则报编译错),之后翻译成对应的中间码,在linux中被称为RTL(Register Transfer Language),通常是平台无关的,这个过程也被称为编译前端。编译后端对RTL树进行裁减,优化,得到在目标机上可执行的汇编代码。gcc采用as作为其汇编器,所以汇编码是AT&T格式的,而不是Intel格式,所以在用gcc编译嵌入式汇编时,也要采用AT&T格式。
        
第三步 汇编
        命令: gcc -o test.o -c test.s
               或者 as -o test.o test.s
        结果:   生成目标机器指令文件test.o(可用objdump查看)
        作用:  把汇编语言代码翻译成目标机器指令, 用file test.o 可以看到test.o是一个relocatable的ELF文件,通常包含.text .rodata代码段和数据段。可用readelf -r test.o查看需要relocation的部分。
        
第四步 链接
        命令: gcc -o test test.o
               或者 ld -o test test.o
        结果:   生成可执行文件test (可用objdump查看) 
        作用:  将在一个文件中引用的符号同在另外一个文件中该符号的定义链接起来,使得所有的这些目标文件链接成为一个能被操作系统加载到内存的执行体。(如果有不到的符号定义,或者重复定义等,会报链接错)。用file test 可以看到test是一个executable的ELF文件。
        
        当然链接的时候还会用到静态链接库,和动态连接库。静态库和动态库都是.o目标文件的集合。
        静态库:
        命令:ar -v -q test.a test.o
        结果: 生成静态链接库test.a
        作用: 静态库是在链接过程中将相关代码提取出来加入可执行文件的库(即在链接的时候将函数的代码将从其所在地静态链接库中被拷贝到最终的可执行程序中),ar只是将一些别的文件集合到一个文件中。可以打包,当然也可以解包。
        
        动态库:  
        命令:  gcc -shared test.so test.o 
             或者/PATH/collect2 -shared test.so test.o (省略若干参数)
        结果:  生成动态连接库test.so
        作用: 动态库在链接时只创建一些符号表,而在运行的时候才将有关库的代码装入内存,映射到运行时相应进程的虚地址空间。如果出错,如找不到对应的.so文件,会在执行的时候报动态连接错(可用LD_LIBRARY_PATH指定路径)。用file test.so可以看到test.so是shared object的ELF文件。
        
当然以上各步可以一步或若干步一起完成,如gcc -o test test.c直接得到可执行文件。

附:
    ELF文件格式
    ELF文件格式是ABI(Application Binary Interface)的一部分,被Tool Interface Standards committee作为在32位Intel架构下可移植的目标文件格式。其格式比较复杂,这里就不细讲了,只说说其类型。
    在specification 1.1中定义了的类型。表示在ELF header中的e_type
    Name        Value  Meaning
    ====        =====  =======
    ET_NONE         0  No file type
    ET_REL          1  Relocatable file
    ET_EXEC         2  Executable file
    ET_DYN          3  Shared object file
    ET_CORE         4  Core file
    ET_LOPROC  0xff00  Processor-specific
    ET_HIPROC  0xffff  Processor-specific
    
    主要的有4种
    1. Relocatable file 保留了代码和数据,被用来和其他的object file一起创建可执行的文件或者是shared object file. (也就是我们常见的.o文件)
    2. Executable file 保留了用来执行的程序,该文件可以被系统exec()加载用以创建程序进程。(也就是我们常说的可执行文件) 
    3. Shared object file 保留了代码和数据,以在两种情况下被连接,一是link editor如ld,可以用它与其他的Relocateble或者Shared的object file一起创建另一个object file. 二是与Executable file或者其他的Shared object file动态链接成为一个进程映像。(也就是我们常说的动态链接库,或者.so文件)    
    4. Core file 的内容在规范中没有指明,目前多用来记录core dump信息。

原文地址:http://blog.csdn.net/lychee007/article/details/4123018

在Unix系统上,从源文件、目标文件、可执行文件的编译过程的更多相关文章

  1. 使用apache daemon让java程序在unix系统上以服务方式运行

    通过使用apache_commons_daemon,可以让Java程序在unix系统上以服务器的方式运行. 当然,通过wrapper也是可以达到这样的目的,wrapper还可以指定java应用中用到的 ...

  2. linux下的 sudo ln -s 源文件 目标文件

    这是linux中一个非常重要命令,请大家一定要熟悉.它的功能是为某一个文件或目录在另外一个位置建立一个同步的链接,类似Windows下的超级链接. 这个命令最常用的参数是-s,具体用法是:sudo l ...

  3. 在Windows系统上一批可以下载但是需要经过编译再安装的第三方的直接编译后的版本(UCI页面)

    在Windows系统上一批可以下载但是需要经过编译再安装的第三方的直接编译后的版本(UCI页面) (https://www.lfd.uci.edu/~gohlke/pythonlibs/) win10 ...

  4. UNIX系统上的抓包工具tcpdump常用命令说明

    tcpdump 介绍 tcpdump采用命令行方式对接口的数据包进行筛选抓取,其丰富特性表现在灵活的表达式上. 不带任何选项的tcpdump,默认会抓取第一个网络接口,且只有将tcpdump进程终止才 ...

  5. UNIX 系统上的文本操作简介

    http://www.oschina.net/question/129540_53561 UNIX 的基本哲学之一就是创建只做一件事并将这一件事做好的程序(或进程).这一哲学要求认真考虑接口以及结合这 ...

  6. Unix系统编程()复制文件描述符

    Bourne shell的IO重定向语法2>&1,意在通知shell把标准错误(文件描述符2)重定向到标准输出(文件描述符1).因此下列命令将把标准输出和标准错误写入result.log ...

  7. Linux和类Unix系统上5个最佳开源备份工具

    一个好的备份最基本的目的就是为了能够从一些错误中恢复: 人为的失误 磁盘阵列或是硬盘故障 文件系统崩溃 数据中心被破坏等等. 所以,我为大家罗列了一些开源的软件备份工具. 当为一个企业选择备份工具的时 ...

  8. Linux 和类 Unix 系统上5个最佳开源备份工具

    转载:http://linux.cn/article-4623-weixin.html#rd?sukey=cbbc36a2500a2e6cb7678c4d38b691a9fa7403b259f898e ...

  9. Unix系统编程()在文件特定偏移量处的IO:pread和pwrite

    首先我想问的是这两个p代表的是什么? 系统调用pread和pwrite完成与read和write相类似的工作,只是前两者会在offset参数所指定的位置进行文件IO操作,而非始于文件的当前偏移量处,并 ...

随机推荐

  1. 使用CRA开发的基于React的UI组件发布到内网NPM上去

    前言:构建的ES组件使用CNPM发布内网上过程 1. 使用Create-React-APP开的组件 如果直接上传到NPM,你引用的时候会报: You may need an appropriate l ...

  2. Java基础:(五)Object通用方法

    一.Object对象的九个方法 getClass():hashCode():equals():clone():toString():notify():notifyAll():wait():finali ...

  3. 【转】说说Runnable与Callable

    说说Runnable与Callable   Callable接口:   Runnable接口: 相同点: 两者都是接口:(废话) 两者都可用来编写多线程程序: 两者都需要调用Thread.start( ...

  4. DHTMLX 使用汇总

    1.dhtmlxGrid  底部总出现滚动条 ------------------------------------------ 发现使用DHTMLXGRID时 GRID 底边总有   滚动条 测试 ...

  5. html5 03

    HTML03 一. 表单标签 <form></form> 常用属性 Action 跳转到什么页面 Method  以什么模式提交 Get Url有长度限制 IE6.0 url ...

  6. iOS 应用架构 (一)

    摘要:iOS 客户端应用架构看似简单,但实际上要考虑的事情不少.本文作者将以系列文章的形式来回答 iOS 应用架构中的种种问题,本文是其中的第一篇,主要讲架构设计的通识和方法论等,同时还讨论了大家关心 ...

  7. C# 报表和打印等

    说到报表打印.那就不得不说需要查数据库了,然后填写报表信息.设计报表用的 grid++. 查数据库时候,我也是醉了,直接一个表自身与自身级联了4次...一共取了7个表的信息数据. 关于级联--(表字段 ...

  8. python 之正则表达式

    一.正则表达式 首先,我们需要感性的了解下什么是正则表达式,简单的是说“正则表达式”就是一个“表达式”,更准确定义是:“用一个简洁的方法来实现对“一组字符串”的表达式. 最终目的就是实现“一行胜千言” ...

  9. CF 55D Beautiful numbers (数位DP)

    题意: 如果一个正整数能被其所有位上的数字整除,则称其为Beautiful number,问区间[L,R]共有多少个Beautiful number?(1<=L<=R<=9*1018 ...

  10. HTML之元素分类

    一.元素展示类型 在HTML本身定义了很多元素,这些元素在网页上展示的时候都会有自己的默认状态,例如有些元素在默认状态下对高宽的属性设置不起作用,有些元素都默认情况下都独立一行显示,这种现象我们称之为 ...