《程序员的自我修养——链接,装载与库》读后总结

第一章 温故而知新

1.1 从Hello World说起

一开始从打印一个“hello world”这个程序说起,不仅仅停留在表面,给我提出了一个疑问?打印出 “hello world”是如何实现的,提出了一系列的问题,这部分问题的大部分答案,我也不清楚,这里留下了一个悬念,问题放到了下面。
在这里插入图片描述

1.2 万变不离其宗

这一部分将抽象的计算机概念,进行了具体化,一个计算机的组成最重要的三个部件,中央处理器CPU,内存和I/O控制芯片。为了协调CPU,内存和高速的图形设备,人们想到了一系列的方法,设计南桥和北桥,然后技术越来越先进,在2004年,cpu的频率从那时再也没有发生质的提高,原因是人类在cpu的工艺达到物理极限,然后人类通过增加cpu的数量来提高效率,然后就有了多核处理器。

在这里插入图片描述

1.3 站的高,望的远

本段介绍了系统软件的体系结构,如下图:
在这里插入图片描述

每个层次之间都需要通信,既然需要通信就必须有一个通信的协议,我们将其称位 “接口”,接口的下面那层是接口的提供者,每个中间层都是对其下层的包装和扩展。从整个层次结构上看,开发工具与应用工具属于同一个层次,他们都使用操作系统应用程序编程接口。应用程序接口的提供者是运行库,运行库是对系统调用接口的包装和扩展。系统调用是在操作系统内核实现的,系统调用接口的实现往往以软中断的方式提供。操作系统内核层,是对硬件接口的使用者,而硬件是接口的定义者。
这里提供两个图来更好的理解:
在这里插入图片描述
在这里插入图片描述

1.4 操作系统做什么

提供抽象的接口,管理硬件资源

1.4.1 不要让cpu打盹

开启多道设计程序,分时系统,cpu分配方式,抢占式,让cpu尽最大可能的去忙碌。

1.4.2 设备驱动

通过操作系统中的硬件驱动程序,去完成硬件的驱动,例如文件的读取,通过硬件驱动程序,读取磁盘上的数据,将数据读取到,事先设置好的内存地址中。

1.5 内存不够怎么办

这一段其实主要讲的是虚拟内存,由于主存的存储空间不足,通过辅存,从逻辑上扩展内存,这个是一个虚拟的概念,对我们程序员来说,我们看到的内存是虚拟的,当我们访问到的虚拟地址不存在于主存中时,cpu会陷入缺页中断,通过交换,分页和调度,会将磁盘中的一页调入内存,或者当主存被占满时,通过调度机制,将不常用的一页调出主存,写入磁盘,将我们需要的一页调入主存,然后给我们一个假象,我们拥有很大的内存,并通过虚拟内存可以实现进程的虚拟地址空间的隔离。

1.6 众人拾柴火焰高

这一段主要讲线程,然后阐述了线程与进程的关系:
在这里插入图片描述
然后线程的优点,访问权限,线程之间共享进程中的全局变量,堆上数据,函数里的静态变量,程序代码,任何线程都有权利执行读取进程中的任何代码,打开文件,A线程打开文件,B线程对文件进行读写。线程私有,局部变量,函数参数,线程局部数据。

线程的执行状态:等待,就绪,运行
还有三态转换:
在这里插入图片描述
线程调度,每个线程都被分配了一定的时间片和优先级,线程优先级改变的方法:
用户指定优先级,根据进入等待状态的频繁程度来提高或降低优先级。长时间得不到执行而被提升优先级。

1.6.2 线程安全

主要讲述了线程安全的一些措施,利用锁,读写锁,信号量,条件变量,原子操作。但是我觉比较新奇的是,过度优化那里,编译器过度优化会改变指令顺序,cpu会改变指令的顺序,在多线程下会造成数据不一致的问题,但是许多体系结构的cpu会提供barrier指令,防止线程不安全。还有就是内核线程和用户线程的对应关系,现在基本采用多对多的关系,好处是,用户现程数量可以多个,用户线程中一个阻塞一般不会影响其他用户线程。

第二部分编译和链接

2.1 被隐藏了的过程

一个简单的hello.c 程序如下:

#include<stdio.h>
int main(){
printf("hello world!");
return 0;
}

在Linux下当我们使用 gcc hello.c -o hello 时,会一气呵成的生成一个hello 可执行文件
./hello 就可以输出 “hello world!”,事实上上述过程可以分为四个步骤,预处理,编译,汇编,链接,如下图所示:
在这里插入图片描述

2.1.1 预编译

预编译的过程就是对一些#进行一些处理,处理步规则如下:
在这里插入图片描述

2.1.2 编译

编译部分其实就是将预处理后的代码变成汇编代码,这里涉及语义分析,词法分析,语法分析及优化后的汇编代码,这个过程很复杂。

