Linux GCC编译C程序


一个c语言程序从源文件到生成可执行文件,编译器需要共经历4个步骤:

1) 预处理:把c文件中预处理命令扫描处理完毕,即对源代码文件中的文件包含(#include)、预编译语句(如宏定义#define等)进行分析,此时生成的文件仍然是可读的。
2) 编译:把预处理后的结果编译成汇编或者目标模块,即生成汇编语言文件,此时生成的文件仍然是可读的汇编文件。
3) 汇编:把编译出来的结果汇编成具体CPU上的目标代码模块,也即此时转换成具体的机器语言代码,此时生成的文件是不可读的非文本文件。
4) 连接:把多个目标代码模块连接生成一个大的目标模块,即将多个上面产生的机器代码文件(与其它的机器代码文件和库文件)汇集成一个可执行的二进制代码文件。

    gcc作为c语言在Linux下很著名的编译软件,分别有如下option来支持4个步骤:

名称   gcc选项    英文名称         gcc调用的程序 示例
预处理   -E       Pre-Processing   cpp            gcc -E test.c -o test.i
编译     -S       Compiling        ccl            gcc -S test.i -o test.s
汇编     -c        Assembling      as             gcc -c test.s -o test.o
连接     无        Linking         ld              gcc test.o -o test

说明:

    gcc在编译c语言文件时,首先调用cpp进行预处理,在预处理过程中,对源代码文件中的文件包含(#include)、预编译语句(如宏定义#define等)进行分析;其次调用ccl进行编译工作,将文件编译成汇编语言文件,此时文件依旧是可读的;之后调用as进行汇编工作,将具体的汇编语言文件编译成cpu可执行的目标代码,此时文件不可读了;当所有的目标文件都生成之后,gcc就调用ld来完成最后的关键性工作,链接。在链接阶段,所有的目标文件被安排在可执行程序中的恰当的位置,同时,该程序所调用到的库函数也从各自所在的库中链接到合适的地方。下面对上面4个过程做下分别的说明:

1、在预处理阶段,如果不用“-o”指定文件名,那么会默认将预处理结果输出到标准终端设备。

[root@dbbak tmp]# cat a.c
int main()
{
        printf("shengtong test!\n");
}

[root@dbbak tmp]# gcc -E a.c
# 1 "a.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "a.c"
int main()
{
        printf("shengtong test!\n");
}
[root@dbbak tmp]# gcc -E a.c -o a.i
[root@dbbak tmp]# cat a.i
# 1 "a.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "a.c"
int main()
{
        printf("shengtong test!\n");
}

2、在编译阶段,如果不用“-o”指定文件名,那么默认会生成一个“*.s”的汇编语言文件。

[root@dbbak tmp]# gcc -S a.i
[root@dbbak tmp]# ls
a.c a.i a.s
[root@dbbak tmp]# gcc -S a.i -o a1.s
[root@dbbak tmp]# ls
a.c a.i a.s a1.s

[root@dbbak tmp]#
[root@dbbak tmp]# cat a.s
        .file   "a.c"
        .section        .rodata
.LC0:
        .string "shengtong test!\n"
        .text
.globl main
        .type   main,@function
main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        andl    $-16, %esp
        movl    $0, %eax
        subl    %eax, %esp
        subl    $12, %esp
        pushl   $.LC0
        call    printf
        addl    $16, %esp
        leave
        ret
.Lfe1:
        .size   main,.Lfe1-main
        .section        .note.GNU-stack,"",@progbits
        .ident "GCC: (GNU) 3.2.3 20030502 (Red Hat Linux 3.2.3-42)"
[root@dbbak tmp]# cat a1.s
        .file   "a.c"
        .section        .rodata
.LC0:
        .string "shengtong test!\n"
        .text
.globl main
        .type   main,@function
main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        andl    $-16, %esp
        movl    $0, %eax
        subl    %eax, %esp
        subl    $12, %esp
        pushl   $.LC0
        call    printf
        addl    $16, %esp
        leave
        ret
.Lfe1:
        .size   main,.Lfe1-main
        .section        .note.GNU-stack,"",@progbits
        .ident "GCC: (GNU) 3.2.3 20030502 (Red Hat Linux 3.2.3-42)"

3、在汇编阶段,如果不用“-o”指定文件名,那么默认会生成一个“*.o”的机器语言代码文件。

[root@dbbak tmp]# gcc -c a.s
[root@dbbak tmp]# ls
a.c a.i a.o a.s a1.s
[root@dbbak tmp]# gcc -c a1.s -o a1.o
[root@dbbak tmp]# ls
a.c a.i a.o a.s a1.o a1.s
[root@dbbak tmp]#
[root@dbbak tmp]# file a.o
a.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
[root@dbbak tmp]# file a1.o
a1.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped

  • 1
  • 2
  • 3
  • 下一页

相关内容