---
schema_version: "library-reader-v1"
source_type: "original_book"
title: "编码 隐匿在计算机软硬件背后的语言"
author: null
edition: null
publisher: null
year: null
isbn: "9787121181184"
library_document_id: "38270854-596f-4a26-8183-db8c968c6020"
source_sha256: "249786274d83909f0bddc34d77f81ed8f0b14d1eac8843c772a37a3ecbfe2cfc"
pdf_physical_page_count: 438
pdf_physical_page_index_base: 0
range_start: 370
range_count: 10
html_url: "https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020?start=370&limit=10"
markdown_url: "https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020.md?start=370&limit=10"
previous_url: "https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020.md?start=360&limit=10"
next_url: "https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020.md?start=380&limit=10"
---

# 编码 隐匿在计算机软硬件背后的语言

> 页码规则：PDF_PHYSICAL_PAGE_INDEX 是从 0 开始的权威文件物理页索引；PRINTED_PAGE 是页面中识别出的印刷页码，可能为空，二者不得混用。

## PDF_PHYSICAL_PAGE_INDEX=370 | PRINTED_PAGE=354

目录区是磁盘中的一个非常重要的区域，磁盘文件中每个文件的名字和其他一些重要信息都存储在该区域，根据目录就能够很方便、高效地查找文件。存放目录也需要占用空间，磁盘上每个文件对应的目录项（directory entry）大小均为32字节，由于目录区大小为2048字节，所以这个磁盘上最多可以存放64（2048/32）个文件。

为了能够根据目录找到相应的文件，每一个32字节的目录项包含以下信息。

在目录项中，第一个字节用来设置文件的共享属性，只有文件系统被两个或更多人同时共享时才设置此字节为1。在CP/M中，这个字节跟第13、14字节一样，通常设置为0。

CP/M中每个文件的文件名由两部分构成，第一部分称为文件名（filename)，文件名最多由8个字符构成，目录项的第1\~8字节用来存储文件名。第二部分称为文件类型(file type)，最多由3个字符表示，这些字符存储在目录项的第9\~11字节中。我们会经常遇到一些常见的标准文件类型，例如：TXT表示文本文件（此文件只包含ASCII码）；COM(command的简写)表示这个文件中存放的是8080机器码指令，或者说是一段程序。当命名一个文件时，通过一个点来隔开这两部分，如下所示：

MYLETTER.TXT

CALC.COM

人们习惯形象地称这种文件命名方式为8.3，就是说在点号隔开的前半部分最多有8个字母，后半部分最多有3个字母。

接下来介绍一下如何利用目录项查找文件。目录项中的第16\~31字节是磁盘存储表，它能够标明文件所存放的分配块。假设磁盘存储表的前4项分别为14h、15h、07h、23h，其余项全为0，这表明文件占用了4个分配块的空间，大小为4KB，而实际上文件可能并没有用完4KB空间，因为最后一个分配块往往只有部分扇区被使用。目录项的第15字节表明最后一个分配块到底用到了多少个128字节的扇区。

编码隐匿在计算机软硬件背后的语言

354

## PDF_PHYSICAL_PAGE_INDEX=371 | PRINTED_PAGE=355

磁盘存储表的长度为16字节，最多可以容纳16,384字节（16KB）的文件，如果文件的长度超过16KB，就需要用多个目录项来表示，这种方法称为扩展（extents)。如果一个大文件使用目录项扩展来，则将第一个目录项的第12字节设置为0，第二个目录项的第12字节则设置为1，依此类推。

文本文件对我们并不陌生，通常也称之为 ASCII文件（ASCIIfile）、纯文本文件(text-only file)或纯 ASCII 文件(pure-ASCII file)，当然还有其他一些类似的名称。ASCII码（包括换行符和回车符）是文本文件中唯一包含的字符，文本文件通俗易懂，便于浏览。除了文本文件外，其余的文件称为二进制文件（binaryfile)，在CM/P中，COM文件存放的是二进制的8080机器码，它是二进制文件。

假设一个小文件中包含三个16位数，如：5A48h、78BFh和 F510h。如果此文件是二进制文件，只要6字节就可以了。

