美文网首页
《程序员的自我修养》第二部分

《程序员的自我修养》第二部分

作者: 绍清_shao | 来源:发表于2019-12-05 19:26 被阅读0次

    第2章 编译和链接

    流行的IDE把编译和链接合并到一起,这个过程叫构建(Build)
    IDE会提供默认配置,隐藏大量细节,导致我们遇到在运行时种种性能瓶颈会束手无策

    用gcc hello.c编译hello文件时会发生这些事:
    预处理(Prepressing)、编译(Compilation)、汇编(Assembly)、链接(Linking)

    预编译过程简单
    源文件.c和相关头文件stdio.h等被预编译成cpp。
    预编译过程:
    1.预编译指 #include #define… 2.删除注释 3.添加行号、文件名标识 4.保留#pragme编译器指令

    编译过程复杂,需要优化
    词法分析、语法分析、语义分析及优化。之后生产相应的汇编代码.s文件

    ** 汇编**过程简单,直接翻译
    输入.s 翻译成 .o机器可执行指令文件
    汇编代码变成机器可执行的指令,每条汇编语句几乎都对应一条机器指令。

    链接过程费解
    输入需要链接的.o文件,链接后输出 .out文件可执行文件

    编译过程
    一般分6步:扫描、语法分析、语义分析、源代码优化、代码生成和目标代码优化

    1.词法分析:
    输入:扫描源代码,
    再处理:用lex程序,按照用户之前描述好的词法规则将输入的字符串分割成一个个记号。
    2.语法分析:只做语法分析,并不了解这个语句是否真正有意义。
    输入:记号进行语法分析
    输出:语法树
    过程:词法分线器 生成语法树(以表达式为节点的树)。
    array[index] = (index + 4) * (2 + 6)
    符号、数字是最小表达式,不由其他表达式组成,通常作为语法树叶节点。
    很多运算符号优先级,符号不同含义进行语法分析

    工具:yacc可以根据给定的语法规则对输入的记号序列进行解析,构建语法树。所以只要改变语法规则,就能进行解析。跟lex词法分析器一样。只对表达式的语法层面分析,并不了解语句本身是否有意义。比如C语言两个指针做乘法运算是没有意义,在语法分析是合法。
    3.语义分析:
    两个相关概念:静态语义、动态语义
    静态语义指编译期可以确定的语义。
    动态语义指运行期才能确定的语义,比如0作为除数。
    语义分析:只能分析静态语义中出现的错误,包括声明、类型的匹配、类型转换等。
    4.中间语言生成 (编译器前端)
    输入:语法树
    输出:中间代码,不同编译器中间店面有很多种类。
    编译器前端:负责产生机器无关代码
    编译器后端将中间代码转换成目标机器代码。这个属于5的范畴
    前端后端分开的好处:针对不同平台使用同一个前端,不同机器平台对应不同后端
    5.目标代码生成与优化 (编译器后端)
    编译器后端包括:生成器、目标代码优化器
    生成器:输入:中间代码 输出:目标机器代码。这个过程依赖目标机器,字长不同。

    如上图:右边是中间代码,经过生成器处理,变成左边目标机器码。
    最后目标代码优化器对目标机器码进行优化。

    链接器
    产生的背景:
    最开始是在一个文件内写所以代码,对文件修改后还要对各个目标的地址重新计算(重定向)。
    从打卡纸带的程序到发明汇编语言。修改程序后,汇编器会重新计算“foo”目标地址。
    汇编语言和汇编器解决了低级的繁琐的调整地址的工作,产生了符号这个概念。关于符号,它用来表示一个地址,这个地址可能是一段子程序(huo)的起始地址或者变量的起始地址。
    按功能和性质划分代码,形成功能模块,模块按照层次结构或其他结构组织。
    每个模块互相依赖又相对独立,可单独开发、编译、测试,改变部分代码不需要编译整个程序。
    模块间通信有两种方式:一是模块间函数调用,二是模块间变量访问。两种方式可归结为一种方式,模块间符号的引用

    模块拼接—静态链接
    链接过程主要包括:地址和空间分配、符号决议和重定位。

    第3章 目标文件里有什么

    相关文章

      网友评论

          本文标题:《程序员的自我修养》第二部分

          本文链接:https://www.haomeiwen.com/subject/klsjgctx.html