ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

预处理之翻译和执行环境详解(跑路人笔记)

2022-01-20 12:31:01  阅读:164  来源: 互联网

标签:文件 符号表 汇编 环境 笔记 编译 详解 test 预处理


文章目录

前言

大家吼啊,进阶C已经接近尾声了,这估计是进阶C的倒数第二个博客了嘿嘿.

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

翻译环境类比于我们的VS2019集成开发环境

如图:

image-20220118151113009

image-20220118211250463

我们的可执行程序在生成的过程中,先将源文件逐个单独(一定是逐个单独)交给编译器使其变成我们连接器可以使用的目标文件(在Windows系统的拓展名是.obj )如test.c—>test.obj,然后经过连接器统一处理变成可执行程序.

翻译环境如何工作

image-20220118210127994

围绕着这个两个图展开

分两大步——编译和链接。

编译[^1]

编译这一步通过编译器完成

编译又分

  • 预编译(也叫预处理)

    • 完成了头文件的包含

    • #define定义的符号和宏的替换

    • 删除注释

      一系列的文本操作

  • 编译

    • 语法分析

    • 词法分析

    • 语义分析

    • 符号汇总

      也就是将C语言代码转换成了汇编代码。

  • 汇编

    • 将汇编代码转换成二进制也就是机器语言

    • 生成符号表

      生成了.obj的文件(他的格式elf),我们可以通过readelf这个工具来观察这个文件.

预编译

当我们想在gcc编译器下得到预编译后的结果可以通过输入:gcc test.c -E这样我们就得到了预编译后的文件test.i

功能一:完成头文件的包含

​ 原代码:

image-20220119181626401

后得到的文件内容:

image-20220119181947816

又分为了两个部分:

1.看不懂的部分

image-20220119182108303

而这我们看不懂的部分其实是对#include<stdio.h>的操作.他讲stdio.h内的文件包含到了我们的函数内

注:我们的stdio.h文件并非仅仅只有这些只是但是并非我们需要重视的知识点.

2.几乎和我们代码相同的部分

image-20220119182200073

这些就是我们的代码

功能二: #define定义的符号和宏的替换

原代码:

image-20220119182958721

预编译后:

image-20220119183126194

image-20220119183309110

我们之前通过#define定义的均已被替换我们的#define也已经被处理不见.

功能三: 删除注释

直接将注释删除(偷个懒)

所以无论写多少注释都不会对程序运行产生影响

编译

通过指令gcc test.i -S

编译完成后会得到test.s文件

编译部分会在计算机专业一门叫做:《编译原理》的课上讲解如果大家感兴趣可以听一听在哪一节课上会讲

  • 语法分析
  • 词法分析
  • 语义分析
  • 符号汇编

符号汇总我会在汇编这一步提一嘴(毕竟汇编生成了符号表)

汇编

通过指令gcc test.s -c

将汇编指令转换成了二进制指令并形成符号表然后放在text.o(此文件为elf格式)文件内

文件内容:

image-20220119190111303

我们虽然肉眼看不懂二进制指令但是我们可以通过工具readelf来看此文件.

生成符号表

readelf-s就可以得到

image-20220119190905812

对比一下之前的代码

image-20220119192923078

不难发现我们的文件里有函数和全局变量

可是这个的作用是什么呢?

我们不妨将Add函数拆开到另一个源文件

image-20220120105327283

然后经过编译的全部过程就得到了这些

image-20220120110641826

这个时候我们就需要链接来继续后面的操作了

链接

我们知道链接的作用有

  • 符号表的合并和重定位
  • 合并段表

image-20220120111701708

将符号表重定位并合并之后就可以交给我们的运行环境来操作了.

运行环境

  1. 程序必须载入内存中。在有操作系统的环境中: 一般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。

  2. 程序的执行便开始。接着便调用main函数。

  3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程 一直保留他们的值。

  4. 终止程序。正常终止main函数;也有可能是意外终止。

对第3的小讲

image-20220120120804801

执行程序时就在栈区分配的main函数和Add函数的空间将临时变量放入栈区来后运行程序.

关于函数栈帧的建立和摧毁我会再出一篇博客继续聊.

结尾

今天还会出一篇预处理大家期待一下

标签:文件,符号表,汇编,环境,笔记,编译,详解,test,预处理
来源: https://blog.csdn.net/qq_61434711/article/details/122598859

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有