Gcc 编译过程

gcc编译

gcc hello.c -o hello

hello.c 预处理——>hello.i 编译——>hello.s 汇编——>hello.o 链接——>hello

示例

hello.c

#include<stdio.h>
#define TEST_STRING "hello world!"
int main()
{
printf("%s\n", TEST_STRING);
return 0;
}

预处理

gcc -E hello.c -o hello.i

预编译过程主要处理那些源代码文件中以“#”开始的预编译指令,比如“#include”、“#define”等。

主要处理规则有:

  1. 将所有的“#define”删除,并且展开所有的宏定义。
  2. 处理所有的条件预编译指令,比如:“#if”、“#ifdef”、“#elif”、“#else”、“#endif”
  3. 处理“include”预编译指令,将被包含的文件插入到该预编译指令的位置,该过程是递归进行的。
  4. 删除所有的注释“//”和“/**/”。
  5. 添加行号和文件名标识,以便于编译时编译器产生调试用的行号信息及用于编译时产出错误或警告时能够显示行号。
  6. 保留所有的#pragma编译器指令,因为编译器需要使用它们。

hello.i 文件末尾内容如下,头文件已展开,并将 TEST_STRING 替换为 hello world

/**
* bala bala 省略部分
*/
# 940 "/usr/include/stdio.h" 3 4
# 9 "hello.c" 2
int main()
{
printf("%s\n", "hello world!");
return 0;
}

编译

编译过程就是把预处理完的文件进行一系列词法分析、语法分析、语义分析及优化后生成相应的汇编代码文件。

gcc -S hello.i -o hello.s

编译生成汇编代码 hello.s

.file "hello.c"
.section .rodata
.LC0:
.string "hello world!"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl $16, %esp
movl $.LC0, (%esp)
call puts
movl $0, %eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
.section .note.GNU-stack,"",@progbits

汇编

汇编器是将汇编代码转变成机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令。

汇编后输出 目标文件,还不可执行!

gcc -c hello.s -o hello.o

链接

链接的过程主要包括:地址和空间分配、符号决议和重定位

主要工作是把一些指令对其它符号地址的引用加以修正,把各个模块之间的相互引用的部分处理好。
比如 A 模块用到 B 模块的某个函数,但是在编译 A 模块时,并不知道 B 模块中的函数的地址,所以需要链接器来处理。

符号决议:

确保所有目标文件中的符号引用都有唯一的定义

重定位:

链接时,确定变量或函数的地址后,把指令的目标地址修改成确定后的地址,这个过程就是重定位

gcc hello.o -o hello
posted @   shelmean  阅读(61)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示