CSAPP-深入理解计算机系统-task01计算机系统漫游
Posted 夜灬凄美
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CSAPP-深入理解计算机系统-task01计算机系统漫游相关的知识,希望对你有一定的参考价值。
计算机系统漫游(上)
1.hello world程序的创建-运行-退出的流程
hello world程序从编写到最终执行结束需要经过下面这4个步骤:
-创建/create
-编译/compile
-运行/run
-退出/exit
创建的代码如下,保存为hello.c的文件:
#include<stdio.h>
int main(void)
printf("hello, world");
return 0;
编译部分:通过gcc -o hello hello.c命令完成对源代码的编译,生成可执行程序hello
运行部分:在shell命令行终端中输如 ./hello,就可以执行程序
2.编译部分具体内容
通过gcc -o hello hello.c命令完成对源代码的编译,生成可执行程序hello,这个过程中编译系统的处理大致可以分为四个阶段,分别为:预处理、编译、汇编以及链接。
2.1预处理
预处理器会在以#开头的代码处进行修改,例如hello程序中引入了头文件 stdio.h ,预处理器会读取该头文件中的内容,将其中的内容直接插入到源程序中,结果就得到了另外一个 C 程序,这个经过预处理器处理后得到的文件通常以 .i 结尾. hello.c 经过预处理器后得到 hello.i,这个 hello.i 仍旧是一个文本文件。
2.2编译
编译器将hello.i文件翻译成hello.s文件。这一阶段包括词法分析、语法分析、语义分析、中间代码生成以及优化等等一系列的中间操作。感兴趣的可以了解一下《编译原理》。
2.3汇编
汇编器根据指令集将汇编程序 hello.s 翻译成机器指令,并且把这一系列的机器指令按照固定的规则进行打包,得到可重定位目标文件 hello.o 。此时 hello.o 虽然是一个二进制的文件,但是还不能执行。
2.4链接
在 hello.c 这个程序中,我们调用了printf 函数,printf 函数在是在名为 printf.o 的文件中,这个文件是一个提前编译好的目标文件,链接器(ld)负责把 hello.o 和 printf.o 进行合并。因为链接器要遵循一定规则对 hello.o 和 printf.o 的进行调整,所以 hello.o 才会被称之为可重定位目标文件。最终,hello.o经过链接阶段可以得到可执行目标文件 hello。此时,得到的 hello 就可以被加载到内存中执行了。
2.系统的硬件组成
2.1CPU
中央处理单元(Central Processing Unit , CPU) ,也称处理器,包含 PC ( 程序计数器:Program Count ) 、寄存器堆(Register file) 、ALU(算数/逻辑计算单元:Arithmatic/logic Unit)三个部分.
- 程序计数器 PC:是一个 4 字节或是 8 字节的存储空间,里面存放的是某一条指令的地址。从系统上电的那一瞬间,直到系统断电,处理器就不断地在执行PC 指向的指令,然后更新 PC,使其指向下一条要执行的指令(注意:这个下一条指令与刚刚执行的指令不一定是相邻的)
- 寄存器:可以理解为一个临时存放数据的空间。例如计算两个变量 a+b 的和,处理器从内存中读取 a 的值暂存在寄存器 X 中,读取 B 的值暂存在寄存器 Y中,这个操作会覆盖寄存器中原来的数值,处理器完成加载的操作后,ALU(Arithmatic/logic Unit)会从复制寄存器 X 和 Y 中保存的数值,然后进行算术运算,得到的结果会保存到寄存器 X 或者寄存器 Y 中,此时寄存器中原来的数值会被新的数值覆盖。
- 算数/逻辑计算单元 ALU:计算速度极快,且专攻算数与逻辑的计算,计算机核心部分。
2.2主存(内存)
主存(Main Memory) ,也称为内存、运行内存,处理器在执行程序时,内存主要存放程序指令以及数据。从物理上讲,内存是由随机动态存储器芯片组成;从逻辑上讲,内存可以看成一个从零开始的大数组,每个字节都有相应地址.
2.3总线
内存和处理器之间通过总线来进行数据传递。实际上,总线贯穿了整个计算机系统,它负责将信息从一个部件传递到另外一个部件。通常总线被设计成传送固定长度的字节块,也就是字(word) ,至于这个字到底是多少个字节,各个系统中是不一样的,32 位的机器,一个字长是 4 个字节;而 64 位的机器,一个字长是 8 个字节.
2.4输入输出设备(I/O)
除了处理器,内存以及总线,计算机系统还包含了各种输入输出设备,例如键盘、鼠标、显示器以及磁盘等等。每一个输入输出设备都通过一个控制器或者适配器与IO 总线相连.
区别:控制器与适配器主要区别是在于它们的封装方式,无论是控制器还是适配器,它们的功能都是在 IO 设备与 IO 总线之间传递数据.
3.程序执行
3.1操作过程
hello.c 经过编译系统得到可执行目标文件 hello,此时可执行目标文件 hello 已经存放在系统的磁盘上,那么,如何运行这个可执行文件呢?
在 linux 系统上运行可执行程序:打开一个 shell 程序,然后在 shell 中输入相应可执行程序的文件名:
linux>./hello
shell 是什么?
shell 是一个命令解释程序,如果命令行的第一个单词不是内置的 shell 命令,shell就会对这个文件进行加载并运行. 此处,shell 加载并且运行 hello 程序,屏幕上显示hello,world 内容,hello 程序运行结束并退出,shell 继续等待下一个命令的输入.
3.2程序执行流程
(1)首先我们通过键盘输入” ./hello” 的字符串,shell 程序会将输入的字符逐一读入寄存器,处理器会把 hello 这个字符串放入内存中。
(2)当我们完成输入,按下回车键时,shell 程序就知道我们已经完成了命令的输入,然后执行一系列的指令来来加载可执行文件 hello。
(3)这些指令将 hello 中的数据和代码从磁盘复制到内存。数据就是我们要显示输出的”hello , world\\n” ,这个复制的过程将利用 DMA(Direct Memory Access)技术,数据可以不经过处理器,从磁盘直接到达内存。
(4)当可执行文件 hello 中的代码和数据被加载到内存中,处理器就开始执行 main函数中的代码,main 函数非常简单,只有一个打印功能。
4.设备容量
通常情况下,大容量的存储设备的存取速度要比小容量的慢,运行速度更快的设备的价格相对于低速设备要更贵。例如:在一个系统上,磁盘的容量一般为 TB 级,内存的容量一般为 GB 级,磁盘的容量大概是内存的 1000 倍。
4.1高速缓存(Cache)
对于处理器而言,从磁盘上读取一个字所花费的时间开销比从内存中读取的开销大1000 万倍。寄存器文件的只能存储几百个字节的信息,而内存的可以存放几十亿的字节信息(GB 级) ,从寄存器文件读取数据比从内存读取差不多要快 100 倍。
随着半导体技术的发展,处理器与内存之间的差距还在持续增大,针对处理器和内
存之间的差异,系统设计人员在寄存器文件和内存之间引入了高速缓存(cache) ,比较新的,处理能力比较强的处理器,一般有三级高速缓存,分别为 L1 cache ,L2cache 以及 L3 cache。
L1 cache 的访问速度与访问寄存器文件几乎一样快,容量大小为数万字节(KB 级别) ;L2 cache 的访问速度是 L1 cache 的五分之一,容量大小为数十万到数百万字节之间;L3 cache 的容量更大,同样访问速度与 L2 cache 相比也更慢。
4.2存储设备的层次结构
整个计算机系统的信息存储可以用一个层次结构来表示,通常而言,存储容量越小,速度越快,价格越高,上一层存储设备是下一层存储设备的高速缓存.
计算机系统漫游(下)
1.操作系统的作用
无论是 shell 程序还是 hello 程序都没有直接访问键盘、显示器、磁盘这些硬件设备,真正操挫硬件的是操作系统,我们可以把操作系统看成是应用程序和硬件之间的中间层,所有的应用程序对硬件的操作必须通过操作系统来完成。
这样设计的目的主要有两个:
1 防止硬件被失控的应用程序滥用;
2 操作系统提供统一的机制来控制这些复杂的底层硬件.
为了实现上述的功能,操作系统引入了几个抽象的概念。例如:文件是对 IO 设备的抽象;虚拟内存是对内存和磁盘 IO 的抽象;进程是对处理器、内存以及 IO 设备的抽象。
2.进程
假设示例场景中只有两个并发的进程:shell 进程和 hello 进程
1 最开始的时候,只有 shell 进程在运行,即 shell 在等待命合行的输入。
2 当我们通过 shell 进程加载 hello 进程时,shell 进程通过系统调用来执行我们的请求,系统调用会将控制权从 shell 进程传递给操作系统,操作系统保存 shell进程的上下文,然后创建一个新的 hello 进程及其上下文,然后将控制权转交给新的 hello 进程。
3 hello 进程执行完之后,操作系统就会恢复 shell 进程的上下文,并将控制权交给 shell 进程,之后 shell 进程继续等待下一个命令的输入。
4 操作系统会跟踪进程运行所需要的所有状态信息,这种状态,称为上下文(Context) 。例如当前 PC 和寄存器的值,以及内存中的内容等等。
3.虚拟内存
操作系统为每个进程提供了一个假象,就是每个进程都在独自占用整个内存空间,每个进程看到的内存都是一样的,我们称之为虚拟地址空间
1.第一个区域是用来存放程序的代码和数据的,这个区域的内容是从可执行目标文件中加载而来的,例如我们多次提到的 hello 程序。对所有的进程来讲,代码是从固定的地址开始。至于这个读写数据区域放的是什么数据呢?例如在 C语言中,全局变量就是存放在这个区域.
2.顺着地址增大的方向,继续往上看就是堆(heap) ,学过 C 语言的同学应该用过malloc 函数,程序中 malloc 所申请的内存空间就在这个堆中。程序的代码和数据区在程序一开始的时候就被指定了大小,但是堆可以在运行时动态的扩展和收缩.
3.接下来,就是共享库的存放区域。这个区域主要存放像 C 语言的标准库和数学库这种共享库的代码和数据,例如 hello 程序中的 printf 函数就是存放在这里.
4.继续往上看,这个区域称为用户栈(user stack) ,我们在写程序的时候都使用过函数调用,实际上函数调用的本质就是压栈。这句话的意思是:每一次当程序进行函数调用的时候,栈就会增长,函数执行完毕返回时,栈就会收缩。需要注意的是栈的增长方向是从高地址到低地址.
5.最后,我们看一下地址空间的最顶部的区域,这个区域是为内核保留的区域,应用程序代码不能读写这个区域的数据,也不能直接调用内核中定义的函数,也就是说,这个区域对应用程序是不可见的.
4.文件
Linux 系统的哲学思想是:一切皆为文件。
所有的 IO 设备,包括键盘,磁盘,显示器,甚至网络,这些都可以看成文件,系统中所有的输入和输出都可以通过读写文件来完成.
虽然文件的概念非常简单,但却非常强大。例如︰当程序员需要处理读写磁盘上的文件时,他们不需要了解具体的磁盘技术,同一个程序,可以在不同磁盘技术上的不同系统上运行.
5.系统之间利用网络通信
随着互联网的发展,从一台计算机发送消息到另外一台计算机已经成为非常普遍的应用。 《深入理解计算机系统》中讲述了如何使用本地计算机上的 telnet 客户端连接远程主机上的 telnet 服务器。
由于 telnet 的安全性问题,目前 ssh 的连接方式的更加普遍。当我们在 ssh 的客户端中输入 hello 字符串并且敲下回车之后,客户端的软件就会通过网络将字符串发送到 ssh 服务端,ssh 服务端从网络端接收到这个字符串以后,会将这个字符串传递给远程主机上的 shell 程序,然后 shell 负责 hello 程序的加载,运行结果返回给 ssh 的服务端,最后 ssh 的服务端通过网络将程序的运行结果发送给 ssh 的客户端,ssh 客户端在屏幕上显示运行结果。
参考:Datawhale开源社区
《深入理解计算机系统》 CSAPP 入坑推荐
1、CSAPP是什么
-
CSAPP是什么?
CSAPP是一本书,全称Computer Systems A Programmer’s perspective,国内通常的书名翻译是《深入理解计算机系统》
电子在线版本可以在github上找到:
https://hansimov.gitbook.io/csapp/
https://github.com/Hansimov/csapp -
CSAPP的来源?
这本书是CMU的计算机导论教材,是曾经的CMU计算机系主任编写的。
配套的课程可以再github和bilibili上找到。
https://github.com/EugeneLiu/translationCSAPP
https://www.bilibili.com/video/av31289365 -
为什么这本书好?
CMU是全美以至全球公认的CS最好的大学之一。
作为该校的计算机导论课教材,浅显易懂又涵盖整个计算机领域的最权威严谨的专业知识。
包括一直以来网友对这本书的封神,称之为计算机专业神书。
国内也有很多高校,比如NJU(Coursera上有相关公开课)开始采用这本书作为大一或大二的教材了。
2、CSAPP的大致内容
-
这本书主要讲什么?
从程序员的角度 学习计算机系统是如何工作的,通过描述程序是如何映射到计算机系统上,程序是如何执行的,以及程序效率低下的原因,这样的方式可以让大家能更好的知道「程序与计算机系统 」的关系。 -
这本书如何讲述的?
从一个简单的hello world程序在计算机上的执行过程:
预处理->编译->汇编->链接->可执行文件->装载->数据流->屏幕输出显示
汇总成一句:信息 = 位+上下文。 -
这本书的内容覆盖?
内容涵盖了计算机组成 + 操作系统 + 汇编 + C语言 + Linux等等
以上是关于CSAPP-深入理解计算机系统-task01计算机系统漫游的主要内容,如果未能解决你的问题,请参考以下文章