系统级程序设计笔记(unit1——计算机系统漫游)

这个专题的所有学习笔记来自于对武汉大学计算机学院软件工程专业大三上学期的专业必修课《系统级程序设计》的学习(教材为深入理解计算机系统CSAPP),涉及的编程语言全部为C语言和C++语言。

该博客为第1单元的学习笔记,这一单元的主要内容是计算机系统漫游,内容来自《深入理解计算机系统》的第一章,对应ssd6课程的lecture2。


信息就是位+上下文

信息是什么? 信息就是位+上下文
程序的生命周期是从一个源程序(源文件)开始的,源程序实际上就是由一个值0和1组成的位(又称为比特)序列,8个位被组织成一组称为字节。每个字节表示程序中的某些文本字符。
只由ASCII字符构成的文件称为文本文件,所有其他文件都称为二进制文件。
系统中的所有信息——包括磁盘文件、内存中的程序、内存中存放的用户数据以及网络上传送的数据都是一串比特表示的。区分不同数据对象唯一的方法是我们读到这些数据对象时的上下文。比如,在不同的上下文中,一个同样的字节序列可能表示一个整数、浮点数、字符串或者机器指令。

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

(1)

unix> gcc –E hello.c -o hello.i

Stop after the stage of compilation proper; do not assemble.
预处理阶段,预处理器根据以字符#开头的命令修改原始的C程序。
比如#include < < <script id="MathJax-Element-22" type="math/tex"><</script>stdio.h > > <script id="MathJax-Element-23" type="math/tex">></script>命令告诉预处理器读取系统头文件stdio.h的内容并把它直接插入程序文本中,得到另一个C程序,通常以.i作为文件扩展名。

(2)

unix> gcc –S hello.i -o hello.s

Stop after the preprocessing stage; do not run the compiler proper.
编译阶段。输入的是中间文件.i,编译后生成汇编语言文件.s 。

(3)

unix> gcc –c hello.s -o hello.o

Compile or assemble the source files, but do not link.
汇编阶段,将输入的汇编文件.s转换成机器语言.o
hello.o文件是一个二进制文件

(4)

unix> gcc hello.o -o hello

Compile or assemble the source files, one-shot.
链接阶段。最后,在连接阶段将输入的机器代码文件*.s(与其它的机器代码文件和库文件)汇集成一个可执行的目标文件。

编译系统是如何工作的:

(1)优化程序性能
现代编译器都是成熟的工具,通常可以生产很好的代码,作为程序员,我们无须为了写出高效代码而去了解编译器的内部工作。但是,为了在C程序中做出好的编码选择,我们确实需要了解一些机器代码以及编译器将不同的C语句转化为机器代码的方式。比如,一个switch语句是否总是比一系列的if-else语句高效得多?有个函数的调用的开销有多大?while循环比for循环更有效吗?指针引用比数组索引更有效吗?为什么将循环求和的结果放到一个本地变量中会比将其放到一个通过引用传递过来的参数中运行起来快很多呢?为什么我们只是简单地重新排列一下算术表达式中的括号就能让函数运行得更快?

(2)理解链接时出现的错误
根据我们的经验,一些最令人困扰的程序错误往往都与链接器操作有关,尤其是当你试图构建大型的软件系统时。比如,链接器报告说它无法解析一个引用,这是什么意思?静态变量和全局变量的区别是什么?如果你在不同的C文件中定义了名字相同的两个全局变量会发生什么?静态库和动态库的区别是什么?我们在命令行上排列库的顺序会有什么影响?最严重的是,为什么有些链接错误直到运行时才会出现?

(3)避免安全漏洞
多年来,缓冲区溢出错误是造成大多数网络和Internet服务器上安全漏洞的主要原因。存在这些错误是因为很少有程序员能够理解需要限制从不受信任的源接收数据的数量和格式。学习安全编程的第一步就是理解数据和控制信息存储在程序栈上的方式会引起的后果。作为学习汇编语言的一部分,我们将在lecture3中描述堆栈原理和缓冲区溢出错误。我们还将学习程序员、编译器和操作系统可以用来降低攻击威胁的方法。

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

