标签:ubunt 版本 链接库 ... \n 条件编译 软件开发 head 设置断点
软件开发工具——GCC
GCC(GNU Compiler Collection,GNU编译套装)能够编译C、C++等语言。原本只能处理C语言,但是随着众多开发者的加入和GCC自身的发展,如今的GCC已成为可编译多种语言的编译器,如C/C++,Java,Fortran,Pascal等,GCC也由原来的GNU C Compiler变为GNU Compiler Collection,能够在当前CPU计算机平台上,为众多不同体系的硬件平台开发软件服务,尤其应用于嵌入式开发领域。
目前Linux默认使用的C编译器是GCC,具有如下优点:
通过GCC能够完美地控制整个编译过程,用户可以根据需要,在任何阶段让编译终止或暂停,以检查或使用编译器在该阶段的输出信息,并最终生成二进制文件。
通常使用"-On"控制优化配置,n越大,代码优化越明显。
GDB调试工具具有查看程序运行状态、设置断点、查看表达式、显示变量等众多功能。GCC和GDB的结合使用是开发者进行C语言编程的利剑。
提供众多的编译选项可以定制人性化的编译过程。例如可以产生调试信息、优化代码执行过程、选取需要的头文件等。
提供很多警告信息,增强了程序的稳定性和可移植性。
GCC编译过程分为四个阶段:预处理、编译、汇编、链接。如下图所示:
提供帮助:
gcc --heip
GCC常用选项:
选项 | 含义 |
-V | 查看gcc编译器的版本,显示gcc执行时的详细过程 |
-O file | 把输出文件制定到file中,该选项可以输出汇编文件、目标文件以及可执行文件。 |
-E | 只对源文件进行预处理,不做编译、汇编及链接,GCC会忽略任何不需要预处理的输入文件。 |
-S | 只进行编译,不做汇编及链接,对于每个输入的非汇编语言文件,输出文件都是汇编语言文件。 |
-c | 只进行汇编,不做链接,汇编成源文件的目标文件,默认状态下生成.o文件,GCC忽略-c选项后面任何无法识别的输入文件。 |
例如新建文件hello.c如下:
#include <stdio.h> int main() { printf("hello, world\n"); }
第一步 预处理阶段
执行命令: gcc -o hello.i -E hello.c
预处理器cpp根据以字符开头#开头的命令,修改原始C程序。比如hello.c中的第一行为 #include <stdio.h>,预处理器便将stdio.h的内容直接插入到程序中。预处理之后得到文本文件hello.i,打开如下:
# 1 "hello.c" # 1 "<built-in>" # 1 "<command-line>" # 31 "<command-line>" # 1 "/usr/include/stdc-predef.h" 1 3 4 # 32 "<command-line>" 2 # 1 "hello.c" # 1 "/usr/include/stdio.h" 1 3 4 # 27 "/usr/include/stdio.h" 3 4 # 1 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 1 3 4 # 33 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 3 4 # 1 "/usr/include/features.h" 1 3 4 # 424 "/usr/include/features.h" 3 4
.........
extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
# 868 "/usr/include/stdio.h" 3 4
# 2 "hello.c" 2
# 3 "hello.c"
int main()
{
printf("hello, world\n");
}
预处理就是将要包含(include)的文件插入原文件中、将宏定义展开、根据条件编译命令选择要使用的代码,最后将这些代码输出到一个“.i”文件中等待进一步处理。
第二步 编译阶段
执行命令: gcc -o hello.s -S hello.i
编译器ccl将文本文件hello.i 翻译为hello.s,这个文件里面包含一个汇编程序,就是把C/C++代码(比如上面的".i"文件)“翻译”成汇编代码。汇编语言是非常有用的,因为它将不同高级语言的不同编译器提供了通用的输出语言。如下所示:
.file "hello.c" .text .section .rodata .LC0: .string "hello, world" .text .globl main .type main, @function main: .LFB0: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 leaq .LC0(%rip), %rdi call puts@PLT movl $0, %eax popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size main, .-main .ident "GCC: (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0" .section .note.GNU-stack,"",@progbits
第三步 汇编阶段
执行命令:gcc -c -o hello.o hello.s
汇编器as将hello.s翻译成机器语言保存在hello.o中。汇编就是将第二步输出的汇编代码翻译成符合一定格式的机器代码,在Linux系统上一般表现位ELF目标文件(OBJ文件)。
第四步 链接阶段
执行命令: gcc -o hello hello.o
链接就是将汇编生成的OBJ文件、系统库的OBJ文件、库文件链接起来,最终生成可以在特定平台运行的可执行程序。链接分为静态链接和动态链接两种。
动态链接:动态链接使用动态链接库进行链接,生成的程序在执行的时候需要加载所需的动态库才能运行。 动态链接生成的程序体积较小,但是必须依赖所需的动态库,否则无法执行。
静态链接:静态链接使用静态库进行链接,生成的程序包含程序运行所需要的全部库,可以直接运行,不过静态链接生成的程序体积较大。
结果得到hello 可执行文件,可以被加载到内存中由系统执行。
./hello
完整的执行过程为:
keegen@keegensCP:~/test$ touch hello.c keegen@keegensCP:~/test$ vim hello.c keegen@keegensCP:~/test$ gcc -o hello.i -E hello.c keegen@keegensCP:~/test$ ls -a . .. hello.c hello.i keegen@keegensCP:~/test$ gcc -o hello.s -S hello.i keegen@keegensCP:~/test$ ls -a . .. hello.c hello.i hello.s keegen@keegensCP:~/test$ gcc -c -o hello.o hello.s keegen@keegensCP:~/test$ ls hello.c hello.i hello.o hello.s keegen@keegensCP:~/test$ gcc -o hello hello.o keegen@keegensCP:~/test$ ls hello hello.c hello.i hello.o hello.s keegen@keegensCP:~/test$ ./hello hello, world
总结编译器的编译过程:
源文件-->预处理-->编译/优化-->汇编-->链接 -->可执行文件
在编译过程中。除非使用了"-c",“-S”,或"-E"选项(或者编译错误阻止了完整的过程),否则统一完整链接步骤。如运行
gcc hello.c 或 gcc -o hello hello.c
keegen@keegensCP:~/test$ rm -rf hello hello.i hello.o hello.s keegen@keegensCP:~/test$ ls hello.c keegen@keegensCP:~/test$ gcc hello.c keegen@keegensCP:~/test$ ls a.out hello.c keegen@keegensCP:~/test$ ./a.out hello, world keegen@keegensCP:~/test$ gcc -o hello hello.c keegen@keegensCP:~/test$ ls a.out hello hello.c keegen@keegensCP:~/test$ ./hello hello, world
标签:ubunt 版本 链接库 ... \n 条件编译 软件开发 head 设置断点
原文地址:https://www.cnblogs.com/keegentang/p/10678254.html