《汇编程序设计与计算机体系结构:软件工程师教程》 —1.3.2 翻译流水线
1.3.2 翻译流水线
现在要来演示从高级到低级的处理过程。为了讲解得直观一些,大家可以把该过程想象成一条翻译流水线(translation pipeline),如图1-2所示。
提示:一种较为抽象的讲解方式是用虚拟机(virtual machine)这个概念来演示计算机体系结构中的各个层面,很多经典的范例都用到了它,你在读别的教科书或是听人讲解多层设计时,或许也会遇到这个说法。虚拟机可以用硬件或软件的方式实现。
用高级语言编写的程序必须经过翻译才能在底层运行。翻译有两种办法:一种是解释(interpreting),就是在执行程序的过程中翻译一行运行一行;另一种是编译(compiling),就是先把所有代码全都翻译完,然后再执行。Python 是解释型的高级编程语言,C++ 是编译型的高级编程语言。
高级语言里的一条语句(例如 x - y + 2)翻译成机器语言后通常会变成多条语句,也就是说,高级语言中的一条语句会翻译成好几条汇编指令或机器指令。
汇编语言是翻译流水线里的一个中间环节。用高级语言写的程序先翻译成汇编代码,然后再根据处理器的指令集架构翻译成机器语言。把汇编代码翻译成机器语言的过程通常称为编码(encoding),反向的过程,也就是把机器码翻译成汇编语言的过程,通常称为解码(decoding)。
汇编语言的语句与机器语言之间是一一对应的,这意味着,每一条汇编语言指令都对应于一条机器语言指令。后者通常用十六进制等中介的数值形式来表示,然后翻译为二进制,以便在物理硬件上实现,这就是数字逻辑(digital logic)。
编程知识:有一些编译器,例如 Microsoft 的 C 语言编译器,能够把用高级语言写成的代码直接翻译为机器语言,中间是否生成汇编码可以通过选项来控制。另一些编译器,例如 GCC,则要先翻译成汇编码,然后再翻译为机器代码。
指令集架构(Instruction Set Architecture,ISA)是计算机体系结构中与编程有关的方面。它指出了处理器所具备的指令、寄存器、内存架构、数据类型以及其他一些属性,以供程序员使用。你可以把 ISA 理解成计算机所说的语言,它能够促进软件与硬件之间的通信,见图 1-3。
图1-3 指令集架构
指令集架构分为复杂与精简两种。复杂指令集(Complex Instruction Set Computing,CISC)架构中的指令,其长度(也就是表示该指令所需的字节数)不固定。之所以说它复杂,是因为一条指令有可能要完成多项任务,比方说,既要访问某个内存地址,又要执行算术运算。与之相对的ISA设计称为精简指令集(Reduced Instruction Set Computing,RISC),其中的所有指令都一样长,而且只执行一项任务(例如只访问某个内存地址,不做其他的事情)。
x86 与 x86_64都是 CISC 架构,而其他一些 ISA 设计方案则多为 RISC 架构。第4、5两章会详细讨论 x86 指令,那时你就会明白它为什么叫复杂指令集。此外,第6、11章会提供一些反汇编的例子,这些例子能够显示出指令的长度不固定以及指令所执行的任务较为复杂这两项特点。本章后面的编程知识会提到可重定位的机器语言。
编程知识:反汇编是由反汇编器对包含机器语言的目标文件进行解码之后所输出的汇编代码,这实际上相当于把机器语言的二进制序列解码成汇编指令。大多数汇编器、编译器、调试器以及开发环境都提供反汇编功能,例如 NASM(ndisasm)、GDB、LLVM、Xcode 以及 Visual Studio。还有一些独立的反汇编器可供使用,像是 Capstone、IDA、objdump 与 otool。如何对目标文件做反汇编,请参阅本书附录C。
提示:32 位版的 x86 指令集通常称为 IA-32,此外也叫作 i386。64 位版的 x86 指令集通常称为 x64 或 x86_64,不过制造商也有可能使用其他一些叫法。请注意,64 位版的 x86与 64 位的 Intel Architecture(简称 IA-64)是两种完全不同的架构,后者是 Itanium(安腾)系列处理器所用的指令集,它与 IA-32 及 x64 均不兼容。
表1-1举例说明了翻译流水线。先假设有一个名为 sum 的整数,然后用高级语言 C++ 编写一行代码,也就是 sum = 5;。接下来,用 GNU Assembler(GAS)将其翻译成遵循 AT&T 语法规则的汇编代码,进而根据 IA-32 指令集架构,把它翻译成机器语言,令其可以在 Intel 32 位处理器上执行。最后,以二进制的形式对十六进制形式的机器语言指令做物理实现(或者说数字实现)。
表1-1 翻译流水线
接下来再看三行代码,以巩固这种印象。范例1-2主要是想让大家明白汇编语言需要编码成对应的机器语言,而至于具体怎样对应则不是此处的重点。第4、5两章会详细讲解这些指令。
假设有一条 32 位的汇编指令: MOV eax, 5。如果用高级语言来表达该指令的意思,那么写出来的代码可能类似于 variable = 5;,然而从汇编语言的角度来看,这条指令强调的是:把立即值5移动(或者说复制)到 eax 寄存器里。MOV操作码与eax寄存器都是 IA-32 指令集架构的一部分。像这种把某个立即值移动到 eax 寄存器中的操作方式,是与特定的机器语言相对应的,具体来说,就是会编码成十六进制形式的B8,而作为操作数的立即值也会加以编码,并出现在 B8 的后面。
范例1-2 把汇编指令编码成 IA-32 架构的机器语言
由于机器语言要用数字的形式来表示,因此,我们应该理解各种计数系统(number system,或者说数制),尤其是十六进制与二进制。机器语言是针对特定的处理器而言的,不过,同一个系列的处理器能够解读同一种机器语言,因此,针对 x86 处理器所写的代码可以用在该系列的任何一款处理器上,x86_64 也是如此。
编程知识:汇编代码无法在不同系列的处理器之间移植。比方说,针对 x86 系列的处理器所写的代码,无法在 SUN Sparc、IBM 370 以及 ARM Cortex 等系列的处理器上执行。
x86/x86_64处理器家族,既包括 Intel 的 Pentium、Core-Duo 及 Core i7,也包括 AMD 的 Athlon、Phenom 及 Opteron。Intel 与 AMD 的处理器设计方案都实现了 x86 指令集,但实现该指令集所用的具体技术(也就是微架构,microarchitecture)却有所不同。
- 点赞
- 收藏
- 关注作者
评论(0)