从源码到可执行文件(那些被隐藏了的过程)

23 篇文章 0 订阅
20 篇文章 0 订阅

本文介绍Linux下如何将高级语言(C/C++)编写的代码编译成二进制可执行文件的过程

预处理

概述

源文件file.c被预编译器cpp处理为file.i文件的过程

终端命令

gcc -E file.c -o file.i 或者 cpp file.c > test.i

处理规则

  • 处理所有的条件编译指令
  • #include递归引入的头文件包含进当前文件
  • 删掉所有的#define,替换宏常量,展开所有的宏定义
  • 删掉文件中的注释
  • 保留#pragma编译器指令
  • 添加行号和文件名标识,便于编译器产生调试和error / warning使用的信息

编译

概述

c -> cc1、c++ -> cclplus、java -> jc1

由预编译编译程序(新版本的gcc将预编译和编译统一交给同一个程序处理)将源文件 / 预处理后的文件进行词法分析、语法分析、语义分析、优化后产生汇编代码文件的过程。

终端命令

gcc -S file.c -o file.s或者gcc -S file.i -o file.s

处理规则

词法分析

词法分析器lex运用类似有限状态机的算法将源码序列分割成一系列记号记号可分为:标识符字面值常量特殊符号几类。识别的同时,将各类记号分类保存,以备后续使用。

eg:
	标识符 -> 符号表
	字面常量 -> 文字表
	......
语法分析

语法分析器yacc将扫描器lex产生的记号使用上下文无关语法进行语法分析,生成语法树。语法树的节点由表达式构成。

这个过程可以检测出表达式是否合法。eg:

  • 括号不匹配
  • 表达式中缺少操作

若不合法,编译器会报告语法分析阶段的错误。

语义分析

语义分析器可以对静态语义进行分析,静态语义即在编译期间能够确定的语义。与之相对的动态语义为运行期间才能够确定的语义。

静态语义包括:声明和类型的匹配,类型的转换等。如果分析过程中出现类似“将浮点型数据赋值给指针”这种无法进行隐式类型转换的类型不匹配错误,编译器就会报错。

语义分析后,整个语法树的节点都被标识了类型,有时还会在树中插入相应的转换节点。

优化

优化分为两个部分:

  1. 源代码优化
    因为直接在语法树上优化比较困难,也没有必要,所以源代码优化器就将语法树转换成中间代码,在这个过程进行一系列的优化。
    中间代码和机器以及运行时环境无关,所以是可以跨平台的。因为它不会包含数据的尺寸,变量地址以及寄存器名字等。
    常见的中间代码形式有:三地址码P-代码
  2. 目标代码生成和优化
    代码生成器将中间代码转换成目标机器代码,这个过程十分依赖机器,因为不同的机器具有不同的字长,寄存器,数据类型等。
    目标代码优化器会使用一系列方法进行优化,例如:合适的寻址方式、使用位移来代替乘除法、删除多余的指令等。

汇编

概述

由汇编器as将编译后的代码对照翻译成机器码的过程

终端命令

gcc -c file.c -o file.o


链接

链接器 collect2。注意:colletc2是ld的一层包装

此阶段的工作:

  • 合并段表
  • 符号表的合并和重定位
  • 将文件中调用的各种静态库和共享库和当前文件链接在一起,形成可执行文件
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值