2.1.3 汇编

这部分就是将汇编代码,变成机器可以执行的机器码。

2.1.4 链接

链接通常是一个比较让人费解的过程。文章里提供了一系列问题。
在这里插入图片描述
链接就是把一大堆文件链接成一个可执行文件。

2.2 编译器做了什么

编译器就是将高级语言翻译成机器语言的一个工具。
编译的过程一般分为六部:扫描,语法分析,语义分析,源代码优化,代码生成和目标代码优化。
在这里插入图片描述

2.2.1 词法分析

源代码程序被输入到扫描器,扫描器的任务很简单,他只是简单的进行词法分析,运用类似于有限状态机的算法,将字符串序列分割成一系列记号。例如这个程序:
在这里插入图片描述
他被分割后,如下图所示,字符串被分割成一些列的记号,记号有自己的类型:
在这里插入图片描述
词法分析产生的记号一般可以分为如下几类:关键词,标识符,字面量和特殊字符。
在这里插入图片描述
扫描器做了以上的工作。有一个叫lex的程序可以实现词法扫描,他会按照用户之前描述好的词法规则对字符串分割成一个个记号。因为这样一个程序的存在,程序开发者就无须为每一个编译器开发一个独立的词法扫描器,而是根据需要改变词法规则就可以了。

2.2.2 语法分析

接下来语法分析器将对扫描器产生的记号进行语法分析,从而产生语法分析树,整个分析过程采用上下文无关语法的分析手段
在这里插入图片描述
由于我根本不懂上下文无关语法,所以我决定去看看。
在这里插入图片描述
看完定义,说实话没看懂,等会去可靠他说的例子,我们先看看它上面的哪些东西是如何定义的。
在这里插入图片描述
这些东西这里还是不做深入理解了,毕竟我也不懂,也不是一时半会能学会的,都怪我编译原理没好好学,想要深入去学编译原理吧,这里浅尝辄止即可。简单的讲由语法分析器产生的语法分析树就是以表达式为节点的树。类似于表达式求值那道算法题,不知道你们写过没有,解法有用栈来写,还有用语法分析树来写。下图是上图表达式的语法分析树:
在这里插入图片描述
在这里插入图片描述
正如前面词法分析有lex一样,语法分析也有一个现成的工具叫做yacc。他像lex一样可以根据用户给定的语法规则,对输入的记号序进行解析,从而构建出一颗语法树。对于不同的编译语言,编译器开发者只需改变语法规则即可,无需为每一个编译器写一个语法分析器。

2.2.3 语义分析

在这里插入图片描述
语法分析仅是完成表达式方面的分析,但是她并不了解这个语句是否有真正的意义。检查合法性
在这里插入图片描述
比如这个,我让一个野指针去和b相乘,a和b不是同一个类型,这样在语法上面是没有任何问题的,但是语义上面却是不被允许的。
在这里插入图片描述
在这里插入图片描述
通过上图的话,应该可以理解,语义分析的重要性。
在这里插入图片描述
被标识了类型的语法树,经过语义分析的语法树成为上图的样子。

中间层语言生产

现代编译器有着很多成优化,有些代码写的实在累赘,所以编译器需要把他优化。
在这里插入图片描述
优化后,就会变成另一个模样的语法树:
在这里插入图片描述

2.2.5 目标代码生产与优化

在这里插入图片描述
这里讲了下如何生成目标代码要有代码生成器和目标代码优化器,让我们得到的最终代码是最优的形式。
在这里插入图片描述
这句话很有趣,其实他的意思就是多文件编写,比如我昨天做的那个手动链接那个小实验,两个代码不在同一个文件,当我们在一个文件里面使用了另一个文件的函数,然后需要重定位,各种各种的东西,链接器可以帮我们做了,可以看我的那篇博客,写的很清晰:使用裸ld手动链接c程序

2.3 链接器年龄比编译器长

这部分前面讲了链接器的历史,然后讲了一下程序并不是一写好就是一直不变的。
在这里插入图片描述
解释了什么是重定位。
在这里插入图片描述

2.4 模块拼装——静态链接

写一个数百万行的代码在一个文件里,是十分难以维护的,所以出现量模块化,将一个大项目,分割成很小的模块,每个模块独立编译,然后按照要求将他们组装起来,就成了一个大的模块,这个过程称位链接。
在这里插入图片描述
这句话清楚的解释了链接的含义。
在这里插入图片描述
阐述静态链接和动态链接在细节上的命名规范。
在这里插入图片描述
上图这个过程,在预编译阶段将头文件个复制一份插入源代码,经历编译汇编生成可重定位的目标代码,再连接阶段,将运行库里的目标代码链接进来,最终成为一个可执行文件。
在这里插入图片描述
运行时库,就是对系统调用的进一步分装。
在这里插入图片描述
这断话举了一个很好的例子,看完他,会有一个自己的理解。

