zoukankan      html  css  js  c++  java
  • gcc 编译流程分析

    //test.c
    #include<stdio.h>
    int main()
    {
      int x=3,y=4;
      printf("x=%d y=%d
    ",x,y);
      return 0;
     }
    
    1:预处理阶段,对包含的头文件(#include)和宏定义(#define,#ifdef等)进行处理。在上述的代码处理过程中,编译器将包含的头文件stdio.h编译进来,并且让用户使用选项”-E“
    进行查看,该选项的作用是让gcc在预处理结束后停止编译过程。”.i“文件为已经过预处理的c程序。一下列出部分test.i文件的内容:
    # 1 "test.c"
    # 1 "<built-in>"
    # 1 "<command-line>"
    # 1 "test.c"
    # 1 "/usr/include/stdio.h" 1 3 4
    # 28 "/usr/include/stdio.h" 3 4
    # 1 "/usr/include/features.h" 1 3 4
    # 361 "/usr/include/features.h" 3 4
    # 1 "/usr/include/sys/cdefs.h" 1 3 4
    # 365 "/usr/include/sys/cdefs.h" 3 4
    # 1 "/usr/include/bits/wordsize.h" 1 3 4
    # 366 "/usr/include/sys/cdefs.h" 2 3 4
    # 362 "/usr/include/features.h" 2 3 4
    # 385 "/usr/include/features.h" 3 4
    # 1 "/usr/include/gnu/stubs.h" 1 3 4
    ..................................................
    extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__)) ;
    
    
    extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__));
    # 938 "/usr/include/stdio.h" 3 4
    
    # 2 "test.c" 2
    int main()
    {
      int x=3,y=4;
      printf("x=%d y=%d
    ",x,y);
      return 0;
     }

    2:编译阶段
    接下来进行编译阶段,在这个阶段中,gcc首先要检查代码的规范性,是否有语法错误等,以确定代码实际要做的工作,在检查无误后,gcc把代码翻译成汇编语言。用户可以使用
    “-S”选项来进行查看,该选项只进行编译而不进行汇编,结果生成汇编代码。
    下面列出汇编代码test.s
        .file    "test.c"
        .section    .rodata
    .LC0:
        .string    "x=%d y=%d
    "
        .text
    .globl main
        .type    main, @function
    main:
        pushl    %ebp
        movl    %esp, %ebp
        andl    $-16, %esp
        subl    $32, %esp
        movl    $3, 24(%esp)
        movl    $4, 28(%esp)
        movl    $.LC0, %eax
        movl    28(%esp), %edx
        movl    %edx, 8(%esp)
        movl    24(%esp), %edx
        movl    %edx, 4(%esp)
        movl    %eax, (%esp)
        call    printf
        movl    $0, %eax
        leave
        ret
        .size    main, .-main
        .ident    "GCC: (GNU) 4.4.6 20120305 (Red Hat 4.4.6-4)"
        .section    .note.GNU-stack,"",@progbits
    3:汇编阶段
    汇编阶段把编译生成的.s文件转换成目标文件,读者在此使用选项“-c"就可以看到汇编代码已经转换成”.o“的二进制目标代码了!

    4:连接阶段
    在成功编译后,之后进入连接阶段。这里涉及到一个重要的概念:函数库。
    读者可以查看这个程序,在这个程序中并没有定义”printf"的函数实现,且在预编译中包含进来的“stdio"中也只有该函数的声明,而没有函数的实现,那么是在哪里实现了
    “printf”函数呢?最后的答案是系统把这些函数的实现都放在名为lib.so.6的库文件中去了,在没有特别指定时,gcc会到系统默认的搜索路径”/usr/bin"下进行查找,也就是链接到libc.so.6函数库中去,这样就能调用函数“printf"了,而这正是动态链接的作用。
    函数库有静态库和动态库两种。静态库是指编译链接时,将库文件的代码全部加入可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名通常为”.a“。动态库与之相反,在编译链接时并没有将库文件的代码加入到可执行文件中,而是在程序执行时加载库,这样可以节省系统的开销。一般动态库的后缀名为”.so“,如前面所述的lib.so.6就是动态库。gcc在编译时默认使用动态库。
    完了链接之后,gcc 就可以生成可执行文件。
    ”-I dir"选项可以在头文件的搜索路径列表中添加dir目录。由于linux中头文件都默认放到了“usr/include/"目录下,因此,当用户希望添加放置在其他位置的头文件时,就可以通过”-I dir"选项来指定,这样,gcc就会到相应的位置查找对应的目录。
    在include语句中,<>表示在标准路径中搜索头文件,“ ”表示在本目录中搜索。故在上例中,可把test.c中的#include<my.h>改为#include"my.h",就不需要加上“-I”选项了!!!!!!
    下面链接的时候出现错误的!!!!
  • 相关阅读:
    正经学C#_循环[do while,while,for]:[c#入门经典]
    Vs 控件错位 右侧资源管理器文件夹点击也不管用,显示异常
    asp.net core 获取当前请求的url
    在实体对象中访问导航属性里的属性值出现异常“There is already an open DataReader associated with this Command which must be
    用orchard core和asp.net core 3.0 快速搭建博客,解决iis 部署https无法登录后台问题
    System.Data.Entity.Core.EntityCommandExecution The data reader is incompatible with the specified
    初探Java设计模式3:行为型模式(策略,观察者等)
    MySQL教程77-CROSS JOIN 交叉连接
    MySQL教程76-HAVING 过滤分组
    MySQL教程75-使用GROUP BY分组查询
  • 原文地址:https://www.cnblogs.com/leijiangtao/p/4390896.html
Copyright © 2011-2022 走看看