深入理解计算机系统_第一章_计算机系统漫游

深入,并且广泛
				-沉默犀牛

写在前面

今天是2018/12/14,还有一周我的实习期就结束了,发现自己的基础特别薄弱,选了几本提升基础的书籍,《深入理解计算机系统》是我将要看的第一本书,特别开这个系列文章,记录所学所得所想,也用作检验自己学习进度的指标之一。
PS:大部分是摘抄书中原话,[]方括号中的内容是自己所想所得。

计算机系统漫游

所有的计算机都有相似的硬件和软件结构,它们又执行着相似的功能。这本书就是为了那些希望深入了解这些组件如何工作以及这些组件是如何影响程序的正确性和性能的程序员而写的。

以下将以一个hello程序的生命周期来开始对系统的学习——从它被程序员创建开始,到在系统上运行,输出简单的消息,然后终止。我们将沿着这个生命周期,简要的介绍一些逐步出现的关键概念,专业术语和组成部分。

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

[以前从未考虑过类似于此的问题,大学时只是简单的编译一下看到输出结果就很开心了,现在来了解一下它的生命周期。]

信息就是位+上下文

hello程序的生命周期是从一个源程序(或者说源文件)开始的,即程序员通过编辑器创建并保存的文本文件,文件名是hello.c。源程序实际上就是一个由值0和1组成的位(又称为比特)序列,8个位被组织成一组,成为字节。每个字节表示程序中的某些文本字符。

所以hello程序是以字节序列的方式存储的文件中的。每个字节都有一个整数值,对应于某些字符。例如第一个字节的整数值为35,它对应的字符是"#",第二个字节的整数值为105,它对应的字符是"i"。像hello.c这样只由ASCII字符构成的文本称为文本文件,其他所有的文件都称为二进制文件

  • hello.c的表示方法说明了一个基本思想:系统中的所有信息——包括磁盘文件、内存中的程序、内存中存放的用户数据以及网络上传输的数据,都是用一串比特表示的。区分不同数据对象的唯一方法是我们读到这些数据对象时的上下文。比如,在不同的上下文中,一个同样的字节序列可能表示为一个整数,浮点数,字符串或者机器指令。

[看这些内容的时候,想到了一个生活中类比的事情(也与我最近在看哲学书籍有关):假设有外在存在的世界(位),这个世界在不同的人眼中看,反射出来的就是不一样的(这里暂不讨论阳明心学中的吾心光明,只讨论西方哲学思想),如果我相信世界是消极的,是无序的,是黑暗的(上下文),那么世界在我这里反射出来的就是消极的,无序的,黑暗的(信息),如果我相信世界是积极的,是有序的,是光明的(上下文),那么世界在我这里反射出来的就是积极的(信息)。]
[看当时自己这个类比还觉得蛮好的,哈哈哈 -2019/5/6]

程序被其他程序翻译成不同的格式

hello程序的生命周期是从一个高级C语言程序开始的(因为这种形式能够被人读懂)。然而,为了在系统上运行hello.c程序,每条C语句都必须被其他程序转化为一系列的低级机器语言指令。然后这些执行按照一种称为可执行目标程序的格式打好包,并且以二进制磁盘文件的形式存放起来,目标程序也称为可执行目标文件

GCC编译器驱动程序读取源文件hello.c,并把它翻译成一个可执行目标文件hello。翻译过程如下图:

在这里插入图片描述

  • 预处理阶段:预处理器(cpp)根据以字符#开头!的命令,修改原始的C程序。比如hello.c中的第一行 #include <stdio.h> 命令告诉预处理器读取系统头文件stdio.h的内容,并把它直接插入程序文本中。结果得到了另一个C程序,通常以.i作为文件扩展名。
  • 编译阶段:编译器(ccl)将文本文件hello.i翻译成文本文件hello.s,它包含一个汇编语言程序
  • 汇编阶段:汇编器(as)将hello.s翻译成机器指令语言,把这些指令打包为一种叫做可重定位目标程序(relocatable object program)的格式,并将结果保存在目标文件hello.o中。
  • 链接阶段:hello程序调用的printf函数,printf函数存在一个名为printf.o的单独的预编译好了的目标文件中,而这个文件必须以某种方式合并到我们的hello.o程序中。链接器(ld)就负责处理这种合并。结果就得到了hello文件,它是一个可执行目标文件(或可执行文件),可以被加载到内存中,由系统执行。

了解编译系统如何工作是大有益处的

有一些重要的原因促使程序员必须知道编译系统是如何工作的:

  • 优化程序性能。比如,一个switch语句是否总是比一些列的if-else语句高效得多?一个函数调用的开销有多大?while循环比for循环更有效吗?指针引用比数据索引更有效吗?为什么循环求和的结果放到一个本地变量中,会比将其放到一个通过引用传递过来的参数中,运行起来快很多呢?为什么只是简单地重新排列一下算术表达式中括号就能让函数运行的更快呢?
  • 理解链接时出现的错误。比如,链接器报告说它无法解析一个引用,这是什么意思?静态变量和全局变量的区别是什么?如果你在不同的C文件中定义了名字相同的两个全局变量会发生什么?静态库和动态库的区别是什么?我们在命令行上排列库的顺序有什么影响?最严重的是,为什么有些链接错误直到运行时才会出现?
  • 避免安全漏洞。缓冲区溢出错误是造成大多数网络和Internet服务器上安全漏洞的主要原因。存在这些错误的因为很少有程序员能够理解需要限制从不受信任的源接受数据的数量和格式。

处理器读出并解释存储在内存中的指令

此刻,hello.c源程序已经被编译系统翻译成了可执行目标文件hello,并被存放在磁盘中。想要在Unix系统上运行该可执行文件,我们将它的文件名输入到称为shell的应用程序中即可。

shell是一个命令行解释器,它输出一个提示符,等待输入一个命令行,然后执行这个命令。如果该命令行的第一个单词不是一个内置的shell命令,那么shell就会假设这是一个可执行文件的名字,它将加载并运行这个文件。

系统的硬件组成

这张图是Intel系统产品族的模型,但是所有其他系统也有相同的外观和特性。
在这里插入图片描述

  1. 总线。贯穿整个系统的一组电子管道,称为总线,它携带信息字节并负责在各个部件间传递。通常总线被设计成传送定长的字节快,也就是字(Word)。字中的字节数(即字长)是一个基本的系统参数,各个系统中都不尽相同。现在大多数机器字长要么是4个字节(32位),要么是8个字节(64位)。

  2. I/O设备。I/O设备是系统与外部世界的联系通道。上图中的示例系统包括四个I/O设备:作为用户输入的键盘和鼠标,作为用户输出的显示器,用于长期存储数据和程序的磁盘驱动器(简单的说就是磁盘)。最开始&

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值