18

据我了解,处理器电路因芯片而异,因此可能需要不同的低级指令来执行相同的高级代码。在成为原始机器代码之前,是否所有程序最终都转换为汇编语言,还是不再需要这一步?

如果是这样,处理器在什么时候开始执行自己独特的指令集?这是最底层的代码,那么此时程序指令是否由处理器逐位执行?

最后,所有架构都具有/需要汇编语言吗?

4

8 回答 8

21

可以说,汇编语言是一种人类可读的表达处理器执行指令的形式(它们是二进制数据,很难由人类管理)。因此,如果机器指令不是由人生成的,则不需要使用组装步骤,尽管有时确实会为了方便而发生。如果一个程序是用 C++ 等语言编译的,编译器可以直接生成机器码,而无需经过汇编代码的中间阶段。尽管如此,许多编译器仍提供生成汇编代码的选项,以便人们更容易检查生成的内容。

许多现代语言,例如 Java 和 C#,都被编译成所谓的字节码。这是 CPU 不直接执行的代码,而是一种中间形式,可以在程序执行时即时编译为机器码(JIT-ted)。在这种情况下,会生成依赖于 CPU 的机器代码,但通常不需要经过人类可读的汇编代码。

于 2013-09-26T18:31:06.007 回答
7

汇编语言只是原始机器代码的人类可读的文本表示。它的存在是为了(人类)程序员的利益。它根本不需要作为生成机器代码的中间步骤。一些编译器确实会生成汇编,然后调用汇编器将其转换为机器代码。但是由于省略该步骤会导致更快的编译(并且并不难做到),编译器将(广义上)倾向于直接生成机器代码。但是,可以选择编译为汇编,以检查结果。

对于您的最后一个问题,汇编语言是一种人类便利,因此没有架构真正需要它。如果你真的想要,你可以创建一个没有架构的架构。但实际上,所有架构都有汇编语言。首先,创建一种新的汇编语言非常容易:为所有机器操作码和寄存器指定一个文本名称,添加一些语法来表示不同的寻址模式,并且您已经完成了大部分工作。即使所有代码都直接从高级语言直接转换为机器语言,如果只是在寻找编译器错误等时作为反汇编和可视化机器代码的一种方式,您仍然需要汇编语言。

于 2013-09-26T18:34:42.497 回答
5

每个通用 CPU 都有自己的指令集。也就是说,某些字节序列在执行时会对寄存器和内存产生众所周知的、有记录的影响。汇编语言是一种写下这些指令的便捷方式,这样人们就可以阅读和编写它们并理解它们所做的事情,而无需一直查找命令。可以相当肯定地说,对于每个现代CPU,都存在一种汇编语言。

现在,关于程序是否转换为汇编。让我们首先说 CPU 不执行汇编代码。它执行机器代码,机器代码命令和装配线之间是一一对应的。只要您牢记这一区别,您就可以说“现在 CPU 执行 MOV,然后执行 ADD”等等。当然,CPU 执行对应于 MOV 命令的机器代码。

也就是说,如果您的语言编译为本机代码,那么您的程序确实会在执行之前转换为机器代码。一些编译器(不是全部)通过发出汇编源代码并让汇编器完成最后一步来做到这一点。此步骤(如果存在)通常被很好地隐藏。程序集表示仅在编译过程中存在很短的时间,除非您告诉编译器保持它完好无损。

其他编译器不使用汇编步骤,但会在被要求时发出汇编。例如,Microsoft C++ 采用选项 /FA - 将程序集列表与目标文件一起发出。

如果它是一种解释性语言,那么就没有显式转换为机器。源代码行由语言解释器执行。面向字节码的语言(Java、Visual Basic)介于两者之间。它们被编译为与机器代码不同的代码,但比高级源代码更容易解​​释。对于那些,可以说它们没有转换为机器代码也是公平的。

于 2013-09-26T18:44:22.177 回答
1

这是一个相当大的兔子洞,你正在往下看。

话虽如此,不,并非所有程序都变成了汇编语言。如果我们排除即时编译,像 ruby​​、lisp 和 python 这样的解释性语言,以及像 java 和 c# 这样在虚拟机 (VM) 上运行的程序都不会变成汇编。而是有一个现有的程序,一个解释器或虚拟机,它接收源(解释)或字节码(VM)(不是您计算机的汇编语言)并运行它们。当解释器看到特定的输入序列并采取正确的行动时,它知道该怎么做,即使它以前没有看到那个特定的输入。

编译的程序,就像你用 C 或 C++ 编写的一样,作为编译过程的一部分,可以变成汇编语言,然后再变成机器语言。通常会跳过此步骤以加快速度。一些编译器(如 LLVM)输出通用位码,因此它们可以将生成位码的编译器部分与将位码转换为机器码的部分分开,从而允许跨架构重用。

