目标代码、机器代码和汇编代码之间有什么区别?
你能举一个视觉上的例子吗?
目标代码、机器代码和汇编代码之间有什么区别?
你能举一个视觉上的例子吗?
机器码是二进制(1和0)代码,可以直接由CPU执行。如果在文本编辑器中打开机器码文件,您会看到垃圾字符,包括不可打印的字符(不是那些不可打印的字符 ;) )。
目标码是尚未链接到完整程序中的部分机器码。它是构成完成产品的一个特定库或模块的机器码。它还可能包含占位符或偏移量,在已经完成的程序的机器码中找不到。链接器将使用这些占位符和偏移量连接所有内容。
汇编代码是纯文本且(有点)易于阅读的源代码,其大部分具有与机器指令直接对应的1:1模拟。这是通过为实际指令、寄存器或其他资源使用助记符来实现的。例如CPU的跳转和乘法指令的JMP
和MULT
。与机器码不同,CPU不理解汇编代码。您可以借助汇编器或编译器将汇编代码转换为机器代码,尽管我们通常考虑编译器与更高级的编程语言相关联,这些语言进一步抽象了CPU指令。
构建完整程序涉及使用汇编语言或像C++这样的更高级别语言为程序编写源代码。将源代码汇编(对于汇编代码)或编译(对于更高级别语言)为目标码,然后将单独的模块链接在一起,成为最终程序的机器码。对于非常简单的程序,可能不需要连接步骤。在其他情况下,例如使用IDE(集成开发环境),链接器和编译器可以一起调用。在其他情况下,可以使用复杂的make脚本或solution文件告诉环境如何构建最终应用程序。
还有一种解释型语言,其行为方式不同。解释型语言依靠特殊解释器程序的机器码。在基本层面上,解释器解析源代码并立即将命令转换为新的机器码并执行它们。现代解释器现在更加复杂:一次性评估整个源代码部分,尽可能缓存和优化,并处理复杂的内存管理任务。
最后一种程序类型涉及使用运行环境或虚拟机。在这种情况下,程序首先被预编译成较低级别的中间语言或字节码。然后,虚拟机加载字节码,并即时将其编译成本地代码。这里的优势在于虚拟机可以利用程序运行时和特定环境提供的优化。编译器属于开发人员,因此必须生成相对通用(不太优化)的机器码,可在许多地方运行。但是,运行时环境或虚拟机位于最终用户的计算机上,因此可以利用该系统提供的所有功能。
其他回答已经很好地描述了它们之间的区别,但您还希望有一个可视化展示。以下是一张图表,展示了从C代码到可执行文件的过程。
汇编代码是机器码的人类可读表示:
mov eax, 77
jmp anywhere
机器代码是纯十六进制代码:
5F 3A E3 F1
我理解你所说的目标代码是指目标文件中的对象代码。与机器代码相比,它的跳转有点参数化,以便链接器可以填充它们。
汇编器用于将汇编代码转换为机器代码(目标代码)。链接器将多个对象(和库)文件链接在一起生成可执行文件。
我曾经使用纯十六进制编写过汇编程序(没有可用的汇编器),幸运的是这是在早期的 6502 处理器上完成的。但我很高兴现在有针对 Pentium 指令集的汇编器。
8B 5D 32
是机器码。
mov ebx, [ebp+32h]
是汇编语言。
lmylib.so
包含 8B 5D 32
,是目标代码。
源代码、汇编代码、机器代码、目标代码、字节码、可执行文件和库文件。所有这些术语通常会让大多数人感到困惑,因为他们认为这些术语是相互独立的。请参考下图以了解它们之间的关系。每个术语的描述如下。
用人类可读(编程)语言编写的指令
用高级(编程)语言编写的指令
例如 C、C++ 和 Java 程序。
用汇编语言编写的指令(一种低级编程语言)。作为编译过程的第一步,将高级代码转换为此形式。随后进行的是将汇编代码转换为实际的机器代码。在大多数系统上,这两个步骤是作为编译过程的一部分自动完成的。
例如 program.asm。
编译过程的产物。它可以是机器代码或字节码的形式。
例如 file.o。
用机器语言写成的指令。
例如 a.out。
以一种中间形式编写的指令,可以由JVM等解释器执行。
链接过程的产物,是机器码,可以直接由CPU执行。
例如,.exe文件。
需要注意的是,在某些情况下,包含字节码或脚本语言指令的文件也可能被认为是可执行文件。
某些代码以此形式编译出来,出于不同的原因,例如可重用性,并且稍后由可执行文件使用。
cc1
可执行文件中内置汇编器)。我认为汇编圆圈应该突出“源”圆圈的左侧,因为有些汇编只是汇编,而不是源代码。当然,它永远不会是目标代码,但某些汇编是从源代码到目标文件的过程中的一步。 - Peter Cordes还没有提到的一个问题是汇编代码有几种不同类型。在最基本的形式中,指令中使用的所有数必须被指定为常量,例如:
$1902: BD 37 14 : LDA $1437,X $1905: 85 03 : STA $03 $1907: 85 09 : STA $09 $1909: CA : DEX $190A: 10 : BPL $1902
如果将上面这段代码存储在Atari 2600游戏卡带中地址为$1900的位置,它将从地址为$1437的表中获取多个颜色的行并以不同的颜色显示。在某些工具中,键入一个地址以及上述行的最右侧部分将会将中间一列显示的值存储到内存中,并以下一个地址开始下一行。使用这种形式的代码比输入十六进制代码更方便,但需要知道每个东西的精确地址。
大多数汇编器都允许使用符号地址。上面的代码可以写成:
rainbow_lp: lda ColorTbl,x sta WSYNC sta COLUBK dex bpl rainbow_lp
汇编器将自动调整LDA指令,使其引用映射到标签ColorTbl的任何地址。使用这种样式的汇编器使得编写和编辑代码比手动输入和维护所有地址更容易。
您的程序源文件将被编译成目标文件,然后链接器将这些目标文件链接在一起,生成一个包含您架构机器代码的可执行文件。
无论是目标文件还是可执行文件,在文本编辑器中打开时都涉及到架构机器代码的可打印和不可打印字符形式。
尽管如此,文件之间的区别在于目标文件可能包含未解决的外部引用(例如printf
)。因此,它可能需要与其他目标文件链接。也就是说,需要解决未解决的外部引用,才能通过与其他目标文件(如C/C++运行时库)链接获得良好的可运行可执行文件。