Linux中gcc编译器

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/ychyxch/article/details/81287249

目录

基本知识

术语

本文中用的术语:源文件、目标文件、可执行文件。
1. 源文件:通常指编辑代码的文件;
2. 目标文件:经过编译器的编译生成的CPU可识别的二进制代码,一般是不能执行的;
3. 可执行文件:目标文件与相关的库链接后的文件,顾名思义可执行文件是可以执行的。

编译过程

GCC编译器对程序的编译分为4个阶段:预编译、编译和优化、汇编以及链接。GCC编译器可以将这4个步骤合并为一个。

  • 预编译
    将程序中引用的头文件包含进源代码中,并对一些宏进行替换。
  • 编译和优化
    将用户可识别的鱼眼翻译成一组处理器可识别的操作码,生成目标文件,通常翻译成汇编语言。
  • 汇编
    将编译输出的汇编代码翻译成符合一定格式的机器代码,在Linux系统上一般表现位ELF目标文件(OBJ文件)。
  • 链接
    就是将汇编生成的OBJ文件、系统库的OBJ文件、库文件链接起来,最终生成可以在特定平台运行的可执行程序。

自动编译

自动编译的过程包括头文件扩展、目标文件编译,以及链接默认的系统库生成可执行文件,最后生成系统默认的可执行程序a.out。
以“Hello World!”源码为例

/*hello-world.c*/
#include <stdio.h>               //头文件包含

int main(void)
{
    printf("Hello World!\n");    //打印“Hello World!”
    return 0;
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

运行如下命令直接编译成可执行文件:

$gcc hello-world.c
 
 
  • 1

执行生成的可执行文件a.out如下:

$ ./a.out 
Hello World!
 
 
  • 1
  • 2

在编译过程中会生成一个对应的a.out.h文件一般存放在/usr/lib/gcc/i486-linux-gnu/4.4.3/include-fixed/linux路径下,其中i486-linux-gnu/4.4.3为对应的gcc版本可通过执行gcc -v查看,如下:

$ gcc -v
Using built-in specs.
Target: i486-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.4.3-4ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --program-suffix=-4.4 --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-plugin --enable-objc-gc --enable-targets=all --disable-werror --with-arch-32=i486 --with-tune=generic --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu
Thread model: posix
gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5) 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

分步编译

预处理

通过在编译过程中使用编译选项-E告诉编译器进行预编译操作,继续以“hello-world.c”为例,输入如下指令,可以将预处理结果输出到屏幕上;

$ gcc -E hello-world.c 
# 1 "hello-world.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "hello-world.c"
……//省略部分内容
# 3 "hello-world.c" 2

