程序的编译

本文详细介绍了C程序从翻译环境到执行环境的全过程,包括编译的预处理、编译、汇编和链接四个阶段,以及运行环境中的程序加载和执行。在编译过程中,讲解了预处理如何处理头文件、宏定义和注释,以及语法分析、词法分析、语义分析和优化等步骤。链接阶段则涉及目标文件的合并、符号表的处理和重定位。最后,讨论了程序在内存中的载入和执行,包括main函数的调用、堆栈和静态内存的使用。
摘要由CSDN通过智能技术生成

1、程序的翻译环境和执行环境

在ANSI C的任何一种实现中,存在两个不同的环境。

  1. 第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。
  2. 第2种是执行环境,它用于实际执行代码

2、详解编译+链接

2.1 编译环境

在这里插入图片描述

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

2.2 编译的几个阶段

预编译->编译->汇编

接下来用Linux解释这几个阶段

  1. 先通过命令vim test.c 创建test.c文件
    在这里插入图片描述
    这是test.c的内容
    在这里插入图片描述
  2. 通过命令 gcc test.c -E 进行预处理
    通过预处理我们可以看到写的c文件内容在下面,上面有一段内容是来自stdio头文件的,我们可以stdio.h发现是来自 /usr/include/ 路径下的。
    在这里插入图片描述
  3. 我们重新创建test.c文件
    在这里插入图片描述
  4. 通过 gcc test.c -E > test.i 进行预编译并将预处理后的文件放于文件test.i中。

通过下面的图我们发现预编译进行了三部分的处理

  • 完成了头文件的包含#include
  • #define定义的符号和宏的替换
  • 删除了注释
    在这里插入图片描述
  1. 在通过命令 gcc test.i -S 将C代码编译成汇编代码生成文件 test.s
    这里汇编就不作解释了,看得懂的都是大佬(狗头保命
    在这里插入图片描述

编译阶段进行了四个步骤:

  • 语法分析
    源代码程序进入扫描器(scanner),将源代码的字符序列分割成一系列的记号(Token)。并将记号进行分类,如符号表(存放标识符)和文字表(存放数字、字符串常量)等。
  • 词法分析
    语法分析器(Grammer Parser)对记号(Token)进行语法分析,并生成语法树(Syntax Tree)。
  • 语义分析
    语义分析器完成对表达式的语法层面的分析。它不知道语句真正含义,是对静态语义的分析。所谓静态语义,是编译期可确定的语义,包括声明、类型匹配和类型转换。对应的动态语义,则是运行期确定的语义。
  • 符号汇总
    源代码优化器对源代码进行优化。如将编译期可确定的值进行优化。
    此处四个步骤参考链接: gcc编译原理.
  1. 在通过命令 gcc test.s -c 将汇编代码翻译成二进制指令(机器指令)生成对应目标文件 test.o
    在这里插入图片描述
    test.o 文件格式是 elf 格式,elf 文件又是分段组成的。
    这里我们可以通过命令 readelf test.o -s 来查看,可以看到符号汇总(红色圈圈部分),是我们刚刚在test.c文件中定义的。
    在这里插入图片描述
  2. 最后通过命令 gcc test.o 可以将多个目标文件通过连接器与链接库进行链接生成a.out文件(可执行文件)。
    在这里插入图片描述

链接作用:

  • 合并段表(elf格式文件相同段的部分进行合并,a.out也是elf格式文件)
  • 符号表合并和重定位
  1. 我们这里在重新创建两个文件 test.c 和 add.c
    在这里插入图片描述
    在这里插入图片描述
    我们再次通过命令 readelf test.o -s 来查看符号汇总
    在这里插入图片描述
    在这里插入图片描述
    通过红色部分,我们可以看到两个文件的符号汇总。
    变量和函数都是有地址的,但是不能两个一样的符号在一起把,extern外部声明的符号是没有实际地址的,所以这里用的是sum.c文件中变量的地址。所以链接完之后,符号表合并的就是这些变量。
    在这里插入图片描述

2.3 运行环境

程序执行的过程:

  1. 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序
    的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
  2. 程序的执行便开始。接着便调用main函数。
  3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回
    地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程
    一直保留他们的值。
  4. 终止程序。正常终止main函数;也有可能是意外终止。

点个赞在走吧!!!

在这里插入图片描述

  • 13
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雨轩(爵丶迹)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值