48 5A BF 78 10 F5

这是采用Intel格式来存储的，放在前面的是低位，放在后面的是高位。并不是所有的数据都是按照这种格式来存储的，例如为Motorola处理器编写的程序更倾向于按以下的方式来组织文件：

5A 48 78 BF F5 10

假如上面的三个16位数用ASCII文本文件来存放，则文件中保存的数据如下所示：

35 41 34 38 68 0D 0A 37 38 42 46 68 0D 0A 46 35 31 30 68 0D 0A

上面的这些字节是数字和字母的ASCII码表示形式，用回车符(0Dh)和换行符(0Ah)来表示每一个数的结束。因为文本文件可以不通过解释相应的ASCI字节串来显示字符，而是将字符本身直接显示，所以显得更加方便，如下所示：

5A48h 78BFh F510h

22 操作系统

355

## PDF_PHYSICAL_PAGE_INDEX=372 | PRINTED_PAGE=356

也可以用如下的形式来表示包含这三个数的ASCI文本文件：

$$
\texttt { 3 2 } 3 3 3 1 3 1 3 2 0 0 0 0 \texttt { 3 3 } 3 0 3 9 3 3 1 0 0 0 \texttt { 3 6 } 3 2 \texttt { 3 7 } 3 3 3 6 0 0 \texttt { 0 }
$$

这是用十进制数的ASCI码形式来表示上述三个数，这两种表示形式是等价的，如下所示：

23112   
30911   
62736

显然，文本文件更易于人们阅读，同样，与十六进制相比，十进制更符合人们的习惯，没理由使用十六进制而拒绝十进制。

前面曾提到过，磁盘最开始的两个磁道存储CP/M系统本身，而CP/M在磁盘上是无法运行的，必须将其加载到内存里。只读存储器（ROM）在CP/M计算机中使用得并不多，只需要用它来存放一小段称为引导程序（bootstraploader，操作系统的其余部分可以通这段代码的自举操作被高效地引导）的代码即可。开机启动时，磁盘上最开始的128字节的扇区内容，会首先由引导程序加载到内存并运行，这个扇区包含有特定的代码，可以把CP/M中的其余部分加载到内存中，整个过程称为操作系统的引导（booting)。

操作系统的引导过程完成后，随机存储器（RAM）的最高地址区域用来存放CP/M，加载完CP/M后，整个内存空间的组织结构如下所示。

编码—隐匿在计算机软硬件背后的语言

356

## PDF_PHYSICAL_PAGE_INDEX=373 | PRINTED_PAGE=357

该图仅仅粗略地表示出了内存各构成部分，没有按比例刻画各部分所占内存的大小。控制台命令处理程序(Console Command Processor，CCP)、基本磁盘操作系统(Basic DiskOperating System，BDOS）和基本输入/输出系统（Basic Input/Output System，BIOS)是CP/M的三个组成部分，这三个部分只占用了6KB大小的内存空间。在拥有64KB内存空间的计算机中，大约 58 KB被临时程序区（Transient Program Area，TPA）占用，但是这58KB空间一开始时是空的。

控制台命令处理程序的功能和以前讨论过的命令处理程序是一样的。在这里，键盘和显示器组成了控制台（console)。控制台命令处理程序显示如下所示的命令提示符(prompt ):

A>

在命令提示符后面可以输入一些信息。大多数计算机可能有不止一个磁盘驱动器，第一个磁盘驱动器标为A，CP/M被装载到该驱动器中。在命令提示符后面敲入命令并按回车（Enter）键，控制台命令处理程序会执行该命令，然后将执行的结果显示到屏幕上。执行完命令后，命令提示符又会显示在屏幕上，等待下一次输入。

控制台命令处理程序只能识别一部分命令，其中最重要的命令是：

DIR

该命令用于显示磁盘的目录信息，换句话说，它列出了存储在磁盘上的所有文件。然而有时候需要查看具有特定名字和类型的文件，这时候就可以在命令中使用像“？”和“\*”这样的特殊字符来限定。如果想显示当前目录下所有的文本文件，可以使用如下指令：

DIR \*.TXT

