指令是如何执行的

比如我们设计一套指令集,其中肯定有条加法指令。比如Add R1 R2 。我们可以认为这条指令的意思是计算寄存器R1中的内容和R2的和,然后把结果存到R1寄存器中。
那么经过编译后这条指令会变成二进制,比如010100010010 。这条二进制指令一共12位。明显可以分为三大部分。最前面的0101表示这是条加法指令,后面0001说的是第一个操作数是寄存器1,最后0010说的是第二个数就是寄存器2(其实实际没有这么简单的指令,至少应该区分操作数是寄存器还是直接的数据,但为了把这说的更容易理解作了简化)。我们可以通过十二根导线把这条指令输入一个CPU中。导线通电就是1,不通电就是0 。为了叙述方便我们从左到右用A0-A11给这12根导线编上号。
然后计算机会分析这条指令。步骤如下:
  1. 最开始的两根导线A0和A1,第一根有电第二根没电,就能知道这是一条运算指令(而非存储器操作或者跳转等指令)。那么指令将被送入逻辑运算单元(ALU)去进行计算。其实很简单。只要这两根线控制接下来那部分电路开关即可。
  2. 接下来的A2和A3,01表示加法,那么就走加法运算那部分电路,关闭减法等运算电路。
  3. A4-A7将被送入寄存器电路,从中读取寄存器保存的值。送到ALU的第一个数据接口电路上。
  4. 后面的A8-A11同样被送入寄存器选择电路,接通R2寄存器,然后R2就把值送出来,放到ALU的第二个数据接口上。
  5. ALU开始运算,把两个接口电路上的数据加起来,然后输出。
  6. 最后结果又被送回R1。
基本上简单的运算计算机就是这么操作的。他其实不知道你那些指令都是什么意思。具体的指令编程机器码后就会变成数字电路的开关信号。其中某几段会作为控制信号,控制其他部分的数据走不同的电路以执行运算。他没有一个地方保存着如何翻译这些机器码的字典,所有机器码的意义都被体现在整个电路的设计中了。
当然,从汇编到机器码这步是汇编程序翻译的。汇编程序当然知道某条指令要翻译成什么样的机器码。

作者:青山牧云人
链接:https://www.zhihu.com/question/20793038/answer/115687100
来源:知乎
著作权归作者所有,转载请联系作者获得授权。

我们知道,现在指令集有CISC(复杂指令集)和RISC(精简指令集)。Windows只能跑在CISC上,而Linux即可以跑CISC,也可以跑RISC。

CISC架构的CPU上,加法运算指令:
MUL ADDRA, ADDRB
这条指令可以将ADDRA和ADDRB中的数相乘并将结果储存在ADDRA中。其中将ADDRA, ADDRB中的数据读入寄存器,相乘和将结果写回内存的操作全部依赖于CPU中设计的逻辑来实现。这种架构会增加CPU结构的复杂性和对CPU工艺的要求,但对于编译器的开发十分有利。比如上面的例子,C程序中的a*=b就可以直接编译为一条乘法指令。

RISC架构要求软件来指定各个操作步骤。上面的例子如果要在RISC架构上实现,将ADDRA, ADDRB中的数据读入寄存器,相乘和将结果写回内存的操作都必须由软件来实现,即:
MOV A, ADDRA;
MOV B, ADDRB;
MUL A, B;
STR ADDRA, A。
这种架构可以降低CPU的复杂性以及允许在同样的工艺水平下生产出功能更强大的CPU,但对于编译器的设计有更高的要求。

所以,通过比较CISC和RISC的不同,我们能看出CPU指令集就是上面总结的:
(汇编 --> 机器码 的这种“翻译规则”) + (CPU执行机器码的逻辑电路) = 指令集。

汇编是离机器码最近的一个人类可阅读可编写的语言形式。
机器(CPU)为了运算速度,被设计成只能阅读010101这样的文字的东西。
而人类不可能用0 和 1 ,来写程序,阅读和理解和修改起来太费劲了,效率太低。
所以最开始就有了汇编语言,人类用汇编语言来写人类看得懂的程序,例如:MOV AH,15
之后“编译器”这个程序会把人类编写的程序,翻译成CPU能理解的010101.........
通过编程语言建立起人类和CPU之间的翻译工作。
估计你以后会问为什么会用C语言编程很简单,C比汇编更加效率。


作者:Kaiser Li
链接:https://www.zhihu.com/question/22193700/answer/20599157
来源:知乎
著作权归作者所有,转载请联系作者获得授权。
作者:bombless
链接:https://www.zhihu.com/question/22193700/answer/20639515
来源:知乎
著作权归作者所有,转载请联系作者获得授权。

所以我说的3层是指这3层:机器码、CPU指令集还有汇编编程。以下将CPU指令集简称指令集。
汇编编程实际上最终面对的是机器码,那么为什么要涉及指令集这个玩意呢……因为指令集它不是数字序列。除了算术学家,没人想对着一堆数字思考。数学家喜欢符号。学生可能觉得符号望而生畏很难适应,那是因为他暂时还没意识到直接对着数字想那是有多困难。
当我们开始起名字的时候,数字就不单纯是数字了,所以我说指令集是一种抽象是一种理想。
我们在说汇编指令的时候提到CPU需要的是数字序列也就是机器码,这个转换过程叫汇编,我理解成“汇总、编辑”,汇总之前实际还涉及一些替换以及四则运算,这个我们也说过了。汇总的意思是,我们编写的这些CPU机器码的文字性表示也许分散在几个不同的地方,所以我们需要汇总起来。编辑的意思是,我们会在汇编指令之间(又或者是末尾或开头)插入一些标记,在转换成机器码之前它们需要适时换成此处的数字前总共有多少个数字,我们有一些汇编指令会需要这个数量。
那么我们为这个转换,也就说汇编,编写的工具叫做汇编器。汇编器的作者,他也不想只对着一堆数字思考。他参照指令集来考虑,实现这样一套工具。有了汇编器,我们就可以做汇编编程了,当然是照着这个汇编器的规则来编程。

那么,重点来了,为什么高级语言编译器要把源代码转成汇编指令呢。对于编译器作者有很多个理由可以这么做:
  1. 他也不想对着数字思考,反正汇编器作者已经受了一次罪了他就可以轻松了
  2. 有几个机器码形式不同的CPU需要他的编译器支持,他觉得这样可以省点功夫
  3. 只有一个CPU需要支持,但他怕领导未来让他支持其他CPU,所以先留点后路
  4. 他很同情他未来的同事,想着如果未来同事要支持不同的CPU,可以按照他的工作结果改,能轻松一些
  5. 领导没限制他这么做,他爱这么做就这么干了
  6. 领导叫他别这么做,他就爱跟领导对着干
那么我们也不能都怪罪干活的人,也许问题出在管理者: