-
1.2 把程序转化为 低级机器语言指令。然后把 指令 打包为 可执行目标程序 的格式打包, 并以二进制的磁盘文件的形式存放。目标程序也 称为可执行目标文件。
-
在Unix 系统上, 源文件到目标文件的转化是由编译器驱动程序完成的: gcc 编译器驱动程序读取源程序文件 hello.c , 并把它翻译成一个可执行目标文件 hello. 这个翻译过程分为4 个阶段完成。编译系统:hello.c (文本)
1 预处理器 : cpp -> hello.i (文本)
2 编译器 : ccl -> hello.s (文本)
3 汇编器: as -> hello.o(二进制)
4 链接器: ld -> hello (二进制 , 可执行程序)- 预处理阶段: (cpp)更具以字符 # 开头的命令, 修改原始的C 程序。 入去内容,并直接把 内容 插入程序文本中。 得到 hello.i
- 编译阶段: (ccl)将文本文件 hello.i 翻译成文本文件 hello.s , 它包含一个汇编语言程序。翻译以后,低级机器语言指令以文本格式描述。汇编语言
- 汇编阶段:(as)汇编器 将 hello.s 翻译成机器语言指令, 并把指令打包成一些种叫做 可重定位目标程序, 并将结果保存在文件 hello.o (二进制文件)中
- 链接阶段 : hello 程序调用了printf 函数, 她是每个C 编译器都提供的的标准C 库中的一个函数。 print函数存在于一个名为 printf.o 的单独的预编译好了的目标文件中, 而这个文件必须以某种方式合并到我们的 hello.o 程序中。 链接器(Id)就负责处理这种合并。结果就得到 hello 文件, 他是一个 可执行目标文件, 可以被加载到内存中,由系统执行。
-
1.4 处理器读并解释存储在内存中的指令
- after hello.c 源程序已经被编译系统翻译成了可执行目标文件 hello.o, 并被存放在磁盘上。 要想在 Unix 系统上运行该可执行文件, 我们将他的文件名输入到称为 shell 的应用程序中:
linux> ./hello
hello, world
linux>
shell 是一个命令行解释器,它输出一个提示符,等待输入一个命令行,然后执行这个命令。如果该命令行的第一个单词不是一个内置的 shell 命令, 那么shell 就会假设这是一个可执行文件的名字,它将加载并运行这个文件。 所以在此例中,shell 将加载并运行hello 程序, 然后等待程序终止。 hello 程序在屏幕上输出他的消息, 然后终止。 shell 随后输出一个提示符, 等待下一个输入的命令行。
1 总线:
2 I/O 设备:
3 主存:
- 3.1 主存是一个临时存储设备, 在处理执行程序时,用来存放程序和程序处理的数据。从物理上来说, 主存是由一组 动态随机存储器(DRAM)芯片组成的。从逻辑上来说,存储器是一个线性的字节数组,每个字节都有其唯一的地址, 这些地址是从零 开始的。
4 处理器
-
4.1 中央处理单元(CPU), 简称 处理器, 世界是存储在 主存中指令的引擎。CPU 在指令的要求下可能会执行以下操作
- 加载 :从主存 复制内容 到 寄存器, 以覆盖寄存器原来的内容
- 存储 : 从寄存器 复制内容 到主存的某个位置, 以覆盖这个位置上原来的内容
- 操作:
- 跳转:
-
1.4.2 运行hello 程序
- 初始时, shell 程序执行它的指令,等待我们输入一个命令。 待我们输入指令后, shell 程序将字符逐一读入寄存器,再把它存放入内存中。当我们结束命令的输入后。shell 执行一系列指令来加载 可执行的hello 文件, 这些指令将 hello 目标文件中的代码和数据从磁盘复制到主存。 磁盘 -> 主存 -> 寄存器 , 再从寄存器文件中复制到 显示设备。
-
高速缓存至关重要
-
hello 程序的机器指令最初是存放在磁盘上,当程序加载时,他们被复制到主存; 当处理器运行时,指令又从主存复制到处理器。多次复制减慢了程序的速度。
-
高速缓存存储器(cache memory), 加快了主存的运行速度。 cached memory 存放最近需要的信息。
-
存储器层次结构 L0 - L6
- L0: 寄存器
- L1: SRAM
- L2: SRAM
- L3: SRAM
- L4: 主存 (DRAM)
- L5: 本地二级存储(本地磁盘)
- L6: 远程二级存储 (分布式文件系统, web 服务器)
-
-
1.7 操作系统管理硬件 : 我们可以把操作系统 看成是 应用程序 和 硬件之间 的一层软件。 所有引用程序对硬件的操作册灰姑娘是都必须通过操作系统。
- 应用程序 (shell, hello) -> 软件
- 操作系统 -> 软件
- 处理器, 主存, I/O 设备 -> 硬件
-
操作系统有两个基本功能:
- (1) 防止硬件被失控的应用程序滥用
- (2) 向应用程序提供简单一致的机制来控制 硬件设备
- 操作系统通过这几个基本的抽象概念 (进程, 虚拟内存 和 文件 )来实现以上功能
- 处理器 -> 进程
- 主存 -> 虚拟内存
- I/O 设备 -> 文件
-
1.7.1 进程
- 进程是操作系统对一个正在运行的程序的一种抽象。
- 并发运行 : 一个进程的指令和另一个进程的指令是交错执行的, 操作系统实现这种交错执行机制 称为上下文切换。
- 例子: 场景中有两个 并发的进程: shell 进程 和 hello 进程。 最开始只有 shell 进程在运行, 即等待命令行上的输入。 当我们让它运行 hello 程序时, shell 通过调用一个专门的函数, 即系统调用。 1. 操作系用保存 shell 进程的上下文,2. 创建一个新的 hello 进程及其上下文, 3. 然后将控制权转给新的 hello 进程。 hello 进程终止后, 操作系统恢复shell进程的上下文, 并将控制权传回给shell, shell 进程会继续等待下一个命令行的输入。
- 从一个进程到另一个进程的转换是由 操作系统内核(kernel)管理的。kernel 不是一个独立的进程。 相反, 它是系统管理全部进程所用代码 和 数据结构的集合。
-
1.7.2 线程
- 一个进程可以运行多个线程, 每个线程 都运行在进程的上下文中, 并共享同样的代码和 全局数据。 优点: 多线程比多进程之间更容易共享数据。
-
1.7.3 虚拟内存
- 虚拟内存是一个抽象概念,它为每个进程提供了一个假象, 即每个进程都在独占的使用主存。
- 程序代码和数据 : 代码和数据区是直接按照 可执行目标文件的内容初始化的
- 堆:从下向上扩展和收缩,当调用 malloc 和 free. 代码和数据区 紧随 其后的是运行时的堆。
- 共享库 : 用于 动态链接
- 栈 : 编译器用它来实现函数调用。 和堆一样,在程序执行期间 会动态的扩展和收缩。当我们调用一个函数时, 栈就会增长; 从一个函数返回时, 栈就会收缩。
- 内核虚拟内存:地址空间顶部的区域是为内核保留的。基本思想 是把一个进程虚拟内存的内容存储在磁盘上,然后用主内存作为磁盘的高速缓存。
- 虚拟内存是一个抽象概念,它为每个进程提供了一个假象, 即每个进程都在独占的使用主存。
-
1.7.4 文件
- 文件就是字节序列。 每个I/O 设备都可以看成文件。系统中所有输入输出都是通过使用一小组称为 Unix I/O 的系统函数调用读写文件来实现的。
-
1.8 系统之间利用网络通信
- 从一个单独的系统来看, 网络可视为一个 I/O 设备。当系统从主存复制一串 字节到网络适配器时, 数据流经过网络到达另一台机器。
- 举例:
- 用户在键盘上 输入“hello”
- 2.客户端向 talnet 服务器发送字符串 “hello” ;
- 服务器向shell 发送字符串“hello”, shell 运行hello 程序并将输出发送给 telnet 服务器。
- telnet 服务器向客户端 发送字符串 “hello world \n”
- 客户端在显示器上打印“ hello world \n” 字符串
-
小结
网友评论