而

DIR A???B.\*

则显示所有文件名由5个字符构成，其中第一个字符是A，最后一个字符是B的文件。

如果想删除磁盘中的文件，要用到命令ERA，它是Erase的缩写，例如：

ERA MYLETTER.TXT

22 操作系统

357

## PDF_PHYSICAL_PAGE_INDEX=374 | PRINTED_PAGE=358

用来删除名为MYLETTER.TXT的文件，而运行下面的命令：

ERA \*.TXT

则所有的文本文件都被删除。一旦删除文件，此文件的目录项及其所占用的磁盘空间都将被释放。

REN也是一个常用命令，它是Rename的缩写，此命令可以改变文件名。如果想显示文本文件的内容，可以使用TYPE命令，这条命令的功能还不仅如此，要知道文本文件中仅包含ASCI码，所以屏幕上文件的内容也可以通过这条命令来浏览，例如：

TYPE MYLETER.TXT

表示查看MYLETER.TXT 文件的内容。SAVE 命令用来保存文件，它可把临时存储区域中的一个或多个256字节的内存块保存到磁盘中，并且给这个内存块指定一个名字。

当然，上述所介绍的都是CP/M可识别的命令，如果你输入一个不能被CP/M识别的命令，CP/M就会默认为输入的是保存在磁盘上的一个程序名。而程序通常是以文件形式存储的，其文件类型为COM，代表着命令。控制台命令处理程序负责在磁盘上查找此文件，如果找到，此文件会被CP/M从磁盘加载到临时程序区域，该区域的地址从0100h开始，一旦文件被调入内存即可运行。上面从流程的角度介绍了磁盘中的文件是如何被运行的，下面举个例子来说明。假如在CP/M命令提示符后面输入：

CALC

如果在磁盘中存在名为CALC.COM的文件，则该文件会被控制台命令处理程序调入到以地址0100h开始的内存中，接着控制台命令处理程序会转到该地址并执行这段程序。

前面介绍了如何将机器码指令插入到内存空间的任意位置并执行。但是存储在磁盘上的CP/M程序并不能被随意存放到内存中的任意位置，它必须被加载到指定的位置，在这里是以0100h开始的内存空间。

CP/M由一些实用的程序组成，如 PIP(Peripheral Interchange Program)，即外设交换程序，通过它可以复制文件。ED是文本编辑器，可以创建和修改文本文件。在CP/M系统中，有很多像PIP和ED一样的程序，它们很小但可以完成简单的事务处理，这类程序称为实用（utility）程序。仅仅有这些小的简单程序是远远不够的，还有一些大的商业化应用程序（application)，比如字处理软件或计算机电子报表软件等，在CP/M系统中，这些软件的使用会给你的工作带来很大方便。当然，如果你是一个程序开发高手，也可以自己动手编写这些软件，这些程序的存储类型都是COM文件类型。

编码隐匿在计算机软硬件背后的语言

358

## PDF_PHYSICAL_PAGE_INDEX=375 | PRINTED_PAGE=359

在CP/M（跟许多操作系统一样）中，我们了解了很多内容，比如如何利用命令和实用程序对文件进行基本操作，如何将程序加载到内存中并运行等。操作系统的功能远不止如此，下面将介绍它的第三个重要功能。

前面提到过，把输出信息写到视频显示器上，或者从键盘读取输入的内容，或者读写磁盘中的文件，这些都是运行在CP/M下的程序常常要做的操作。这就需要CP/M程序能够直接向视频显示器的内存写入输出内容，也需要CP/M程序能够访问键盘硬件来捕获所输入的内容，还需要CP/M程序能够访问磁盘驱动器来读/写磁盘扇区，然而在通常情况下程序本身是很难直接做到的。

那么有没有别的方法来实现上述的要求呢？答案是肯定的，这些常用事务由CP/M中的子程序集来完成，在CP/M下运行的程序通过调用这些子程序即可完成相应的操作。这些子程序都是专门设计的，计算机中的所有硬件都可以很容易地通过它们来访问，如视频显示器、键盘、磁盘驱动器等，而程序员无须关心这些外设实际是如何连接的。更重要的是，像磁道、扇区这类信息，程序没有必要知道，这些工作都是由CP/M来完成的，它可以负责读/写磁盘上的文件。

