【C语言】.c源文件从编译到链接生成可执行程序的过程

本篇文章目录

  • [1. 过程概览](#1. 过程概览)
  • [2. 编译与链接](#2. 编译与链接)
    • [2.1 预编译/预处理](#2.1 预编译/预处理)
    • [2.2 编译](#2.2 编译)
    • [2.3 汇编](#2.3 汇编)
    • [2.4 链接](#2.4 链接)
  • [3. 执行/运行环境](#3. 执行/运行环境)

1. 过程概览

编译到链接是c语言的翻译环境,c语言还有执行环境。

  1. 组成一个程序的每个源文件通过编译过程分别转换成目标代码(object code);
  2. 每个目标文件由链接器(linker)捆绑在一起,形成一个单一而完整的可执行程序;
  3. 链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库,将其需要的函数也链接到程序中。

2. 编译与链接

2.1 预编译/预处理

总的来说都是文本操作,注释被删除替换成一个空格;#define定义的符号也会被删除,其它所有出现这个符号的地方都被替换成所代表的常量;头文件所有函数实现都会包含进来,总共大概一两万行,最后才是自己写的代码。

预编译后会产生一个对应的.i文件,不过要说明的是这个预编译的步骤在vs中可以看到,但后面的步骤基本只能在linux gcc编译器,使用指令一步步看。

在windows vs中查看预编译后产生的文件:

选择是然后运行程序,实际程序会编译失败,因为仅仅只进行了预处理这个步骤,不过可以在项目文件下的X64/Debug下看到一个对应的.i文件。

在linux下执行预处理选项指令 gcc -E test.c -o test.i(-E代表只进行预处理,-o test.i代表指定输出到这个文件),预处理完成之后就停下来,预处理之后产生的结果都放在test.i文件中。

2.2 编译

在linux下执行编译选项指令 gcc -S test.c,编译完成之后就停下来,结果保存在test.s中。

编译阶段会将c代码转换为汇编代码,汇编大致会经过四个阶段:

  1. 词法分析;
  2. 语法分析;
  3. 语义分析;
  4. 符号汇总。

比如图中左边的这段代码,对应右边编译器一个个符号分析它们分别代表什么。

语法分析阶段会产生一个语法树:

语义分析应该是根据语法树进行,我也不是很了解。

符号汇总这个阶段很重要,编译器会将每个.c文件中的全局符号(函数名、全局变量)汇总起来,后面的汇编和链接都会涉及到符号的处理。

2.3 汇编

汇编阶段是将编译阶段产生的.s文件(汇编代码)转成二进制机器码文件。在linux下执行汇编指令 gcc -c test.c,汇编完成之后就停下来,结果保存在test.o中。

在这个阶段会根据前面编译阶段的符号汇总,产生一个符号表,如:

对于右边申明的Add函数,在符号表中的地址是无效的,后续不会使用这个无效的地址,而是使用左边的地址,符号表在连接阶段会使用。

2.4 链接

链接阶段链接器(linker)会链接所有产生的.obj / .o目标文件,以及链接库生成合并成一个二进制的.exe可执行程序文件,这个阶段会经历合并段表、合并符号表操作。

gcc编译器生成的二进制目标文件和二进制的可执行文件,都是按照elf文件形式组织的,合并段表要做的就是将所有.o文件中相同数据段进行合并在一起;每个文件产生的符号表最后也会合并在一起,符号表中无效的地址会被舍弃,使用有效的地址,因为链接器链接查找函数都是根据符号和地址的匹配关系去找的,不然没法找到;最后生成一个.exe文件。

add.c和test.c的符号表,其中0x0000,无效的地址值会被舍弃:

如果add.c中没有Add函数,那么符号表中没有对应的函数名Add和地址,那么会连接失败:

3. 执行/运行环境

  1. 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
  2. 程序的执行便开始。接着便调用main函数。
  3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。
  4. 终止程序。正常终止main函数;也有可能是意外终止。
相关推荐
Cons.W42 分钟前
Codeforces Round 975 (Div. 1) C. Tree Pruning
c语言·开发语言·剪枝
挥剑决浮云 -1 小时前
Linux 之 安装软件、GCC编译器、Linux 操作系统基础
linux·服务器·c语言·c++·经验分享·笔记
一颗星星辰2 小时前
C语言 | 第十章 | 函数 作用域
c语言·开发语言
꧁༺❀氯ྀൢ躅ྀൢ❀༻꧂2 小时前
实验4 循环结构
c语言·算法·基础题
从0至12 小时前
力扣刷题 | 两数之和
c语言·开发语言
小比卡丘3 小时前
C语言进阶版第17课—自定义类型:联合和枚举
android·java·c语言
一个不知名程序员www3 小时前
leetcode第189题:轮转数组(C语言版)
c语言·leetcode
冷白白3 小时前
【C++】C++对象初探及友元
c语言·开发语言·c++·算法
睡觉然后上课4 小时前
c基础面试题
c语言·开发语言·c++·面试