gcc编译过程
以helloworld为例分析gcc编译过程:
#include
int main()
{
printf(“Hello World\n”);
return 0;
}
通常我们使用gcc来生成可执行程序,命令为:gcc hello.c,生成可执行文件a.out
实际上gcc hello.c可以分解为4个步骤,分别是预处理(Preprocess),编译(Compilation),汇编(Assembly)和链接(Linking),如下图所示:
1 预编译
gcc –E hello.c –o hello.i,以下为预处理后的输出文件hello.i的内容
# 1 "hello.c"
# 1 ""
# 1 ""
# 1 "hello.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 28 "/usr/include/stdio.h" 3 4
/***** 省略了部分内容,包括stdio.h中的一些声明及定义 *****/
# 2 "hello.c" 2
int main()
{
printf("Hello World\n");
return 0;
}
预编译过程主要处理那些源代码中以#开始的预编译指令,主要处理规则如下:
l 将所有的#define删除,并且展开所有的宏定义;
l 处理所有条件编译指令,如#if,#ifdef等;
l 处理#include预编译指令,将被包含的文件插入到该预编译指令的位置。该过程递归进行,及被包含的文件可能还包含其他文件。
l 删除所有的注释//和 /**/;
l 添加行号和文件标识,如#2 “hello.c” 2,以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号信息;
l 保留所有的#pragma编译器指令,因为编译器须要使用它们;
2 编译
编译过程就是把预处理完的文件进行一系列词法分析,语法分析,语义分析及优化后生成相应的汇编代码文件。
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:
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: (GNU) 4.4.0 20090506 (Red Hat 4.4.0-4)"
.section .note.GNU-stack,"",@progbits
3 汇编
汇编器是将汇编代码转变成机器可以执行的命令,每一个汇编语句几乎都对应一条机器指令。汇编相对于编译过程比较简单,根据汇编指令和机器指令的对照表一一翻译即可。
gcc –c hello.c –o hello.o,由于hello.o的内容为机器码,不能以文本形式方便的呈现。
4 链接
链接器ld将各个目标文件组装在一起,解决符号依赖,库依赖关系,并生成可执行文件。
ld –static crt1.o crti.o crtbeginT.o hello.o –start-group –lgcc –lgcc_eh –lc-end-group crtend.o crtn.o (省略了文件的路径名)。
原文地址:https://www.cnblogs.com/theoutoftunestring/p/15375966.html
- 这是一个悲伤的故事
- Golang语言社区--标准库分析之strconv包
- Golang语言社区--结构体数据排序
- mybatis-plus思维导图,让mybatis-plus不再难懂
- ABAP OPEN SQL里OPEN CURSOR和SELECT的比较
- 如何用ABAP代码读取CDS view association的数据
- 使用代币替代传统积分系统
- BTA 常问的 Java基础40道常见面试题及详细答案
- Docker PHP 最佳实践
- 颠覆你对区块链的认识
- 三种决策树算法(ID3, CART, C4.5)及Python实现
- PHP入门-常量基本规则
- PHP入门-书写语法以及基本规范
- 如何清除浮动
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【不可思议的CANVAS】画一只会跟着鼠标走的小狗
- 【Netty】03-实战之序列化与反序列化协议
- JDK15正式发布,划时代的ZGC同时宣布转正
- 一文掌握开发利器:正则表达式
- 探讨iOS 图片解压缩到渲染过程
- iOS Abort 问题系统的解决方案
- 【jvm】01- java内存结构分析
- 【redis】01-redis简介
- 3000字详解四种常用的缺失值处理方法
- python学习笔记(7)——远程主机强迫关闭了一个现有的连接
- 【带你成为pyq最靓的仔】朋友圈九宫格(一)之图片切割篇
- Material Design Compoents 1.1.0
- 【第19期】HTTP请求头referer
- Sentinel流控日志与索引
- Next.js + TypeScript 搭建一个简易的博客系统