当前位置: 首页 > 知识库问答 >
问题:

编译器总是生成汇编代码吗?

轩辕弘雅
2023-03-14

至少在GCC中,如果我们提供生成汇编代码的选项,编译器会通过创建一个包含汇编代码的文件来服从。但是,当我们简单地运行命令gcc而没有任何选项时,它不会在内部生成汇编代码吗?

如果是,那么为什么它需要首先生成一个汇编代码,然后将其翻译成机器语言?

共有1个答案

南门欣怡
2023-03-14

TL:DR不同的目标文件格式/更容易移植到新的Unix平台(历史上)是gcc将汇编器与编译器分开的主要原因之一,我认为。除了gcc之外,主流的x86 C和C++编译器(CLANG/LLVM、MSVC、ICC)直接使用机器代码,如果您要求的话,可以选择打印asm文本。

LLVM和MSVC都带有完整的工具链,而不仅仅是编译器。(还附带汇编器和链接器)。LLVM已经将对象文件处理作为一个库函数,因此它可以使用该函数而不是写出asm文本来提供给单独的程序。

较小的项目通常选择将对象文件格式细节留给汇编程序。例如,FreePascal可以直接访问几个目标平台上的目标文件,但除此之外只能访问ASM。有许多说法(1,2,3,4),几乎所有的编译器都通过asm文本,但对于许多最大、使用最广泛的编译器(除了GCC)来说,这并不是真的,因为它们有很多开发人员在工作。

此外,像javac这样的编译器,目标是可移植字节码格式,使用ASM的理由较少;相同的输出文件和字节码格式可以在它们必须运行的每个平台上工作。

相关的:

  • https://retrocomputing.stackexchange.com/questions/14927/when-and-why-did-high-level-language-compilers-start-targeting-assemblanguage on retrocomputing有其他一些关于将作为分开的优点的答案。
  • 在gcc,G++中生成ASM代码有什么需要
  • C和汇编程序实际上编译成什么?-即使直接处理机器代码的编译器也不会直接生成链接的可执行文件,它们会生成可重定位的目标文件(.o.obj)。除了tcc之外,一个小的C编译器,用于一个文件的C程序。
  • 半相关:为什么我们有编译器还需要汇编器?asm对于人类查看机器代码是有用的,而不是作为C->机器代码的必要部分。

GCC在内部使用一些二进制数据结构用于GIMPLE和RTL内部表示,但它不会将这些IR格式的(文本表示)写入文件,除非您使用特殊的调试选项。

那为什么要停在集会上呢?这意味着GCC不需要知道相同目标的不同对象文件格式。例如,不同的x86-64操作系统使用ELF、PE/COFF、MachO64对象文件,以及历史上的a.out。AS将相同的文本asm组装成由不同目标上的不同对象文件元数据包围的相同机器代码。(gcc必须知道一些小的区别,比如是否在符号名之前加上_,是否可以使用32位绝对地址,以及是否必须PIC代码。)

任何特定于平台的怪癖都可以留给GNU binutils作为(又名GAS),或者gcc可以使用系统附带的供应商提供的汇编程序。

从来没有人将汇编器作为库集成到GCC的CC1编译器中。对于C预处理器(历史上也是在一个单独的进程中完成的),而不是汇编程序。

大多数其他编译器确实直接从编译器生成目标文件,而不需要文本asm临时文件/管道。通常是因为编译器只为一个或几个目标设计,如MSVC或ICC或各种编译器,最初只用于x86或许多供应商为嵌入式芯片提供的编译器。

CLANG/LLVM比GCC设计得更晚。它被设计成一个优化的JIT后端,所以它需要一个内置的汇编程序来快速生成机器代码。作为一个超前编译器,添加对不同对象文件格式的支持可能是一件小事,因为内部软件体系结构直接用于二进制机器代码。

 类似资料:
  • 关于目标旗。与使用Java6编译器编译代码相比,使用针对Java6的Java8编译器编译Java6代码(当代码仍然在JVM6上运行时)有什么好处吗?

  • 我使用了Jooq官方网站上的这个工具:https://github.com/etiennestuder/gradle-jooq-plugin从我的数据库生成代码。 但如果我设置

  • 我正在观看Angular Compiler4.0-TOBIAS BOSCH,突然在1:30的视频中说,如果我们使用AOT编译,将转换为javascript代码。编译过程:视频的快照。现在我超级困惑,引擎盖下到底发生了什么?是先由typescript编译器将(.ts)传递到js,然后由angular编译器执行,还是由angular编译器执行,然后由typescript编译器执行?我经历了这个角编译器

  • 我正在为64位mips机器使用gcc编译器。我注意到生成的一段汇编代码很有趣。下面是详细信息: 通常,bnez将立即跳到0xb0。但在0xb0之后的块中,我确信程序必须使用a1作为参数。但是我们可以看到,在0xb0之后,a1从未出现在块中。 但是a1在0x58中使用,就在bnez(0x54)之后。 那么0x54和0x58指令有可能同时执行吗?超标量处理器通过同时将多条指令分派到处理器上的冗余功能单

  • 我还想知道是否会有更直接的方法来编译和运行生成的代码。

  • 问题内容: 当Java编译器将原语自动包装到包装类时,它在幕后生成什么代码?我想象它调用: 包装器上的valueOf()方法 包装器的构造函数 还有其他魔术吗? 问题答案: 您可以使用该工具亲自查看。编译以下代码: 编译和反汇编: 输出为: 因此,如您所见,自动装箱将调用static方法,而自动拆箱将在给定对象上调用。没什么,真的- 只是语法糖。