1.3 计算机系统的层次结构
计算机系统采用分层方式构建,即计算机系统是一个层次结构系统。计算机解决应用问题的过程就是不同抽象层进行转换的过程。
1.3.1 计算机系统抽象层的转换
希望计算机完成或解决的任何一个应用(问题)最开始形成时是用自然语言描述的,但是,计算机硬件只能理解机器语言。要将用自然语言描述的一个应用问题转换为机器语言程序,需要经过应用问题描述、算法抽象、高级语言程序设计、将高级语言源程序转换为特定机器语言目标程序等多个抽象层的转换。图1.10是计算机系统层次转换示意图,描述了从最终用户希望计算机完成的应用(问题)到电子工程师使用器件完成基本电路设计的整个转换过程。
图1.10 计算机系统层次转换
在进行高级语言程序设计时,需要有相应的应用程序开发环境。例如,要有一个程序编辑器,以方便源程序的编写;需要一套翻译转换软件处理各类源程序,包括预处理程序、编译器、汇编器、链接器等;还需要一个可以执行各类程序的用户界面,如图形用户界面(Graphics User Interface, GUI)和命令行界面(Command Line Interface,CLI)。提供程序编辑器和各类翻译转换软件的工具包统称为语言处理系统,而具有人机交互功能的用户界面和底层系统调用服务例程则是由操作系统提供。
当然,所有的语言处理系统都必须在操作系统提供的计算机环境中运行,操作系统是对计算机底层结构和计算机硬件的一种抽象,这种抽象构成了一台可以让程序员使用的虚拟机(virtual machine)。
从应用问题到机器语言程序的每次转换所涉及的概念都属于软件的范畴,而机器语言程序所运行的计算机硬件和软件之间需要有一个“桥梁”,这个在软件和硬件之间的界面就是指令集体系结构(Instruction Set Architecture, ISA),有些场合简称为体系结构或系统结构(architecture),或指令系统(instruction set),它是软件和硬件之间接口的一个完整定义。在前文小贴士中提到的MIPS、ARM、Intel x86等都是指令集体系结构。
ISA定义了一台计算机可以执行的所有指令的集合,每条指令规定了计算机执行什么操作,以及所处理的操作数存放的地址空间以及操作数类型。因此,ISA实际上就是对指令系统的一种规定或体系结构规范,从物理形态来看就是一本对这些规定和规范进行描述的手册。机器语言程序就是ISA规定的若干条指令的序列。
实现ISA的具体逻辑结构称为计算机组织(computer organization)或微体系结构(microarchitecture),简称微架构。ISA和微体系结构是两个不同层面上的概念。例如,有没有乘法指令是ISA规定的内容,而乘法指令采用加法器和移位器实现,还是采用专门的乘法器实现,则属于微体系结构层面的问题。一个特定的ISA可以采用不同的微架构实现。例如,Intel Core i7、Intel 80486、AMD Athlon是x86体系结构的三种不同的处理器微架构实现。
一个特定的微架构由运算器、通用寄存器组和存储器等功能部件构成,功能部件层也称为寄存器传送级(Register Transfer Level, RTL)层。
功能部件由数字逻辑电路(digital logic circuit)实现。当然,一个功能部件可以用不同的逻辑电路实现。不同的实现方式得到的性能、成本和功耗等都有差异。最终每个基本的逻辑门电路由特定的器件技术(device technology)实现。
总体来说,整个计算机系统由软件、硬件和位于软/硬件交界面的指令集体系结构组成。如果将微体系结构、功能部件、基本逻辑门电路和物理器件作为一个整体的硬件层次,则计算机系统可以分为以下7个抽象层次:
● 第7层(应用层):以自然语言等形式描述应用问题需求,以应用程序的形式提供给最终用户使用。
● 第6层(算法层):以流程图等形式抽象出应用问题的解决思路,便于程序员设计和编写程序。
● 第5层(高级语言层):用符合特定标准规范的高级编程语言编写高级语言程序。
● 第4层(汇编语言层):用符合特定标准规范的汇编语言编写汇编语言程序。
● 第3层(操作系统层):以命令或函数等形式向上层用户(如最终用户、程序员)提供方便的人机交互和操作系统调用功能。
● 第2层(ISA层):给出构成机器语言程序(机器代码)的一整套指令系统规范。
● 第1层(硬件层):基于布尔代数和物理器件实现,可执行ISA中定义的所有指令。
从上到下的转换过程为:将应用问题抽象为流程图等算法描述,再将算法用编程语言设计转换为高级(或汇编)语言程序,在操作系统提供的人机交互命令和系统调用功能的支撑下,通过相应的语言处理系统,将高级(或汇编)语言程序转换为符合ISA规范的机器代码,最终在硬件上执行。
本书内容主要涉及图1.10所示的计算机系统抽象层中ISA层到编程语言层之间的一些基础内容。
1.3.2 计算机系统核心层之间的关联
如图1.11所示,编译程序将高级语言源程序转换为机器级目标代码需要完成多个步骤,包括词法分析、语法分析、语义分析、中间代码生成和优化、目标代码生成和优化等。整个过程可划分为前端和后端两个阶段,通常把中间代码生成及之前各步骤称为前端。因此,前端主要完成对源程序的分析,把源程序切分成一些基本块,并生成中间语言表示(即中间代码)。后端在分析结果正确无误的基础上,把中间代码转化为由特定ISA和特定操作系统所确定的运行平台支持的机器级语言程序(即目标代码)。
每一种程序设计语言都有相应的标准规范,进行语言转换的编译程序前端必须按照编程语言标准规范进行设计。程序员编写程序时,也只有按照编程语言的标准规范进行程序开发,程序才能被编译程序正确翻译。如果编写了不符合语言规范的高级语言源程序,转换过程就会发生错误,或者转换结果为不符合程序员预期的目标代码。
图1.11 编译器的前端和后端
程序执行结果不符合程序开发者预期的原因通常有两种。一种是程序开发者不了解语言规范,另一种是程序开发者编写了含有未定义行为(undefined behavior)或未确定行为(unspecified behavior)的源程序。
1.不了解语言规范的情况
如果程序员不了解语言规范,则会造成与直觉不符的情况。例如,对于C语言程序中的关系表达式“-2147483648<2147483647”,在32位、C90标准下,结果为false。虽然这个结果与直觉不相符,但是,用ISO C90标准规范是可以解释的,编译器前端完全按照语言标准规范进行处理,结果就应该是false。如果程序员觉得结果不符合预期,那是因为不了解C90标准规范。有关关系表达式“-2147483648<2147483647”在C90和C99标准中执行结果的解释参见3.2.3节。
2.编写了含有未定义行为源程序
如果程序员编写了未定义行为的源程序,则会发生每次执行结果可能不一样或在不同的ISA+OS运行平台下执行结果各不相同的情况。未定义行为是指语言规范中没有明确指定其行为的情况。
例如,以下C程序段:
就是未定义行为的情况。C语言标准手册中指出,当格式说明符和参数类型不匹配时,输出结果是未定义的。上述程序段中,格式说明符要求按浮点数打印,但参数x的类型为整型,因此是未定义行为。更多未定义行为的例子可参考网站https://en.wikipedia.org/wiki/Undefined_behavior。
3.编写了含有未确定行为源程序
还有一种类似情况是编写了未确定行为的源程序,以下例子属于未确定行为的情况。C语言标准中,char类型是带符号整数还是无符号整数类型,在语言规范中没有强制规定。也就是说,编译器可以将char类型解释为signed char类型,也可以将其解释为unsigned char类型。如果某个使用了char类型变量的程序在不同的系统中执行,很可能结果会不一样。
编译程序的后端应根据ISA规范和应用程序二进制接口(Application Binary Interface,ABI)规范进行设计实现。正如1.3.1节中提到,ISA是对指令系统的一种规定或体系结构规范,ISA定义了一台计算机可以执行的所有指令的集合、每条指令执行什么操作、所处理的操作数存放的地址空间以及操作数类型等。因为编译程序的后端将生成在目标机器中能够运行的机器目标代码,所以,它必须按照目标机器的ISA规范生成相应的机器目标代码。不符合ISA规范的目标代码将无法正确运行在根据该ISA规范而设计的计算机上。
ABI是为运行在特定ISA和特定操作系统之平台上的应用程序规定的一种机器级目标代码层接口,包含了运行在特定平台上的应用程序所对应的目标代码在生成时必须遵循的约定。ABI描述了应用程序和操作系统之间、应用程序和所调用的库之间、不同组成部分(如过程或函数)之间在较低层次上的机器级代码接口。例如,过程之间的调用约定(如参数和返回值如何传递等)、系统调用约定(系统调用的参数和调用号如何传递以及如何从用户态陷入操作系统内核等)、目标文件的二进制格式和函数库使用约定、机器中寄存器的使用规定、程序的虚拟地址空间划分等。不符合ABI规范的目标程序无法正确运行在根据该ABI规范提供的操作系统运行环境中。关于ABI规范的相关内容将在本书后续章节中以IA-32/x86-64+Linux运行平台为案例进行详细介绍。
ABI不同于应用程序编程接口(Application Programming Interface, API)。API定义了较高层次的源程序代码和库之间的接口,通常是与硬件无关的接口。因此,同样的源程序代码可以在支持相同API的任何系统中进行编译以生成目标代码。在ABI相同或兼容的系统上,一个已经编译好的目标代码可以无须改动而直接运行。
在ISA层之上,操作系统向应用程序提供的运行时环境需要符合ABI规范,同时,操作系统也需要根据ISA规范来使用硬件提供的接口,包括硬件提供的各种控制寄存器和状态寄存器、原子操作、中断机制、分段和分页存储管理部件等。如果操作系统没有按照ISA规范使用硬件接口,则无法提供操作系统的重要功能。
在ISA层之下,处理器设计时需要根据ISA规范来设计相应的硬件接口给操作系统和应用程序使用,不符合ISA规范的处理器设计将无法支撑操作系统和应用程序的正确运行。
总之,计算机系统能够按照程序员的预期正确地工作,是不同层次的多个规范共同相互支撑的结果,计算机系统的各抽象层之间如何进行转换,其实最终都是由这些规范来定义的。不管是系统软件开发者、应用程序开发者,还是处理器设计者,都必须以规范为准绳,也就是要以手册为准。计算机系统中的所有行为都是由各种手册确定的,计算机系统也是按照手册制造出来的。因此,如果想要了解程序的确切行为,最好的方法就是查手册。
小贴士
本书所用的平台为IA-32/x86-64+Linux+GCC+C语言,Linux操作系统下一般使用system V ABI,这里推荐以下三本电子手册作为参考。
C语言标准手册:http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf
system V ABI手册:http://www.sco.com/developers/devspecs/abi386-4.pdf
Intel架构i386手册:https://css.csail.mit.edu/6.858/2015/readings/i386.pdf
1.3.3 计算机系统的不同用户
计算机系统完成的所有任务都是通过执行程序所包含的指令来实现的。计算机系统由硬件和软件两部分组成,硬件(hardware)是物理装置的总称,人们看到的各种芯片、板卡、外设、电缆等都是计算机硬件。软件(software)包括运行在硬件上的程序和数据以及相关的文档。程序(program)是指挥计算机操作的一个指令序列,数据(data)是指令操作的对象。根据软件的用途,一般将软件分成系统软件和应用软件两大类。
系统软件(system software)包括为有效、安全地使用和管理计算机以及为开发和运行应用软件而提供的各种软件,介于计算机硬件与应用程序之间,它与具体应用关系不大。系统软件包括操作系统(如Windows、UNIX、Linux)、语言处理系统(如Visual Studio、GCC)、数据库管理系统(如Oracle)和各类实用程序(如磁盘碎片整理程序、备份程序)等。操作系统(Operating System, OS)主要用来管理整个计算机系统的资源,包括对它们进行调度、管理、监视和服务等,操作系统还提供计算机用户和硬件之间的人机交互界面,并提供对应用软件的底层支持。语言处理系统主要用于提供一个用高级语言编程的环境,包括源程序编辑、翻译、调试、链接、装入运行等功能。
应用软件(application software)指专门为数据处理、科学计算、事务管理、多媒体处理、工程设计以及过程控制等应用所编写的各类程序。例如,人们平时经常使用的电子邮件收发软件、多媒体播放软件、游戏软件、炒股软件、文字处理软件、电子表格软件、演示文稿制作软件等都是应用软件。
一个计算机系统可以认为是由各种硬件和各类软件采用层次化方式构建的分层系统,不同计算机用户工作所在的系统结构层如图1.12所示。
图1.12 计算机系统的层次化结构
从图1.12中可看出,ISA处于硬件和软件的交界面上,硬件所有的功能都由ISA集中体现,软件通过ISA在计算机上执行。因此,ISA是整个计算机系统中的核心部分。
ISA层下面是硬件部分,上面是软件部分。硬件部分包括CPU、主存(MM)和输入/输出(I/O)等主要功能部件,这些功能部件通过数字逻辑电路设计实现。软件部分包括低层的系统软件和高层的应用程序,汇编程序、编译程序和操作系统等这些系统软件直接在ISA上实现,系统程序员所看到的机器的属性是属于ISA层面的内容,所看到的机器是配置了指令系统的机器,称为机器语言机器,工作在该层次的程序员称为机器语言程序员;系统管理员工作在操作系统层,所看到的是配置了操作系统的虚拟机器,称为操作系统虚拟机;汇编语言程序员工作在提供汇编程序的虚拟机器级,所看到的机器称为汇编语言虚拟机;应用程序员大多工作在提供编译器或解释器等翻译程序的语言处理系统层,因此,应用程序员大多用高级语言编写程序,因而也称为高级语言程序员,所看到的虚拟机器称为高级语言虚拟机;最终用户则工作在最上面的应用程序层。
按照在计算机上完成任务的不同,可以把使用计算机的用户分成以下4类:最终用户、系统管理员、应用程序员和系统程序员。
使用应用软件完成特定任务的计算机用户称为最终用户(end user)。大多数计算机使用者都属于最终用户。例如,使用炒股软件的股民、玩计算机游戏的人、进行会计电算化处理的财会人员等。
系统管理员(system administrator)是指利用操作系统、数据库管理系统等软件提供的功能对系统进行配置、管理和维护,以建立高效合理的系统环境供计算机用户使用的操作人员。其职责主要有安装、配置和维护系统的硬件和软件,建立和管理用户账户,升级软件,备份和恢复业务系统及数据等。
应用程序员(application programmer)是指使用高级编程语言编制应用软件的程序员。系统程序员(system programmer)则是指设计和开发系统软件的程序员,如开发操作系统、编译器、数据库管理系统等系统软件的程序员。
很多情况下,同一个人可能既是最终用户,又是系统管理员,同时还是应用程序员或系统程序员。例如,对于一个计算机专业的学生来说,有时需要使用计算机玩游戏或网购物品,此时为最终用户的角色;有时需要整理计算机磁盘中的碎片、升级系统或备份数据,此时是系统管理员的角色;有时需要完成老师布置的一个应用程序的开发,此时是应用程序员的角色;有时可能还需要完成老师布置的操作系统或编译程序等软件的开发,此时是系统程序员的角色。
计算机系统采用层次化体系结构,不同用户工作在不同的系统结构层,所看到的计算机的概念性结构和功能特性是不同的。
1.最终用户
早期的计算机非常昂贵,只能由少数专业化人员使用。随着20世纪80年代初个人计算机的迅速普及以及20世纪90年代初多媒体计算机的广泛应用,特别是互联网技术的发展,计算机已经成为人们日常生活中的重要工具。人们利用计算机播放电影、玩游戏、炒股票、发邮件、查信息、聊天打电话等,计算机的应用无处不在。因而,许多普通人都成了计算机的最终用户。
计算机最终用户使用触摸屏、键盘和鼠标等外设与计算机交互,通过操作系统提供的用户界面启动执行应用程序或系统命令,从而完成用户任务。因此,最终用户能够感知到的只是系统提供的简单人机交互界面和安装在计算机中的相关应用程序。
2.系统管理员
相对于普通的计算机最终用户,系统管理员作为管理和维护计算机系统的专业人员,对计算机系统的了解要深入得多。系统管理员必须能够安装、配置与维护系统的硬件和软件,能建立和管理用户账户,需要时能升级硬件和软件,备份与恢复业务系统和数据等。也就是说,系统管理员应该非常熟悉操作系统或其他系统软件提供的有关系统配置和管理方面的功能,很多普通用户解决不了的问题,系统管理员必须能够解决。
因此,系统管理员能感知到的是系统中部分硬件层面、系统管理层面以及相关的实用程序和人机交互界面。
3.应用程序员
应用程序员大多使用高级程序设计语言编写程序。应用程序员所看到的计算机系统除了计算机硬件、操作系统提供的应用程序编程接口(API)、人机交互界面和实用程序外,还包括相应的编程语言处理系统。
在编程语言处理系统中,除了翻译程序外,通常还包括编辑程序、链接程序、装入程序以及将这些程序和工具集成在一起所构成的集成开发环境(Integrated Development Environment, IDE)等。此外,语言处理系统中还包括可供应用程序调用的各类函数库。
4.系统程序员
系统程序员开发操作系统、编译器和实用程序等系统软件时,需要熟悉计算机底层的相关硬件和系统结构,甚至可能需要直接与计算机硬件和指令系统打交道。比如,直接对各种控制寄存器、用户可见寄存器、I/O控制器等硬件进行控制和编程。因此,系统程序员不仅要熟悉应用程序员所用的所有语言和工具,还必须熟悉指令系统、机器结构和相关的机器功能特性,有时还要直接用汇编语言等低级语言编写程序代码。
在计算机技术中,一个存在的事物或概念从某个角度看似乎不存在,也即,对实际存在的事物或概念感觉不到,则称其为透明。通常,在一个计算机系统中,系统程序员所看到的底层机器级的概念性结构和功能特性对高级语言程序员(通常就是应用程序员)来说是透明的,也即看不见或感觉不到的。因为对应用程序员来说,他们直接用高级语言编程,不需要了解诸如汇编语言的编程问题,也不用了解机器语言中规定的指令格式、寻址方式、数据类型和格式等指令系统方面的问题。