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 gcc编译过程的更多相关文章

  1. Linux学习---GCC编译过程

    (一)GCC编译过程 预处理 cpp -o a.i a.c     //生成预处理文件 等同于[gcc -E] //预处理为将宏定义(#define)等进行替换. 编译 /user/lib/gcc/i ...

  2. GCC编译过程与动态链接库和静态链接库

    1. 库的介绍 库是写好的现有的,成熟的,可以复用的代码.现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常. 本质上来说库是一种可执行代码的二进制形式,可 ...

  3. 1.GCC编译过程

    一. GCC编译过程 gcc -E hello.c -o hello.i // 预处理.将代码中包含的头文件和宏进行替换 gcc -S hello.i -o hello.s // 汇编.将当前文本转换 ...

  4. gcc 编译过程

    gcc 编译过程从 hello.c 到 hello(或 a.out)文件, 必须历经 hello.i. hello.s. hello.o,最后才得到 hello(或a.out)文件,分别对应着预处理. ...

  5. system 系统调用、gcc编译过程

    system 库函数的功能是执行操作系统的命令或者运行指定的程序 #include <stdio.h> #include <stdlib.h>//引入库 int main() ...

  6. GCC编译过程

    以下是C程序一般的编译过程: gcc的编译流程分为四个步骤,分别为:· 预处理(Pre-Processing) 对C语言进行预处理,生成*.i文件.· 编译(Compiling) 将上一步生成的*.i ...

  7. Linux系统GCC常用命令和GCC编译过程描述

    前言: GCC 原名为 GNU C 语言编译器(GNU C Compiler),因为它原本只能处理 C语言.GCC 很快地扩展,变得可处理 C++.后来又 扩展能够支持更多编程语言,如Fortran. ...

  8. gcc编译过程简述

    在linux系统上,从源文件到目标文件的转化是由编译器完成的.以hello.c程序的编译为例,如下: dfcao@linux: gcc -o hello hello.c 在这里,gcc编译器读取源文件 ...

  9. 和菜鸟一起学c之gcc编译过程及其常用编译选项【转】

    转自:http://blog.csdn.net/eastmoon502136/article/details/8162626 版权声明:本文为博主东月之神原创文章,未经博主允许不得转载. 上篇文章,知 ...

随机推荐

  1. easyUI 鼠标悬停某行提示

      最近参与公司的电子档案系统的开发,需求是需要用户鼠标悬停某一行时,需要根据后台业务数据进行提示. 档案系统开发采用的框架是struts2+mybatis+spring+easyUI开发,而前端的e ...

  2. 字符串实现Base64加密/解密

    有时候需要对字符串进行加密,不以明文显示,可以使用此方法,比如对URL的参数加密 using System; using System.Collections.Generic; using Syste ...

  3. 关于Arduino项目的构建思想-转自openbook开源杂志

  4. JSP中,EL表达式向session中取出一个attribute和JSP脚本访问session取出一个attribute,写法有何不同?(转自百度知道)

    EL表达式使用起来会更简洁,假如session中有一个属性A(attrA),那么EL和jsp脚本取值的方式如下: EL表达式:${ sessionScope.attrA } JSP脚本:<%=s ...

  5. 三、css 和 js 的装载与执行

    一个网站在浏览器端是如何渲染的? 一.html 页面加载渲染的过程. 请求回来最先应该是HTML,从一个字节流转换成字符流,浏览器拿到字符流,然后浏览器端进行相应的词法分析成相应的token,然后不断 ...

  6. leetcode 355 Design Twitte

    题目连接 https://leetcode.com/problems/design-twitter Design Twitte Description Design a simplified vers ...

  7. linux 命令——55 traceroute(转)

    通过traceroute我们可以知道信息从你的计算机到互联网另一端的主机是走的什么路径.当然每次数据包由某一同样的出发点(source)到达某一同样的目的地(destination)走的路径可能会不一 ...

  8. linux 命令——33 df(转)

    linux中df命令的功能是用来检查linux服务器的文件系统的磁盘空间占用情况.可以利用该命令来获取硬盘被占用了多少空间,目前还剩下多少空间等信息. 1.命令格式: df [选项] [文件] 2.命 ...

  9. vue中使用setTimeout

    在vue的函数中使用setTimeout self.distroyTimeout = setTimeout(()=>{ self.initData() },1000) 这时清除setTimeou ...

  10. PHP:is_string()字符串函数

    is_string() is_string() - 检测变量是否是字符串. 描述:bool is_string( mixed $var ) 如果var是sring则返回TRUE,否则返回FALSE.m ...