操作系统提供的第三个主要功能是让程序能够方便地访问计算机的硬件，操作系统提供的这种访问操作称为 API（Application ProgrammingInterface)，即应用程序接口。

那么如何设置和使用API呢？在CP/M下运行的程序，可以通过将寄存器C设置为特定的值（称为功能值），并且运行如下指令：

CALL 5

来使用API。例如，你从键盘上按下了一个键，程序会通过执行下面的指令来获取此键对应的 ASCII码：

MVI C,01h

CALL 5

并且将这个键的ASCII码值保存在累加器A中。类似的，运行这条命令：

22 操作系统

359

## PDF_PHYSICAL_PAGE_INDEX=376 | PRINTED_PAGE=360

MVI C,02h

CALL 5

在视频显示器上当前的光标位置将显示累加器A中的ASCⅡ码字符，然后光标移到下一个位置。

如果程序要新建一个文件，它首先将文件名所在区域的地址保存在寄存器对DE中，接着执行如下代码：

MVI C,16h

CALL 5

执行此命令，CP/M会在磁盘上新建一个空文件。程序可以利用CP/M提供的其他功能来向空文件中写入内容，最后关闭（close）文件，关闭文件意味着文件使用完毕，不需要在对该文件执行任何操作了。当然，该文件可以再次被此程序和其他程序打开(open)并读取内容。

CALL 5 指令到底如何工作呢？ CP/M 在内存中地址为 0005h 处设置了一条 JMP(Jump）指令，它跳转到 CP/M 基本磁盘操作系统（Basic Disk Operating System，BDOS)中的某个位置。这个区域包含许多小程序，CP/M的每一项功能都可由它们完成。BDOS，顾名思义，它的主要功能是维护磁盘上的文件系统。文件系统经常要与终端设备打交道，所以 BDOS 经常要调用 CP/M 基本输入/输出系统(Basic Input And Output System，BIOS)中的一些子程序。这里顺便提一下，BIOS可以对硬件进行访问，比如键盘、视频显示器和磁盘驱动器等。实际上，BIOS是CP/M中唯一需要了解计算机中硬件的程序，其他一些对硬件的操作都可通过调用 BIOS中的子程序来实现。控制台命令处理程序通过调用BDOS的子程序来实现自己所有的功能，而在CP/M中运行的程序也是这样。

对于计算机硬件来说，API是一个与设备无关(device-independent)的接口。换言之，对于特定的机器上键盘的工作机制、视频显示器的工作机制以及磁盘扇区的读/写机制，在CP/M下编写的程序不需要知道也没有必要知道。程序使用CP/M提供的功能便可完成对键盘、视频显示器和磁盘驱动器操作，简言之，API屏蔽了硬件之间的差异。有了API，尽管不同计算机硬件差别很大，其访问外设的方式也不尽相同，但CP/M程序都可以在上面运行，从而实现了CP/M程序的跨平台(这里要求所有CP/M程序必须运行在Intel 8080微处理器上，或者运行在能执行 Intel 8080 指令的处理器上，例如 Intel 8085 或 Zilog Z-80

编码——隐匿在计算机软硬件背后的语言

360

## PDF_PHYSICAL_PAGE_INDEX=377 | PRINTED_PAGE=361

处理器)。所以，在使用CP/M系统的计算机中，程序对硬件访问是通过CP/M来实现的。  
如果没有标准的API，程序必须根据不同型号的计算机进行相应的修改后，才能访问硬件。