硬件组成包括总线、IO设备、主存、处理器
详见csapp 5-8页(第三版)

高速缓存至关重要

一个典型的寄存器文件只存储几百字节的信息,而主存里可存放几十亿字节。然而,处理器从寄存器文件中读数据比从主存中读取几乎要快100倍。而且,随着这些年半导体技术的进步,这种处理器与主存之间的差距还在持续增大。加快处理器的运行速度比加快主存的运行速度要容易和便宜得多。
更小更快的存储设备->高速缓存存储器cache
系统可以获得一个很大的存储器,同时访问速度也很快,原因是利用了高速缓存的局部性原理,即程序具有访问局部区域里的数据和代码的趋势。通过让高速缓存里存放可能经常访问的数据,大部分的内存操作都能在快速的高速缓存中完成。

存储设备形成层次结构

主要思想:上一层的存储器作为低一层存储器的高速缓存,寄存器文件就是L1的高速缓存,L1是L2的高速缓存,以此类推。
L0寄存器
L1高速缓存SRAM
L2高速缓存SRAM
L3高速缓存SRAM
L4主存DRAM
L5本地二级存储(本地磁盘)
L6远程二级存储(分布式文件系统、Web服务器)

操作系统管理硬件

(1)几个抽象:文件是对I/O设备的抽象表示,虚拟内存是对主存和磁盘I/O设备的抽象表示,进程是对处理器、主存和I/O设备的抽象表示。
(2)程序在运行时操作系统会提供一种假象,就好像系统上只有这个程序在运行,程序看上去是独占地使用处理器、主存和I/O设备。进程是操作系统对一个正在运行的程序的一种抽象。一个系统可以同时运行多个进程,每个进程都好像在独占地使用硬件。
并发运行,是说一个进程的指令和另一个进程的指令是交错执行的。
并发运行
context switch:上下文切换,即保存当前进程的上下文、恢复新进程的上下文、然后将控制权传递到新进程。
如上图,有两个并发的进程:shell进程和hello进程。最开始只有shell进程在运行,当运行hello程序时,hello通过调用一个专门的函数,即系统调用,来执行我们的请求,系统调用会将控制权传递给操作系统。操作系统保存shell进程的上下文,创建一个新的hello进程及其上下文,然后将控制权传递给新的hello进程。hello进程终止后,操作系统恢复shell进程的上下文,并将控制权传回给它,shell进程会继续等待下一个命令行输入。
(3)虚拟内存是一个抽象概念,它为每个进程提供了一个假象,即每个进程都在独占地使用主存。每个进程看到的内存都是一致的,称为虚拟地址空间。
下图是Linux进程的虚拟地址空间,地址空间中最上面的区域是保留给操作系统中的代码和数据的,地址空间的底部区域存放用户进程定义的代码和数据。
进程的虚拟地址空间
虚拟内存的运作的基本思想是把一个进程虚拟内存的内容存储在磁盘上,然后用主存作为磁盘的高速缓存。
(4)文件是I/O设备的抽象表示,每个I/O设备,包括磁盘键盘显示器甚至网络,都可以看成是文件。系统中的所有输入输出都是通过使用一小组称为Unix I/O的系统函数调用读写文件来实现的。
抽象的表示
再回顾一下刚才那句话:文件是对I/O设备的抽象表示,虚拟内存是对主存和磁盘I/O设备的抽象表示,进程是对处理器、主存和I/O设备的抽象表示。

⑧系统之间利用网络通信
利用talnet通过网络远程运行hello:
(1)用户在键盘上输入hello
(2)客户端向talnet服务器发送字符串hello
(3)服务器向shell发送字符串hello,shell运行hello程序并将输出发送telnet服务器
(4)telnet服务器向客户端发送运行hello程序的返回结果
(5)客户端在显示器上打印hello程序的运行结果。

⑨抽象的扩展:上面提到过文件是对IO设备的抽象,虚拟内存是对程序存储器的抽象,进程是对一个正在运行的程序的抽象。再新增一个新的抽象:虚拟机提供对整个计算机的抽象,包括操作系统、处理器和程序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值