本文是操作系统系列的第二篇,以下是文章目录
浅入理解计算机系统(1)- 操作系统的两个基本功能和三个抽象概念
浅入理解计算机系统(2)- 程序的机器级表示
浅入理解计算机系统(3)- RAM和ROM,处理器和主存的那些事
本章篇幅较短,因为机器代码比较晦涩难懂,例如,逻辑操作、控制切换、过程等,难以用简短的描述出来,所以只提及一些基本概念。
计算机只“认得”机器代码,过去人们使用汇编语言来指定程序用来执行计算的低级指令,而现在大多数情况下会选择高级语言(如C,Java等)编程。高级语言有着较高级别的抽象,代码更易读、易写,在这种抽象等级下的工作效率会更高、更有效。除此之外,编译器提供的类型检查帮助在运行前发现程序错误,并且保证按一致的方式来引用和处理数据。
抽象级别(由高到低)
高级语言(如C,Java等)
编译器承担了生成汇编代码的大部分工作。高级语言最大的优点是,其编写的语言可以在很多不同的机器上编译和执行,而汇编代码与特定机器密切相关。
汇编代码
以C语言为例,汇编器与链接器协作根据汇编代码生成可执行的机器代码。
机器代码
机器执行的程序只是一个字节序列,是对一系列指令的编码,机器本身对产生这些指令的源代码几乎一无所知。一条机器指令只执行一个非常基本的操作,例如,将存放在寄存器的两个数据相加,在存储器和寄存器之间传送数据,或是条件分支转移到新的指令地址。
C语言提供了一种模型,可以在内存中声明和分配各种数据类型的对象,但机器代码只是简单地将内存看作一个很大的、按字节寻址的数组。C语言中的聚合数据类型,如数组和结构,在机器代码中用一组连续的字节来表示。
寄存器
一个x86-64的中央处理单元(CPU)包含一组16个存储64位值的通用目的寄存器。这些寄存器用来存储整数数据和指针。在常见的程序里不同的寄存器扮演着不同的角色,其中最特别的是栈指针 %rsp,用来指明运行时栈的结束位置,有些程序会明确地读写这个寄存器,另外十五个寄存器的用法更灵活,少量指令会使用特定的寄存器。十六个寄存器如下图所示:
图来源《深入理解计算机系统》
源数据类型
大多数指令有一个或多个操作数,指示出执行一个操作中要使用到的源数据值,以及放置结果的目的位置。
源数据值可以以常数形式给出,或是从寄存器或内存中读取。结果可以存放在寄存器或内存中。因此,各种不同的操作数被分为三种类型。
立即数(immediate)
用来表示常数值
寄存器(register)
表示某个寄存器的内容,16个寄存器的低位1字节、2字节、4字节或8字节中的一个作为操作数,这些字节数分别对应8位、16位、32位或64位。
内存引用
根据计算出来的地址(通常称为有效地址)访问内存中的某个位置。
总结
机器级程序和它的汇编代码表示,与C程序的差别很大。各种数据类型之间的差别很小。程序是以指令序列来表示的,每条指令都完成一个单独的操作。部分程序状态、如寄存器和运行时栈,对程序员来说是直接可见的。
本文内容源自《深入理解计算机系统 第三版》以及本文作者的个人理解补充,只涉及一些个人认为重要概念描述和协作原理的简单描述,并不深入剖析每一个点。
如果有不准确或者错误的地方欢迎评论指出。
感谢你的阅读。