转载请联系授权
01
从硬件到软件
之前我们把重点放在硬件 - 组成计算机的物理组件,比如电,电路,寄存器,RAM,ALU,CPU。但在硬件层面编程非常麻烦,所以程序员想要一种更通用的方法编程,一种"更软的"媒介,没错,我们要讲软件!
前面我们一步步讲了一个简单程序,第一条指令在内存地址 0:0010 1110,之前说过,前 4 位是操作码,简称 OPCODE。对于这个假设 CPU,0010 代表 LOAD_A 指令,把值从内存复制到寄存器 A,后 4 位是内存地址,1110 是十进制的 14。所以这 8 位表达的意思是 "读内存地址 14,放入寄存器 A"
只是用了两种不同语言,可以想成是英语和摩尔斯码的区别,"Hello" 和 ".... . .-.. .-.. —",都是"你好"的意思,只是编码方式不同。英语和摩尔斯码的复杂度也不同,英文有 26 个字母以及各种发音,摩尔斯码只有"点"和"线",但它们可以传达相同的信息,计算机语言也类似。
计算机能处理二进制,二进制是处理器的"母语",事实上,它们只能理解二进制,这叫"机器语言"或"机器码"。
02
伪代码
在计算机早期阶段,必须用机器码写程序,具体来讲,会先在纸上用英语写一个"高层次版"。
举例:"从内存取下一个销售额,然后加到天、周、年的总和,然后算税"等等...这种对程序的高层次描述,叫 "伪代码"。
在纸上写好后,用"操作码表"把伪代码转成二进制机器码,翻译完成后,程序可以喂入计算机并运行。
你可能猜到了,很快人们就厌烦了,所以在 1940~1950 年代,程序员开发出一种新语言, 更可读更高层次,每个操作码分配一个简单名字,叫"助记符"。"助记符"后面紧跟数据,形成完整指令。与其用 1 和 0 写代码,程序员可以写"LOAD_A 14"。我们在前面用过这个助记符,因为容易理解得多!
03
汇编器
当然,CPU 不知道 LOAD_A 14 是什么,它不能理解文字,只能理解二进制,所以程序员想了一个技巧,写二进制程序来帮忙,它可以读懂文字指令,自动转成二进制指令,这种程序叫汇编器。汇编器读取用"汇编语言"写的程序,然后转成"机器码","LOAD_A 14" 是一个汇编指令的例子。
随着时间推移,汇编器有越来越多功能,让编程更容易,其中一个功能是自动分析 JUMP 地址,这里有一个前面用过的例子:注意, JUMP NEGATIVE 指令跳到地址 5,JUMP 指令跳到地址 2。问题是,如果在程序开头多加一些代码,所有地址都会变,更新程序会很痛苦。
所以汇编器不用固定跳转地址,而是让你插入可跳转的标签。当程序被传入汇编器,汇编器会自己搞定跳转地址,程序员可以专心编程,不用管底层细节,隐藏不必要细节来做更复杂的工作,我们又提升了一层抽象。
然而,即使汇编器有这些厉害功能,比如自动跳转,汇编只是修饰了一下机器码。一般来说,一条汇编指令对应一条机器指令,所以汇编码和底层硬件的连接很紧密。
汇编器仍然强迫程序员思考 用什么寄存器和内存地址,如果你突然要一个额外的数,可能要改很多代码让我们想一想。