CP/M是8080中非常流行的操作系统，曾经辉煌一时，至今仍有重要的历史意义。16 位操作系统 QDOS( Quick and Dirty Operating System )的开发在很多方面都借鉴了 CP/M的思想。QDOS当初是专为英特尔公司的16位8086和8088芯片而设计的，它出自西雅图计算机产品公司（Seattle computer product）的提姆·帕特森之手。QDOS 系统被微软公司注册后更名为86-DOS。1981年，随着IBM第一代PC诞生，微软公司也将86-DOS更名为 MS-DOS（Microsoft Disk Operating System)，并以此名授权给 IBM 公司用作第一代个人计算机的操作系统。这就是著名的MS-DOS系统，在现在的计算机中也会经常看到它的身影。虽然16 位版本的 CP/M(称为 CP/M-86)也可用于IBM PC，但由于MS-DOS的影响力更大，其很快成为了标准。其他生产IBMPC兼容机的厂商也被授权使用MS-DOS（在 IBM计算机上称为 PC-DOS）系统。

CP/M的文件系统在MS-DOS 没有被继续使用，在MS-DOS 中，文件系统是以文件分配表（FAT，File Allocation Table的简写）的形式来组织的，Microsoft 公司早在1977年就开始使用FAT了。FAT的基本思想是：将磁盘空间分成簇（cluster）——簇的大小由磁盘空间的大小来决定—从512字节到16K字节不等，每个文件占用若干簇。文件的目录项只记录文件起始（starting）簇的位置，而磁盘上每一簇的下--簇的位置由FAT来记录。

每个目录项在MS-DOS磁盘上占用32字节，其命名形式跟CP/M上的8.3形式--样，只是使用的术语有些区别：最后的三个字符称做文件扩展名，而非CP/M中的文件类型。MS-DOS目录项中没有包含分配块列表，它主要包含如下所示的有用信息：文件的最后修改的日期、时间和文件的大小等。

实际上，MS-DOS的早期版本与 CP/M在结构上很类似，只是IBM PC 本身在ROM中已经包含了一套完整的 BIOS了，所以在MS-DOS 中不再需要 BIOS。在MS-DOS 中，命令处理器是一个命名为COMMAND.COM的文件。MS-DOS 有两种运行程序：一是以COM为扩展名的文件，其大小不能超过64KB，二是更大一些的程序，以EXE（意思是可以被执行）为文件的扩展名，表明文件本身是可执行的。

尽管 MS-DOS 起初支持 API 函数的 CALL 5 接口，但不久 Microsoft 为新的程序重新设计了一款新的接口。这个新的接口使用了8086的一个称为软件中断(software interrupt)的功能，说起软件中断，它与子程序调用很类似，只不过程序不必知道它所调用的子程序的确切地址。通过执行INT21h这条指令，程序可以调用MS-DOS的API功能。

22 操作系统

361

## PDF_PHYSICAL_PAGE_INDEX=378 | PRINTED_PAGE=362

从理论上讲，应用程序并不能直接访问计算机的硬件，如果它要访问计算机的硬件，可以通过操作系统提供的接口来进行。然而实际上，在20世纪70年代末和80年代初，由于计算机上运行的都是小型操作系统，许多应用程序往往都绕过它们，这种情况在处理有关视频显示器任务的时候显得特别明显。为什么会这样呢？因为如果程序把字节直接写入视频显示存储器，它的执行速度要远快于不直接写入视频显示存储器。事实上，对于一些程序—比如要将图形显示在视频显示器上—操作系统就显得“心有余而力不足”，这就需要在操作系统之外另作处理。也许正是因为MS-DOS系统卓越的“反传统性”，使得大多数程序员都很热衷于它，它可以让程序员编写的程序最大限度地达到硬件的最快速度，更加充分地发挥硬件的性能。

恰恰是这个原因，运行在IBMPC上的流行软件通常依赖于IBMPC这个硬件平台，换句话说，就是这些软件是根据IBMPC的硬件特点编制的。为了和IBMPC竞争，其他机器制造商不得不沿袭这些特点。如果不这样做的话，再流行的软件也将流行不起来，因为它不能在这些机器上运行。所以在软件的显著位置往往会出现“与IBMPC百分之百兼容”的字样，这同时体现了软件对硬件的要求。

微软于1983年3月发布了MS-DOS2.0版本，与最开始的版本相比，它加强了对硬盘驱动器的管理。虽然当时的硬盘容量很小(按今天的标准)，但是发展很快，没经过多久，硬盘的容量变得越来越大。这带来了不少问题，硬盘容量越大存储的文件也就越多，存储的文件越多，当然，查找某个指定的文件或组织文件也就越困难。

