ToB企服应用市场:ToB评测及商务社交产业平台

标题: C语言执行过程 [打印本页]

作者: 天空闲话    时间: 2022-6-25 16:25
标题: C语言执行过程
本文中涉及的代码地址:analyseExecutionOfC
文件结构:
  1. analyse-execution-of-c
  2.         |-- compilePreProcessSource.o
  3.         |-- compilePreProcessSource.o.png
  4.         |-- compilePreProcessSource.s
  5.         |-- preProcessSource.c
  6.         |-- source
  7.         |-- source.c
  8.         |-- source.png
复制代码
引言

我们比较熟悉的C语言执行流程为:预处理、编译、汇编、链接、运行。但是各个阶段的具体流程又是什么呢?接下来针对每个阶段详细分析。
C语言的流行离不开gcc编译器的成功。gcc编译器帮助C程序完成四个阶段:预处理编译汇编链接。然后将链接后的程序交给OS 执行
本文简单介绍了C语言在执行之前的准备阶段,事实上每个阶段都是十分复杂的,绝对不是一篇或者几篇文章能够描述的,所以这里只能将描述停留在入门级上,希望能够对大家有所帮助。
GCC 编译过程

源文件

  1. #include<stdio.h>
  2. // 声明函数sum
  3. int sum(int arg1, int arg2);
  4. // main被gcc编译器的桩程序调用
  5. int main(){
  6.         sum(3, 5);
  7.         return 0;
  8. }
  9. // 初始化函数sum
  10. int sum(int arg1, int arg2){
  11.         int res = arg1 + arg2;
  12.         return res;
  13. }
复制代码
预处理

在 linux 中运行:gcc -E source.c -o preProcessSource.c 。得到 preProcessSource.c 文件。
参数 -E 运行 preprocessor,-o 将运行结果输出到 preProcessSource.c 文件中。
预处理会丰富我们的源程序,调整删除多余的空格字符和制表符;将字符常数转化成对应的值;替换宏定义等。此时输出仍然是纯C代码。
编译

在 linux 中运行:gcc -S preProcessSource.c -o compilePreProcessSource.s。得到 compilePreProcessSource.s 文件。
参数 -S 将 preProcessSource.c 编译为汇编程序 compilePreProcessSource.s。
编译可以被通俗地理解为将一种格式的字符串转化为另一种格式的字符串。将这个概念带入 -S 指令,可以认为 source.c 源码中出现的 sum(3, 5) 被转化为汇编语言 call sum。
实际上C语言中函数的调用的确对应 X86汇编语言 的 call 指令。但是转化过程十分复杂。不同理论的语言有不同的编译原理,主要分为两各派系,一类是面向过程的编译,一类是面向对象的编译。
接下来我将站在逻辑层面(means I won’t code a real compiler, But I will guide you to understand the compilation process ),结合C语言编译器的实现过程描述C语言的实现过程。

汇编

在 linux 中运行:gcc -c compilePreProcessSource.s -o compilePreProcessSource.o 得到 compilePreProcessSource.o 文件。
参数 -c 将执行汇编过程,并通过 -o 将汇编结果输出到 compilePreProcessSource.o 文件中。
汇编结果展示

看到展示的结果,小伙伴们可能有一些懵,不用着急,随着接下来我们新概念的引入,相信能够解决你的疑惑。


区(section)(也称为段、节或部分)用于表示一个地址范围,操作系统以相同的方式对待和处理在该地址范围内的数据信息。区的概念主要用来表示编译器生成的目标文件(或可执行文件)中不同的信息区域。
链接器会将输入的目标文件内容按照一定规律组合成一个可执行程序。
这里仅仅讲解其中的部分区域,有兴趣的小伙伴可以参考gcc官方文档查看每一个区的作用。
text区、data区:这两个区用以保存程序。当程序运行时,text区通常不会改变,text区中的内容会被进程共享,其中含有指令代码和常数等内容。程序在执行时data区的内容通常是变化的,例如,C语言的变量就存放在data区中。
bss区:该区用于存放未初始化的变量或作为公共变量储存空间。
因为 .o 目标文件有自己规定的格式,每种格式有其特殊含义,所以建议有兴趣的小伙伴可以阅读gcc官方文档。只要理解不同的区被用来实现不同的功能,这些功能配合起来能够成功执行程序就行了。
链接

链接器会将输入的目标文件内容按照一定规律组合成一个可执行程序。
在 linux 中运行:gcc compilePreProcessSource.o -o source 得到 source 文件。
gcc 命令将 compilePreProcessSource.o 链接为可执行文件 source。
链接结果展示

在汇编阶段已经介绍了链接器将目标文件转化为可执行文件。
可执行文件也是文件,有自己的格式,但是不同操作系统定义了不同的可执行文件的格式。根据可执行文件操作系统就能够按顺序执行对应的汇编指令,我们也能得到程序的运行结果。
问题

如果有什么问题可以在issue中发起提问。
另外稍后将会出一片文章,使用本文中的代码将程序的出栈入栈过程绘制出来。
参考文章



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4