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


    第二章

    程序源代码to最终可执行文件

    image-20211024210206235

    预编译:在c语言中,预编译就是处理那些源代码中以“#”开始的预编译命令,如“#include”、“#define”;并删除所有注释;添加行号和文件名标识;展开所有宏定义。.c->.i

    编译:对程序进行一系列词法分析、语法分析、语义分析及优化,生成对应的汇编代码文件。.i->.s

    汇编:根据汇编指令和机器指令的对照表一一翻译。.s->.o

    链接:将一堆文件链接成一个可执行文件。.o->.s

    程序的编译

    词法分析:通过扫描器(类似于有限状态机[1])将代码的字符序列分割成一系列的记号。如sum=3+2; 可以表计划得到以下内容

    语素 标记类型
    sum 标识符
    = 赋值操作符
    3 数字
    + 加法操作符
    2 数字
    ; 语句结束

    语法分析:采用上下文无关语法[2]进行分析生成语法树。

    语义分析:分析的是静态语义[3],给语法树标识类型。

    中间语言生成:将语法树转换成中间代码。常见有:三地址码、P-代码。

    目标代码生成与优化:将中间代码转换成目标机器代码,并对目标代码进行优化,如:选择合适的寻址方式、使用位移代替乘法运算、删除多余指令等。

    第三章

    各种目标文件的格式

    ELF文件的段结构

    一个程序本质上都是由BSS段data段text段三个组成。

    data段:代码段,用来存放已初始化的全局静态变量和局部静态变量

    BSS段Block Start by Symbol,未初始化数据区,通常是指用来存放程序中未初始化的全局变量和局部静态变量的一块内存区域。从逻辑角度出发,这里的内容也可以放到数据段中,但是因为没有初始化,默认是0,因此没有必要在数据段占用空间,BSS 段实际上至少为未初始化的全局变量预留位置而已。BSS 段和代码段都属于静态内存分配[4]

    代码段:存放程序执行代码(编译后的机器码)的一块内存区域。这部分区域大小在程序运行前就已经确定,并且内存区域只读。代码断种也可能有一些只读常量。

    程序分段的好处:

    1. 防止程序指令被有意或无意的篡改;
    2. 提高程序的局部性,提高缓存命中率;
    3. 共享指令。

    小结

    无论是可执行文件、目标文件或库,他们实际上都是一样基于段的文件或是这种文件的集合。程序的源代码经过编译以后,按照代码和数据分别存放到相应的段中,编译器(汇编器)还会将一些辅助性的信息,诸如符号、重定位信息等也按照表的方式存放到目标文件中,而通常情况下,一个表往往就是一个段。

    第四章

    链接器如何合并各个段到输出文件

    1. 空间与地址分配

      获得各个段的长度、属性和位置,并整合符号表中的符号定义和符号引用。根据段的长度计算出段合并后的位置和长度。

      image-20211024210802260

    2. 符号解析和重定位

      重定位

      编译器对于一些不明确的地址,会暂时使用假地址代替,链接器会根据重定位表来修正地址。如.text 段中有要被重定向的地方,重定位表会被保存在.rel.text 中。

      符号解析

      链接器对某个符号的引用进行重定位时,需要确定这个符号的目标地址。这时候就需要查找有所有输入目标文件的符号表组成的全局符号表。

    common 块

    common块即当需要的空间不一致时,以大的为准。是为了允许不同类型的弱符号[5]存在。因为链接器不支持符号类型,无法判断各个符号的类型是否一致。

    第五章

    PE/COFF

    和ELF 文件非常相似,基于段结构的二进制文件格式。

    PE 是COFF 文件格式的改进版本,增加了PE 文件头、数据目录等一些结构

    最主要的变化有两个:第一个是文件最开始的部分不是COFF文件头,而是DOS MZ 可执行文件格式的文件头和桩代码(DOS MZ File Header and Stub);第二个变化是原来的COFF文件头中的“IMAGE_FILE_HEADER”部分扩展成了PE文件文件头结构,这个结构包括了原来的“Image Header”及新增的PE扩展头部结构(PE Optional Header)

    第一个变化是为了兼容DOS 系统。第二个变化是 支持PE文件的装在与运行关系。



    1. 有限状态机:因为满足了某个“事件”,触发了一个“动作”,由“状态A”变成了“状态B”。 ↩︎

    2. 上下文无关文法:所有产生式的左边只有一个非终结符。如S -> aSb; S -> ab↩︎

    3. 静态语义:通常包括声明和类型的匹配,类型的转换。动态语义:在运行期间出现的语义相关的问题。 ↩︎

    4. 静态内存分配:在程序开始编译时完成,不占用CPU资源;在栈上分配;内存块大小固定。动态内存分配:在程序运行中分配;需要指针和引用数据类型;在堆上分配;内存按需分配。 ↩︎

    5. 强符号&弱符号:函数和初始化的全局变量(包括显式初始化为0)时强符号;未初始化的全局变量时弱符号。强符号不允许多次定义,但强弱可以共存;强弱共存时,强覆盖弱;都是弱符号时,选择占用空间最大的 ↩︎

  • 相关阅读:
    Hibernate的查询方式汇总
    JdbcTemplate详解
    spring读取数据库的配置信息(url、username、password)时的<bean>PropertyPlaceholderConfigurer的用法
    spring aop方式配置事务中的三个概念 pointcut advice advisor
    spring mvc静态资源请求和<mvc:annotation-driven>
    spring aop实现原理
    Spring 配置 事务的几种方式
    转!!常用的4种动态网页技术—CGI、ASP、JSP、PHP
    转! java 中“==” 与“ .equals ”比较
    mysql 批处理文件--- 创建 用户 以及 导入数据
  • 原文地址:https://www.cnblogs.com/weirwei/p/15455709.html
Copyright © 2020-2023  润新知