int main(void)
{
    printf("Hello World!\n");
    return 0;
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

一般使用如下命令生成预编译后的中间文件,如下:

$ gcc -o hello-world.i -E hello-world.c

 
 
  • 1
  • 2

编译和优化

编译生成汇编语言,使用的GCC选项是-S,默认情况下声场的文件名和源文件名一致,扩展名为.s,既可以通过源文件直接生成汇编文件,也也可以使用预处理后的文件生成汇编文件,使用源文件的指令如下:

$ gcc-S hello-world.c
 
 
  • 1

使用预处理文件编译指令如下:

$ gcc -o hello-world.s -S hello-world.i 
 
 
  • 1

输出的汇编文件如下:

    .file   "hello-world.c"
    .section    .rodata
.LC0:
    .string "Hello World!"
    .text
.globl main
    .type   main, @function
main:
    pushl   %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    subl    $16, %esp
    movl    $.LC0, (%esp)
    call    puts
    movl    $0, %eax
    leave
    ret
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
    .section    .note.GNU-stack,"",@progbits
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

汇编

汇编生成机器文件的指令如下

$gcc -o hello-world.o -c hello-world.s
 
 
  • 1

生成的.o文件可以通过如下指令进行查看:

$ hexdump -C hello-world.o 
00000000  7f 45 4c 46 01 01 01 00  00 00 00 00 00 00 00 00  |.ELF............|
00000010  01 00 03 00 01 00 00 00  00 00 00 00 00 00 00 00  |................|
00000020  d4 00 00 00 00 00 00 00  34 00 00 00 00 00 28 00  |........4.....(.|
00000030  0b 00 08 00 55 89 e5 83  e4 f0 83 ec 10 c7 04 24  |....U..........$|
00000040  00 00 00 00 e8 fc ff ff  ff b8 00 00 00 00 c9 c3  |................|
00000050  48 65 6c 6c 6f 20 57 6f  72 6c 64 21 00 00 47 43  |Hello World!..GC|
00000060  43 3a 20 28 55 62 75 6e  74 75 20 34 2e 34 2e 33  |C: (Ubuntu 4.4.3|
00000070  2d 34 75 62 75 6e 74 75  35 29 20 34 2e 34 2e 33  |-4ubuntu5) 4.4.3|
00000080  00 00 2e 73 79 6d 74 61  62 00 2e 73 74 72 74 61  |...symtab..strta|
00000090  62 00 2e 73 68 73 74 72  74 61 62 00 2e 72 65 6c  |b..shstrtab..rel|
000000a0  2e 74 65 78 74 00 2e 64  61 74 61 00 2e 62 73 73  |.text..data..bss|
000000b0  00 2e 72 6f 64 61 74 61  00 2e 63 6f 6d 6d 65 6e  |..rodata..commen|
000000c0  74 00 2e 6e 6f 74 65 2e  47 4e 55 2d 73 74 61 63  |t..note.GNU-stac|
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

链接

通过.o文件可以使用如下命令生成可执行文件hello-world:

 $gcc -o hello-world hello-world.o
 
 
  • 1

同样.o文件换成源文件等任意的一个中间版本均可生成可执行文件。
输入如下指令可以查看链接的过程:

$ gcc -v -o hello hello-world.o
Using built-in specs.
Target: i486-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.4.3-4ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --program-suffix=-4.4 --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-plugin --enable-objc-gc --enable-targets=all --disable-werror --with-arch-32=i486 --with-tune=generic --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu
Thread model: posix
gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5) 
COMPILER_PATH=/usr/lib/gcc/i486-linux-gnu/4.4.3/:/usr/lib/gcc/i486-linux-gnu/4.4.3/:/usr/lib/gcc/i486-linux-gnu/:/usr/lib/gcc/i486-linux-gnu/4.4.3/:/usr/lib/gcc/i486-linux-gnu/:/usr/lib/gcc/i486-linux-gnu/4.4.3/:/usr/lib/gcc/i486-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/i486-linux-gnu/4.4.3/:/usr/lib/gcc/i486-linux-gnu/4.4.3/:/usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/i486-linux-gnu/4.4.3/../../../:/lib/:/usr/lib/:/usr/lib/i486-linux-gnu/
COLLECT_GCC_OPTIONS='-v' '-o' 'hello' '-mtune=generic' '-march=i486'
 /usr/lib/gcc/i486-linux-gnu/4.4.3/collect2 --build-id --eh-frame-hdr -m elf_i386 --hash-style=both -dynamic-linker /lib/ld-linux.so.2 -o hello -z relro /usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crt1.o /usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crti.o /usr/lib/gcc/i486-linux-gnu/4.4.3/crtbegin.o -L/usr/lib/gcc/i486-linux-gnu/4.4.3 -L/usr/lib/gcc/i486-linux-gnu/4.4.3 -L/usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/i486-linux-gnu/4.4.3/../../.. -L/usr/lib/i486-linux-gnu hello-world.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i486-linux-gnu/4.4.3/crtend.o /usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crtn.o
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • crt1.o、crti.o、crtbegin.o、crtend.o、crtn.o是gcc加入的系统标准启动文件,对于一般应用程序,这些启动是必需的。
  • lc:链接libc库文件,其中libc库文件中就实现了printf等函数。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值