图说 WebAssembly(三):什么是汇编
本文是图说 WebAssembly 系列文章的第三篇。如果您还未阅读之前的文章,建议您从第一篇入手。
为了更好的理解 WebAssembly ,我们有必要去先理解什么是汇编(Assembly),以及编译器是如何产生汇编的。
因为 WebAssembly 在浏览器中的作用跟汇编类似,这也是为什么 WebAssembly 称为 WebAssembly 的原因。
在上一篇文章中,我们提到,我们跟计算机的交流就像是跟外星人的交流。
什么是汇编
现在,我们来看看外星人的大脑是如何工作的。类比一下就是,计算机的大脑如何分析并理解我们跟它交流的内容。
计算机的大脑中有一块区域是专门负责思考的,这个思考就是我们所说的加法、减法和其他逻辑操作。
在这个区域的附近,也有一块区域是负责短期记忆的。当然,相对的,也存在负责长期记忆的区域。
人类给这些区域分别取了独特的名字:
- 负责思考的区域称为算术逻辑单元(Arithmetic-logic Unit, ALU)
- 负责短期记忆的区域称为寄存器(Register)
- 负责长期记忆的区域称为随机存储器(Random Access Memory, RAM),也就是内存
机器语言中的句子我们把它称为指令。
当这些指令传给计算机的大脑时会发生什么呢?
计算机会把指令拆分成不同的部分,每部分都有它们自己独特的含义。
计算机拆分指令的方式跟计算机大脑内部的实现相关。
举例来说,一种实现方式可能总是取出最开始的 6 位数据,并把它送给 ALU。
然后, ALU 根据这些 0 和 1 发现,原来它的意思是要把两个整数加起来。
我们把这 6 位数据组成的数据块称为操作码(Operation Code),因为告诉 ALU 需要做什么操作。
当计算机大脑知道是要做加法操作后,它会把接下来的两个 3 位数据块取出来,以此来定位是哪两个数要相加。取出的两个 3 位数据块对应的就是寄存器的地址,寄存器中保存的数据就是待相加的整数。
注意上图中我们对机器码的注释,根据这些注释人类可以很简单地明白其中发生了什么。
这些注释就是汇编,也称为符号机器码。它是人类把机器码变成可直接阅读的方式。
汇编的生成
你可能已经发现,汇编跟该机器的机器码有着相当直接的关系。比如上面说的 6 位、3 位数据块等,换一台机器可能就变成了 7 位、4 位等。
因此,实际上有很多种不同的汇编,分别对应不同的计算机架构。当你有一台不同架构的计算机时,很可能你就得使用它专有的汇编。
所以,我们的翻译目标不止一个。
它并不仅仅是一种称为机器码的语言,而是多种不同的机器码。这就像不同国家的人们说不同的语言一样,不同架构的计算机也使用不同的机器语言。
在人类和外星人之间的语言翻译中,你可能要从英语、或者俄语、或者汉语翻译为外星语 A、或者外星语 B。
编程语言领域也一样,我们需要把 C、C++、Rust 翻译为 x86 或者 ARM 架构的汇编。
对应不同架构的计算机,我们需要一种能够把任何一种高级编程语言翻译为不同汇编的能力。
其中一种办法就是创建所有可能的映射关系,然后实现每种语言到每种汇编的翻译。
但这种方法是相当低效的。为了提升效率,大多数的编译器都会在两者之间新增一个中间层。
这种编译器会把高级编程语言翻译成一种介于高级语言和机器码之间的中间产物,称为中间代码(Intermediate Representation,IR)。
这样的话,编译器就可以接受任何一种高级语言,然后把它翻译成中间代码。
之后,编译器的另一部分再把中间代码变成特定架构计算机的汇编。
按照中间代码的生成可以把编译编译流程划分为前端和后端。
编译器前端接收高级编程语言,输出中间代码;编译器后端则是接收中间代码,输出目标架构的汇编代码。
结束
以上的内容就是什么是汇编以及它是如何从高级编程语言翻译过来的。
在下一篇文章中,我们将看到 WebAssembly 是如何生成的。