2.5 本章小结

在这里插入图片描述

第三章 目标文件里有什么

在这里插入图片描述

3.1 目标文件的格式

Windows下的可执行文件格式为PE,和Linux的ELF,他们都是COFF格式的变种。目标文件就是源代码编译后 但未进行链接的那些中间文件(Window下的.obj和Linux下的.o)他跟可执行文件的内容与结构很相似,所以一般跟可执行文件的格式一起采用一种格式存储。动态链接库和静态链接库都按照可执行文件格式进行存储。
在这里插入图片描述
在这里插入图片描述

3.2目标文件是什么样的

目标文件的内容至少有编译后的机器指令代码,数据。没错除了这些信息,还包括链接时所必要的信息,字符串符号表等。
在这里插入图片描述
在这里插入图片描述
上图的File Header文件描述了文件的很多信息,包括段表,文件是否可执行是静态链接还是动态链接等信息。
在这里插入图片描述
接下来讲了c语言编译后的执行语句都保存在.text段;初始化的全局变量和局部静态变量都保存在.data段,而未初始化的全局变量和静态局部变量保存至.bss段,运行时这一段确实占用内存空间,但是.bss段在文件中并不占据空间,只是为未初始化的全局变量和静态变量预留位置而已。
在这里插入图片描述
为什么要把程序的指令和数据分开存放,这样有什么优势?
下面是解释:
在这里插入图片描述

在这里插入图片描述

3.3 挖掘SimpleSection.o

以下面这个代码为例来讲解:
在这里插入图片描述
在这里插入图片描述
我们使用gcc去编译这个代码:
gcc -c SimpleSection.c
然后我们查看这个文件的内部结构
在这里插入图片描述

结构图如下:
在这里插入图片描述
然后接下来说SimpleSection.o段的数量比我们想象的要多,接下来将段的种类:
在这里插入图片描述
在这里插入图片描述
有一个专门的命令叫做size他可以用来查看ELF文件的代码段,数据段和BSS段的长度。
在这里插入图片描述

3.3.1 代码段

将.o文件以16进制的形式输出,.text段最左边是偏移量。
在这里插入图片描述
在这里插入图片描述

3.3.2 数据段和只读数据段

只读数据段的好处:
在这里插入图片描述

3.3.3 BSS段

讲bss段的内容
在这里插入图片描述
Quiz 变量存放的位置
现在来做个小实验
static int x1=0;
static int x2=1;
x1,x2会被存放在什么段中呢?
答案:x1会被存放在.bss段,x2会被存放在.data段,原因:bss段的数据默认为0,而x1=0,所以被优化掉了,放到bss段,节省磁盘空间。

3.3.4 其他段

除了.text,.data,.bss这三个最常用的段之外,ELF文件也有可能包含其他段,用来保存与程序相关的其他信息。表3-2中列举了ELF的一些常见段。
在这里插入图片描述

插入的段名不能和不能使用”.“作为前缀,否则容易根系统保留的段名起冲突。
在这里插入图片描述
在代码中使用图片,音频,等其他东西作为目标文件,将其制成一个段,该怎么做?
在这里插入图片描述
从上面,我觉得通过代码,操作文件可能就是把文件制程一个二进制的.obj,链接进来进行操作。

自定义段
通过__attribute__((section())) 变量 可以将 变量放到我们指定的段中。
在这里插入图片描述

3.4 ELF文件结构描述

在这里插入图片描述

3.4.1 文件头

在这里插入图片描述
在这里插入图片描述
魔术的作用:
在这里插入图片描述
可以去搜一下elf文件中魔术的由来

3.4.2 段表

在这里插入图片描述

段表是一个结构体Elf32_Shdr结构体数组,数组元素等于段的个数。
在这里插入图片描述
结构体的结构,感兴趣的可以自行去查。

3.4.3 重定位表

在这里插入图片描述

3.4.4 字符串表

在ELF文件头就可以得到字符串表和段表的位置,从而解析整个ELF文件。

3.5 链接的接口——符号

链接过程的本质就是要把多个不同的目标文件之间互相黏在一起。
在这里插入图片描述
在这里插入图片描述

3.5.2 特殊符号

在这里插入图片描述

3.5.3 符号修饰与签名

防止函数重名!
在这里插入图片描述

C++修饰符
这里主要讲c++对函数的修饰,函数签名的一些规则

3.5.4 extern “C”

讲C++兼容C
在这里插入图片描述
在这里插入图片描述
为什么C++兼容C?
在这里插入图片描述

3.5.3 强符号与若符号

主要讲了强符合与若符号的区别。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值