字节码和汇编语言是一回事吗?

时间:2016-08-22 16:00:54

标签: assembly virtual-machine bytecode cil machine-code

问题可能看起来很奇怪,但我仍然试图掌握虚拟机的概念。我已经阅读了几个答案,但是如果Java字节码(以及MSIL)与汇编语言相同,我仍然无法得到。据我所知,字节码和汇编都被编译成机器码,因此就抽象而言,它们处于同一级别,即比机器码高出一步。字节码也只是汇编语言,即人类可读的机器代码形式。如果是,那么为什么仍然使用汇编语言?为什么不用字节码(可以在不同的机器上移植)而不是汇编语言(特定于单个机器架构)进行编程?感谢

4 个答案:

答案 0 :(得分:4)

没有

Java字节码是二进制编程语言,不是“人类可读的形式”,除非您考虑数字串可读,或者您使用反汇编程序将其反转为字节码文本助记符,或最终将Java源代码形式本身。

汇编通常是目标机器实际指令的文本助记符,相互之间以1:1映射,因此汇编源代码中的一条指令将直接转换为一条机器代码指令(尽管某些CPU和汇编程序存在一些例外情况,例如,许多RISC汇编程序会根据需要将“带有立即值的加载寄存器”转换为多个指令 - 加载任何立即值,而本机机器代码只能加载特定位,并且您必须通过几条指令组合整个值)

与大多数CPU机器代码相比,Java字节码是相当高级的抽象语言,具有非常微小的指令和内存模型重叠。唯一的相似之处是,字节码以二进制形式存储,就像机器码一样。

编辑:

JVM原则上是解释器,即。它将字节码即时转换为机器码。这就是编译器在编译期间由其他语言完成的事情。

现代JVM不是经典的纯解释器,而是使用“JIT”(Just In Time)编译器将小块的java字节码编译成本机机器码,就在它执行之前,使用缓存来避免已知的二次编译.class文件,还使用性能数据的运行时跟踪来更好地指示JIT编译器,哪些字节码应该大量优化(经常运行或内部循环),哪些应该尽快编译,而不关注性能。

因此,对于现代JVM来说,很难谈论解释器,它是非常复杂和复杂的解决方案。 C#经常更进一步,有时会将部分二进制文件预先编译为常见平台的机器代码(将字节码形式仅作为非常见平台的后备)。

机器代码中没有这些(甚至不类似)。它只是在CPU上执行。

答案 1 :(得分:2)

汇编语言是一种人类可读的文本语言,旨在组装成二进制文件。每个源行直接映射到一个二进制输出块(例如,一个可变长度x86指令),而不依赖于前一行。 (我不确定Java字节码asm是否与上下文相关;我还没有使用过它。)

e.g。 mov eax, 1234汇总到相同的5个字节,无论其他源线是否包围它。 (当然,忽略命名常量和汇编程序宏)。

"汇编语言"的默认含义(描述标签wiki的那个)是CPU机器代码汇编语言,其中汇编到输出文件中的字节是用于某种CPU /微处理器的本机可执行文件的指令和数据。

存在其他类型的汇编语言,例如java字节码汇编,其中汇编到输出文件中的字节是Java .class格式,并且可以由JVM运行。 (@ Ped7g的答案扩展到这一点,关于JVM如何在将Java字节码转换为本机机器代码时进行优化。这个过程绝对不像汇编。)

它只是文本语言,使汇编程序将字节汇编到输出文件

您可以使用任何类型的二进制文件格式的汇编语言,甚至是非可执行文件格式。一个简单的示例:位图静止图像文件格式的汇编语言,您可以在其中为每个像素使用命名颜色(如midnight blue)。汇编器会将位(而不是像普通汇编语言一样的整个字节)组装到输出文件中。

在更复杂的情况下,您可以想象一种H.264汇编语言,您可以使用文本语法来描述标题和每个宏块的编码。

在这种情况下,您可以设计汇编程序将汇编的宏块数据的最终CABAC或CAVLC压缩到比特流中,而不是将其描述为汇编语言的一部分。它就像一个生成gzipped二进制文件的x86汇编程序:组装成一个deflate流。

汇编语言的一个关键特性是它足够接近机器代码格式,反汇编程序可以将二进制文件转换回asm,看起来就像首先组装的那样(但当然没有任何评论,标签名称或宏)。

这就是为什么C和Java被认为是比编译器生成的二进制/汇编更高级语言的原因。

答案 2 :(得分:1)

我明白了你的观点,如果你眯眼,让事情变得有些模糊,那么绝对是的。 JAVA字节码和Pythons等效,Pascals和其他一些可能只是机器代码定义,它们的编译器编译成该机器代码。并且该机器代码在机器上本机运行。到目前为止,这些机器都是虚拟的,并且可能总是这样,这是你从其他人那里得到的回击。

