全部博文(465)
分类: Delphi
2012-11-16 09:06:50
处理器本身能理解的机器指令是0和1的序列,让人来写就要大费周章了,因此人们一直在努力开发各种系统,用人类易于理解的形式来编写程序。本节仅简单介绍一下指示处理器工作的机器语言程序的编写方法。
用汇编语言编程
人类很难书写处理器能够理解的0、1序列,也很容易出错。另外,写完后回头看看一堆0和1,根本看不懂会向处理器发出什么指令,即使出了bug、无法正常运行也毫无办法。
因此,我们将加法指令写成ADD,减法指令写成SUB(Subtract),从内存读取数据的加载指令写成LD(Load),向内存写入数据的存储指令写成ST(Store)。这种易于人类理解的写法称为助记符(Mnemonic)。另外,这些指令使用的操作数也可以采用便于人类理解的写法来指定。
利用这些易于人类理解的符号编写程序,再通过汇编器(Assembler)软件,就能转换成机器指令。这种形式的程序叫做“汇编程序”,有时简称汇编。
不过,尽管这样易于人类书写也容易看懂,但是实质上还是得逐条书写机器指令。例如,把A加B的结果放入C,就要按照以下步骤计算。
LD R1, [A] 从保存数据A的内存中读取数据放入R1
LD R2, [B] 从保存数据B的内存中读取数据放入R2
ADD R3, R1, R2 R1和R2的内容相加,结果放入R3
ST [C], R3 将R3的内容写入保存数据C的内存地址中
这里的R1、R2、R3是寄存器(Register),处理器利用它们在计算等操作中保存临时数据。
用汇编语言编程有时也叫做机器语言编程,但毕竟不是直接写0和1,严格来说并不是用机器指令编程。
另外,利用汇编器转换成机器指令后,就是比特序列而已,所以能够像数据一样从输入设备读取到内存中。将程序读入内存的操作称为“加载程序”。
利用编译器进行高级语言编程
为了让编程更方便,人们设想了如下方案:将上述计算写成C=A+B这种人类熟知的形式(即高级编程语言),用这种形式编写程序,再通过编译器(Compiler)转换为汇编程序(图1.17左图)。另外,通常将程序分为主程序与多个子程序的集合,这时需要对主程序和每个子程序分别编译、汇编后(图1.17),用链接器(Linker)合成一个机器语言程序。
图1.17 利用编译器和汇编器翻译程序
1954年,IBM的John Backus发明了面向科学技术计算的FORTRAN语言,并编写了编译器。后来FORTRAN语言增加了许多功能,即便是现在也被用于科学技术计算程序的开发。
1972年,Bell研究所的研究员Dennis Ritchie构思了C语言并开发了C语言编译器,用来编写UNIX操作系统。后来C语言吸收了面向对象的思想,衍生出了C++、C#等语言,成为现在的主要高级编程语言之一。
优化
将高级语言程序翻译成汇编或机器指令时,C=A+B就会被转换成上文中的汇编形式。然而,如果程序预先将A或B保存到了某个寄存器,那就不需要重新从内存读入。另外,ADD的结果如果仅在紧随其后的指令中使用,那就不需要保存到内存中,而是通过寄存器直接传给下一条指令,这样就能运行得更快。像这样根据上下文环境省略不必要的操作以生成运行更快的汇编程序,称为优化(Optimization)。
编译高级语言程序时,可以指示编译器怎样优化、优化到什么程度。一般而言,最初的调试阶段不进行优化,调试阶段完成后将编译选项设置为-O2或-O3表示尽量进行优化,以提高性能。
* * *
现在,几乎所有的程序都用高级语言编写,再利用编译器和汇编器转换成机器指令。不过,操作系统的某些部分及控制输入/输出设备的硬件操作无法用高级语言表达,所以汇编程序也有用武之地。
解释语言编程
乍一看,解释语言编程跟使用编译器很相似,但它不会对字符串写成的高级语言程序进行编译、汇编等操作,而是在执行时解释程序内容,执行相应的机器指令序列以完成规定的C=A+B等操作。这种方式称为解释(Interpreter)语言。
编程语言中的Java、Ruby等就是解释语言,Windows的批处理文件、UNIX、Linux的Shell脚本也可以算做解释语言。
解释语言在运行时进行编译,将源代码转换成机器指令,因此执行性能并不高,但由于无须在编译、汇编上花费工夫就可以执行程序,修改程序后也不用重新编译、汇编,非常方便,所以应用也很广泛。
编译器和解释器的输入都是硬件无关的高级语言,但编译器的输出结果是汇编程序,或与汇编程序一一对应的机器指令,所以编译结果无法在其他指令架构的处理器上运行。相反,解释程序将高级语言字符串原封不动地作为输入执行程序,因此只要运行程序的计算机系统安装了Java、Ruby等解释器,那么无论哪种指令架构的计算机,都可以正常执行Java和Ruby程序,而无须为不同指令架构准备不同的二进制程序,具有省时省力的优势。
JIT编译
随着解释程序的增多,解释程序的性能改善也变得势在必行,于是出现了JIT编译(Just In Time Compile)的方式(图1.18),在运行时将程序中反复执行的部分转换为机器语言。JIT编译方式,首先解释执行字符串形式的高级语言程序,一旦发现反复执行的部分,就在运行过程中编译这部分,转换成执行效率较高的机器指令。
1.18 拥有JIT编译功能的解释器执行源程序的方式
也就是说,对程序中运行频率较低的部分采用解释方式边解释边运行,而将运行频率较高的部分编译成机器语言以提高执行效率。程序本身仍然是字符串,不会变成机器指令序列,所以它依然保留了与处理器指令构架无关的优点,只要安装了相应语言的处理程序,程序就能正常运行。
但是,即使是运行频率很高的部分,在判断出重复执行之前,只能根据字符串解释运行。此外,JIT编译器会增加编译时间,所以一般来说性能不如编译器编译出的机器指令。但由于它不依赖于处理器架构,所以在商业骨干系统中也得到了应用。