为了解决上述问题，MS-DOS 2.0引入了层次文件系统（hierarchical file system)，它只是在原有MS-DOS的文件系统上做了一些小的改动。前面介绍过，目录存储在磁盘中特定区域，它是一个文件列表，包含了文件存储在磁盘位置的信息。在层次文件系统中，有些文件其本身可能就是目录，也就是说这些文件包含其他文件，其中的一些可能还是目录。在磁盘中，目录的称法也是有讲究的，常规的目录称为根目录（root directory)，子目录(subdirectories）是包含在其他目录里的目录。有了目录（有时称文件夹，folder)，就可以很方便地对相关文件进行分组，所以目录在磁盘文件的管理中起着非常重要的作用。

编码—隐匿在计算机软硬件背后的语言

362

## PDF_PHYSICAL_PAGE_INDEX=379 | PRINTED_PAGE=363

讲到操作系统，我们不能不提到著名的UNIX系统，它在操作系统的发展史上有着举足轻重的地位。实际上，层次文件系统和MS-DOS2.0的其他很多功能都是从UNIX操作系统借鉴而来的。UNIX操作系统是20世纪70年代初在贝尔实验室开发的，肯·汤普森（Ken Thompson，生于1943年）和丹尼斯·里奇（Dennis Ritchie，生于1941年）是此系统的主要开发者。UNIX系统（包括名字本身）的发展历程在这里要提一下，UNIX系统来源于早期的 Multics(Multiplex Information and Computing Services，表示多路复用信息和计算业务)，Multics是贝尔实验室和MIT（麻省理工大学）和GE（通用电气公司）合作开发的一个项目，开发初期由于Multics没能达到预定的目的而且进度缓慢，加之昂贵的开发代价，1969年贝尔实验室退出了该项目，但肯·汤普森和丹尼斯·里奇继续对此进行了开发，为了区别于Multics，取名为UNIX。

对于计算机核心程序开发的精英们来说，UNIX无疑是最受欢迎的操作系统。以前大部分操作系统是针对特定的计算机硬件平台开发的，但UNIX打破了常规，它不针对具体的计算机硬件平台，具有很好的可移植性(portable)，也就意味着它在各种机器上都可以运行。

在开发 UNIX的时候，贝尔实验室是电信业巨头 AT&T（American Telephone &Telegraph，美国电话电报公司）旗下的一员，为了限制 AT&T在电话业务的垄断地位，法院裁定禁止AT&T销售UNIX系统，AT&T被迫将它授权给别人。因此从1973年初，很多大学、公司和政府机构被授权使用和研究UNIX，这在一定程度上促进了UNIX的发展。1983年，AT&T获准重返计算机业务并发布了它自己的UNIX版本。

由于UNIX的广泛授权导致了许多不同版本共存的情况，它们使用着不同的名字，运行在不同的计算机上，并由不同的经销商销售。由于UNIX的影响力和开源性，使得很多人将精力投入到 UNIX 中并推动着它的不断发展。当人们向 UNIX中添加新的组件时，无形之中流行着一种不成文的“UNIX思想”。在这种思想的指导下，人们都使用文本文件作为公用文件形式。许多UNIX实用程序读取文本文件，利用它提供的一些功能做些处理，然后将其写入另一个文本文件。因此可以用链的形式来组织UNIX实用程序，然后对这些文本文件做相应的处理。

在20世纪60-70年代，计算机不仅体积庞大而且价格昂贵，仅仅为一个人服务显然不太现实，为了能够让多个人同时使用计算机，必须有相应操作系统来支持，这也就是开发UNIX系统的最初目的。使用UNIX系统的计算机通过时分复用(time sharing)技术—这种技术允许多个用户同时与计算机进行交互—来达到这个目的。计算机连接多个配备了显示器和键盘的终端（terminals)，每个用户通过这些终端访问计算机。通过在所有终端间的快速切换，使用户感觉这台计算机似乎只为自己工作，而其实计算机同时在为多个用户服务。

22 操作系统

363

下一段：[继续读取](https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020.md?start=380&limit=10)