汇编是人类可读形式的机器代码,其中的位和字节不容易被我们阅读,但很容易被机器读取。

JAVA等,机器代码部分只是另一个指令集,还有其他基于堆栈的指令集直接在硬件中实现,它是一种非常简单的指令集通用方法。但它们有一些高级系统调用,甚至高于CISC,这就是在逻辑中实现它们的问题所在。没有理由甚至微写这样的东西,你接近它的方式是使用本机指令集创建一个虚拟机(最有可能从非JAVA高级语言编译)。

如果真的只是另一个指令集那么绝对可以为此创建硅片。但即使你可以,这并不意味着我们应该放弃我们拥有的所有其他指令集。对于初学者来说,JAVA工具似乎很自豪他们没有优化。所以你从缓慢的程序开始,只让它们更快一点。当本机硬件上的其他语言在资源和能源上的成本要低得多。发明者希望这样做,让我们相信它发生了,ARM Jazelle和其他人。在ARM Jazelle的情况下,硅片采用逻辑中的字节,但它在一个由本机机器码组成的表中查找。声称Jazelle支持的ARM处理器是虚假的,因为您必须从ARM购买软件blob以使其工作,并且任何数量的其他JVM实际上比付费的ARM Jazelle软件更快,更有效(有时是免费的)。所以这是一次失败,无论如何都是假的。

是的,它是一种编译成机器代码的语言。该机器代码在机器上执行。不同之处在于那些机器是虚拟的,没有在硅片中实现(就像在微处理器上实现的机器代码那样,(笑)),而且很可能不会。

答案 3 :(得分:0)

字节码和汇编语言不是相同的东西,但是它们是紧密相关的东西。

字节码是简化的 binary (二进制)语言,类似于机器代码。字节码规范描述了应如何编码程序,以确保虚拟机正确理解并执行该程序。以相同的方式,处理器规范描述了所谓的指令集体系结构(ISA),该指令集体系结构显示了应如何在 binary 机器代码中对程序进行编码,以确保处理器正确理解并执行该程序。因此,字节码是程序的机器友好表示,以位顺序表示。

字节码的问题是,尽管它在处理机器的同时非常方便,但是却给人类带来了极大的不便。汇编语言提供了基于文本的,因此等效于人性化的字节码。实际上,汇编语言在二进制形式的字节码指令与其等效文本之间建立了一对一的映射关系,从而为程序员提供了一种便捷的方式来读取,理解和编写特定字节码(适用于特定处理器或虚拟机)中的程序。换句话说,字节码和汇编语言都在相同的抽象级别上以不同的术语来描述程序。

在汇编语言中,字节码指令和语句之间严格的一对一映射关系使程序可以轻松,明确地从二进制形式转换为文本形式,反之亦然。您可能会注意到,有很多反汇编程序,使工程师可以将已编译的应用程序从字节码二进制文件转换为汇编语言文本,从而了解它们。

将汇编文本转换为字节码需要编译。但是与高级编程语言相比,汇编文本的编译非常简单。汇编程序以逐条语句的方式使用程序文本。通常,汇编语言指定每个语句必须放在程序文本的单独一行中,因此,汇编器逐行使用该文本。它从每一行中提取忽略注释的单词和标点符号序列,并使用该单词集作为映射表中的键,以查找表示同一条指令的等效二进制字节序列。该字节序列放置在程序的字节码中。实际上,为消除与文本解析有关的开销,Java使用字节码,并且在JITing期间不直接从汇编文本中编译机器代码。

此外,与高级语言相比,从汇编语言编译字节码不需要复杂的语法(构建抽象语法树)和语义分析,并且不需要对生成的字节码进行优化。与现代编译器相比,汇编器非常简单。与高级编程语言相反,汇编语言始终链接到特定的字节码,从而链接到特定的处理器或虚拟机。最初引入高级语言是为了程序的可移植性,因此它们被设计为足够通用。相比之下,汇编语言的程序不是可移植的,但是另一方面,它们为程序员提供了对相应处理器或虚拟机的所有功能的完全访问权限,而与此同时,它们中的许多功能都无法使用高级语言进行访问。

诸如Java和C#之类的编程语言所采用的思想是保留高级语言的可移植性,但最小化执行程序所需的解释/编译的开销。因此,他们使用了虚拟机和字节码。

请注意,相同的字节码可以由多种汇编语言支持,因为在相同的字节码指令与对应于它们的不同文本字符串之间可能存在多个一对一映射的字典。每种汇编语言都可以提供自己的单词序列变体,以二进制形式描述同一条指令。例如,看一下x86汇编器。 Intel使用一种表示法,Microsoft使用另一种表示法,最后GNU汇编器完全使用另一种表示法。但是它们全部都编译为相同的机器代码。