gcc 编译流程

来源:互联网 发布:软件测试教程学习 编辑:程序博客网 时间:2024/06/05 20:07

gcc编译流程分为四个步骤:

      1:预编译处理 :主要是进行宏替换和拷贝包含的头文件到本文件

      2:编译: 检查代码的规范性,是否有语法错误等,没错的话将代码编译成汇编语言

       3:汇编:将汇编文件转换成二进制目标文件

      4:链接:链接库函数生成可执行文件


详解如下:

  一:用C语言编写一个简单的程序,文件名为main.c,内容如下

#include<stdio.h>

#define MAX(x,y) (x) > (y) ? (x) : (y)
#define MIX(x,y) (x) < (y) ? (x) : (y)
#define MAXIMUM

int main()
{
    int a = 0;
    int x = 3;
    int y = 5;

    #ifdef MAXIMUM
        a = MAX(x,y);
    #else
        a = MIN(x,y);
    #endif
        printf("a = %d\n", a);
    return 0;
}



二:执行 gcc -E main.c -o main.i(预处理)


打开main.i 可以看到头文件stdio.h被加载进来了,同时main函数里面的宏定义被替换了



三:编译:在这个阶段中,GCC首先要检查代码的规范性,是否有语法错误等,以确定代码实际要做的工作,检查无误后,GCC将代码翻译成汇编语言,命令如下:gcc -S main.i -o main.s


main.s的内容是汇编语言,内容如下:

  1     .file   "main.c"
  2     .section    .rodata
  3 .LC0:
  4     .string "a = %d\n"
  5     .text
  6     .globl  main
  7     .type   main, @function
  8 main:
  9 .LFB0:
 10     .cfi_startproc
 11     pushq   %rbp
 12     .cfi_def_cfa_offset 16
 13     .cfi_offset 6, -16
 14     movq    %rsp, %rbp
 15     .cfi_def_cfa_register 6
 16     subq    $16, %rsp
 17     movl    $0, -12(%rbp)
 18     movl    $3, -8(%rbp)
 19     movl    $5, -4(%rbp)
 20     movl    -8(%rbp), %eax
 21     cmpl    %eax, -4(%rbp)
 22     cmovge  -4(%rbp), %eax
 23     movl    %eax, -12(%rbp)
 24     movl    -12(%rbp), %eax
 25     movl    %eax, %esi
 26     movl    $.LC0, %edi
 27     movl    $0, %eax
 28     call    printf
 29     movl    $0, %eax
 30     leave
 31     .cfi_def_cfa 7, 8
 32     ret
 33     .cfi_endproc
 34 .LFE0:
 35     .size   main, .-main
 36     .ident  "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"
 37     .section    .note.GNU-stack,"",@progbits


四:汇编.汇编阶段就是把编译阶段生成的.s文件转换成目标文件,命令如下:gcc -c main.s -o main.o




五:链接:汇编阶段生成的二进制目标文件并不是可执行程序,例如,main函数里面用到的printf函数并没有实现,有人会问,#include<stdio.h>不是已经实现了吗,不是的,在预处理阶段,包含的stdio.h只有该函数的声明,并没有定义printf函数的实现,其实系统会把stdio.h的函数实现都加在libc.so.6的库文件中,在没有特别的指定时,GCC会到系统默认的搜索路径/usr/lib下进行查找,也就是链接到libc.so.6库函数中,这样就可以实现函数printf了,这也就是链接的作用.

命令:gcc main.o -o  main



静态库和动态库

       库函数一般分为静态库和动态库两种.静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了.其后缀名一般为.a.动态库与静态库相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由链接文件加载库,这样可以节省系统的存储空间,避免重复装载相同的库到内存.动态库一般后缀名为.so ,如前面所述的libc.so.6就是动态库.


ps:以上内容参考教科书<ARM嵌入式Linux应用开发入门>------汪明虎 欧文盛编著,如有侵权,请联系我删除,谢谢!!!