然而,尽管操作系统将 CPU 视为消耗机器代码的东西,但许多 CPU 具有较低级别的微代码。指令集中的每条指令(汇编级)由 CPU 实现为更简单的微代码操作序列。跨 CPU 的指令集可以保持不变,而实现指令的微代码会发生变化。将指令集视为 CPU 的 API。

于 2013-09-26T18:34:56.117 回答
1

所有处理器都在位上运行,我们称之为机器代码,并且由于不同的原因,它可以呈现出非常不同的风格,从而为专利保护思想构建了一个更好的鼠标陷阱。从用户的角度来看,每个处理器都使用某种机器代码,有些处理器在内部将其转换为微码、另一种机器代码,而另一些则不使用。当您听到 x86 vs arm vs mips vs power pc 时,这不仅仅是公司名称,而且它们也有自己的指令集,机器代码,用于各自的处理器。x86 指令集虽然在不断发展,但仍然与它们的历史相似,您可以轻松地从其他指令集中挑选出 x86 代码。对于所有公司来说都是如此,您可以在 mips 和 arm in arm 中看到 mips 的遗产,等等。

因此,要在某个时候在处理器上运行程序,必须将其转换为该处理器的机器代码,然后处理器才能处理它。各种语言和工具以各种方式完成。从高级语言编译成汇编语言不需要编译器,但很方便。首先,无论如何,您基本上都需要该处理器的汇编程序,因此该工具就在那里。其次,通过查看人类可读的汇编语言而不是机器代码的位和字节,可以更容易地调试编译器。一些编译器,如 JAVA、python,旧的 pascal 编译器有一个通用的机器代码(每种语言都有自己不同的机器代码),通用的意思是 x86 上的 java 和 arm 上的 java 在这一点上做同样的事情,然后有是特定于目标的(x86、arm、mips) 解释器,它解码通用字节码并在本机处理器上执行它。但最终它必须是运行它的处理器的机器代码。

这些编译层的这种方法也有一些历史,我认为这是有点 unix 构建块的方法,让一个块做前端,另一个块做后端并输出 asm,然后对象的 asm 是它自己的工具和与他人链接的对象是它自己的工具。每个块都可以通过受控的输入和输出来包含和开发,并且有时可以替换为适合同一位置的另一个块。编译器类教授此模型,因此您将看到新编译器和新语言复制了该模型。解析前端,高级语言的文本。转换为中间的、编译器特定的二进制代码,然后在后端获取该内部代码并将其转换为目标处理器的程序集,允许例如使用 gcc 和许多其他人来更改该后端,以便可以将前端和中间用于不同的目标。然后分别有一个汇编器,还有一个单独的链接器,单独的工具。

人们一直在尝试重新发明键盘和鼠标,但人们对旧方法感到满意,即使新发明更好,他们也会坚持下去。编译器和操作系统也是如此,还有许多其他事情,我们使用我们所知道的以及它们经常编译为汇编语言的编译器。

于 2013-09-26T18:51:57.157 回答
0

基本上是的,Java 的汇编称为字节码,任何芯片的微架构都会有一个由汇编指令或类似内容组成的ISA,而相同的 ISA 可以在许多不同的芯片上实现。如果您学习 MIPS,这是一个很好的介绍,这样您就可以了解编译器如何将 C 转换为 MIPS。然后,您可以看到 MIPS 指令如何转换为机器代码,并且该机器代码将具有到将执行该指令的ALU的操作码。有关更多信息,您可以阅读 Hennessy / Patterson,他们撰写了两本关于计算机硬件的好书:“计算机组织与设计”和“计算机体系结构 - 定量方法”

于 2013-09-26T18:31:42.637 回答
0

生成本机机器代码的编译器确实会生成适当的汇编语言,然后将其汇编成机器代码。这通常在一个步骤中完成,但一些编译器,如 GCC,也可以输出中间程序集。

您是正确的,因为不同的架构具有不同的指令集。利用这些差异是编译器如何为一个或另一个处理器优化可执行文件。

于 2013-09-26T18:34:46.433 回答
-1

以下是一些可能会让您感到困惑的事情:

  • 所有的程序都必须转换成机器指令,因为那是机器执行的。
  • 汇编语言是一种低级编程语言,几乎与机器指令一一对应。
  • 程序可以编译为机器指令,也可以解释为由解释器执行的机器指令。
  • 程序通常不会转换为汇编语言,因为这需要将汇编语言转换为机器指令。我似乎想起了一些非常古老的编译器,它们产生了汇编语言,但我知道今天没有理由做那种事情。
  • 机器有多种方式来执行机器指令。它们可能是硬连线的,也可能使用微码。我怀疑几乎所有现代 CPU 都使用微码。这确实是一种魔法。
于 2013-09-26T18:59:06.480 回答