//test.c
#include<stdio.h>
int main()
{
  int x=3,y=4;
  printf("x=%d y=%d\n",x,y);
  return 0;
 }
gcc 编译流程分析
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\n",x,y);
  return 0;
 }
gcc 编译流程分析
2:编译阶段
接下来进行编译阶段,在这个阶段中,gcc首先要检查代码的规范性,是否有语法错误等,以确定代码实际要做的工作,在检查无误后,gcc把代码翻译成汇编语言。用户可以使用
“-S”选项来进行查看,该选项只进行编译而不进行汇编,结果生成汇编代码。
下面列出汇编代码test.s
    .file    "test.c"
    .section    .rodata
.LC0:
    .string    "x=%d y=%d\n"
    .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“的二进制目标代码了!
gcc 编译流程分析
4:连接阶段
在成功编译后,之后进入连接阶段。这里涉及到一个重要的概念:函数库。
读者可以查看这个程序,在这个程序中并没有定义”printf"的函数实现,且在预编译中包含进来的“stdio"中也只有该函数的声明,而没有函数的实现,那么是在哪里实现了
“printf”函数呢?最后的答案是系统把这些函数的实现都放在名为lib.so.6的库文件中去了,在没有特别指定时,gcc会到系统默认的搜索路径”/usr/bin"下进行查找,也就是链接到libc.so.6函数库中去,这样就能调用函数“printf"了,而这正是动态链接的作用。
函数库有静态库和动态库两种。静态库是指编译链接时,将库文件的代码全部加入可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名通常为”.a“。动态库与之相反,在编译链接时并没有将库文件的代码加入到可执行文件中,而是在程序执行时加载库,这样可以节省系统的开销。一般动态库的后缀名为”.so“,如前面所述的lib.so.6就是动态库。gcc在编译时默认使用动态库。
完了链接之后,gcc 就可以生成可执行文件。
gcc 编译流程分析
”-I dir"选项可以在头文件的搜索路径列表中添加dir目录。由于linux中头文件都默认放到了“usr/include/"目录下,因此,当用户希望添加放置在其他位置的头文件时,就可以通过”-I dir"选项来指定,这样,gcc就会到相应的位置查找对应的目录。
在include语句中,<>表示在标准路径中搜索头文件,“ ”表示在本目录中搜索。故在上例中,可把test.c中的#include<my.h>改为#include"my.h",就不需要加上“-I”选项了!!!!!!
gcc 编译流程分析
gcc 编译流程分析
gcc 编译流程分析
gcc 编译流程分析
gcc 编译流程分析
下面链接的时候出现错误的!!!!
gcc 编译流程分析

 

相关文章:

  • 2021-09-10
  • 2021-12-13
  • 2021-12-15
  • 2022-03-01
  • 2022-02-07
猜你喜欢
  • 2022-02-07
  • 2022-02-07
  • 2022-02-07
  • 2021-04-07
  • 2021-08-31
  • 2021-12-15
  • 2021-08-09
相关资源
相似解决方案