• gcc编译过程


    一个编译过程包括下面4个阶段

    1. 预处理,预处理器CPP主要进行3个方面:文件包含、宏定义、条件编译;
    2. 编译,gcc将c文件编译成汇编文件;
    3. 汇编,as将汇编文件编译成机器码;
    4. 链接,ld将目标文件和外部符号进行链接,得到一个可执行二进制文件。

     下面以一个简单的test.c来探讨这个过程

    #define NUMBER (1+2)
    
    int main(void)
    {
        int num = NUMBER;
        
        return 0;
    }

    1、预处理

    预处理主要做下列的处理

    1. 将所有的#define删除,并且展开所有的宏定义 
    2. 处理所有的条件预编译指令,比如#if #ifdef #elif #else #endif等 
    3. 处理#include 预编译指令,将被包含的文件插入到该预编译指令的位置。 
    4. 删除所有注释 “//”和”/* */”. 
    5. 添加行号和文件标识,以便编译时产生调试用的行号及编译错误警告行号。 
    6. 保留所有的#pragma编译器指令,因为编译器需要使用它们 
    [root@localhost test]# gcc -E test.c > test.i    //等价于 cpp test.c >test.i 
    [root@localhost test]# cat test.i
    # 1 "test.c"
    # 1 "<built-in>"
    # 1 "<command-line>"
    # 1 "test.c"                           //使用gcc -E -P test.c > test.i 就不会显示上面4行#号开头的内容
    
    
    int main(void)
    {
     int num = (1+2);                      //这里进行了行宏替换
    
     return 0;
    }

    2、编译

    预处理后的代码生成汇编代码.

    编译过程可分为6步:扫描(词法分析)、语法分析、语义分析、源代码优化、代码生成、目标代码优化。 

    1. 词法分析:扫描器(Scanner)将源代码的字符序列分割成一系列的记号(Token)。lex工具可实现词法扫描。 
    2. 语法分析:语法分析器将记号(Token)产生语法树(Syntax Tree)。yacc工具可实现语法分析。
    3. 语义分析:静态语义(在编译器可以确定的语义)、动态语义(只能在运行期才能确定的语义)。 
    4. 源代码优化:源代码优化器(Source Code Optimizer),将整个语法书转化为中间代码(Intermediate Code)(中间代码是与目标机器和运行环境无关的)。中间代码使得编译器被分为前端和后端。编译器前端负责产生机器无关的中间代码;编译器后端将中间代码转化为目标机器代码。 
    5. 目标代码生成:代码生成器(Code Generator). 
    6. 目标代码优化:目标代码优化器(Target Code Optimizer)。
    [root@localhost test]# gcc -S test.i > test.s
    [root@localhost test]# cat test.s
        .file    "test.c"
        .text
    .globl main
        .type    main, @function
    main:
        pushl    %ebp
        movl    %esp, %ebp
        subl    $16, %esp
        movl    $3, -4(%ebp)
        movl    $0, %eax
        leave
        ret
        .size    main, .-main
        .ident    "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-4)"
        .section    .note.GNU-stack,"",@progbits

    3、汇编

    将汇编文件编译成机器码。

    [root@localhost test]# gcc -c test.s -o test.o      //等价于 as test.s -o test.o

    4、链接

    通过调用链接器来链接程序运行需要的一大堆目标文件,以及所依赖的其它库文件,最后生成可执行文件。 

    链接的主要内容是把各个模块之间相互引用的部分处理好,使得各个模块之间能够正确地衔接。 

    链接的主要过程包括:地址和空间分配(Address and Storage Allocation),符号决议(Symbol Resolution),重定位(Relocation)  等。 


    链接分为静态链接和动态链接。 
    静态链接是指在编译阶段直接把静态库加入到可执行文件中去,这样可执行文件会比较大。 
    而动态链接则是指链接阶段仅仅只加入一些描述信息,而程序执行时再从系统中把相应动态库加载到内存中去。

    [root@localhost test]# gcc test.o -o test

    GCC编译的详细过程

    [root@localhost swap]# gcc -v test.c
    Using built-in specs.
    Target: i686-redhat-linux
    Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch=i686 --build=i686-redhat-linux
    Thread model: posix
    gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC) 
    COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=i686'
     /usr/libexec/gcc/i686-redhat-linux/4.4.7/cc1 -quiet -v test.c -quiet -dumpbase test.c -mtune=generic -march=i686 -auxbase test -version -o /tmp/ccafFwbO.s
    ignoring nonexistent directory "/usr/lib/gcc/i686-redhat-linux/4.4.7/include-fixed"
    ignoring nonexistent directory "/usr/lib/gcc/i686-redhat-linux/4.4.7/../../../../i686-redhat-linux/include"
    #include "..." search starts here:
    #include <...> search starts here:
     /usr/local/include
     /usr/lib/gcc/i686-redhat-linux/4.4.7/include
     /usr/include
    End of search list.
    GNU C (GCC) version 4.4.7 20120313 (Red Hat 4.4.7-4) (i686-redhat-linux)
        compiled by GNU C version 4.4.7 20120313 (Red Hat 4.4.7-4), GMP version 4.3.1, MPFR version 2.4.1.
    GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
    Compiler executable checksum: 5f02f32570d532de29ae0b402446343a
    COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=i686'
     as -V -Qy -o /tmp/ccvfdR55.o /tmp/ccafFwbO.s
    GNU assembler version 2.20.51.0.2 (i686-redhat-linux) using BFD version version 2.20.51.0.2-5.34.el6 20100205
    COMPILER_PATH=/usr/libexec/gcc/i686-redhat-linux/4.4.7/:/usr/libexec/gcc/i686-redhat-linux/4.4.7/:/usr/libexec/gcc/i686-redhat-linux/:/usr/lib/gcc/i686-redhat-linux/4.4.7/:/usr/lib/gcc/i686-redhat-linux/:/usr/libexec/gcc/i686-redhat-linux/4.4.7/:/usr/libexec/gcc/i686-redhat-linux/:/usr/lib/gcc/i686-redhat-linux/4.4.7/:/usr/lib/gcc/i686-redhat-linux/
    LIBRARY_PATH=/usr/lib/gcc/i686-redhat-linux/4.4.7/:/usr/lib/gcc/i686-redhat-linux/4.4.7/:/usr/lib/gcc/i686-redhat-linux/4.4.7/../../../:/lib/:/usr/lib/
    COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=i686'
     /usr/libexec/gcc/i686-redhat-linux/4.4.7/collect2 --eh-frame-hdr --build-id -m elf_i386 --hash-style=gnu -dynamic-linker /lib/ld-linux.so.2 /usr/lib/gcc/i686-redhat-linux/4.4.7/../../../crt1.o /usr/lib/gcc/i686-redhat-linux/4.4.7/../../../crti.o /usr/lib/gcc/i686-redhat-linux/4.4.7/crtbegin.o -L/usr/lib/gcc/i686-redhat-linux/4.4.7 -L/usr/lib/gcc/i686-redhat-linux/4.4.7 -L/usr/lib/gcc/i686-redhat-linux/4.4.7/../../.. /tmp/ccvfdR55.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i686-redhat-linux/4.4.7/crtend.o /usr/lib/gcc/i686-redhat-linux/4.4.7/../../../crtn.o

    ---------------------------------------------------------------------------------------------------
    参考资料:

    http://blog.csdn.net/xdxiaofeng/article/details/2640013

    http://yinyuzw.blog.163.com/blog/static/20549019420123942248206/

    http://daimajishu.iteye.com/blog/1087393

  • 相关阅读:
    leetcode第四题
    解决Hystrix主线程结束,子线程拿不到request
    RabbitMQ如何保证消息的顺序性+解决消息积压+设计消息队列中间件
    RabbitMQ 如何保证消息不丢失?
    redis布隆过滤器的使用
    PageHelper自定义count
    mysqlbinlog 工具分析binlog日志
    linuxubuntu常用命令
    MySQL 常用命令
    Ubuntu 16.04 安装 Apache, MySQL, PHP7
  • 原文地址:https://www.cnblogs.com/LubinLew/p/gcc_process.html
Copyright © 2020-2023  润新知