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

时间:2012-12-26 11:17:32

标签: gcc assembly compiler-construction

来自思考C ++ - 第1卷

  

在第二遍中,代码生成器遍历解析树   并生成汇编语言代码 的机器代码   树的节点。

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

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

4 个答案:

答案 0 :(得分:2)

汇编程序阶段可以证明有两个原因:

  • 它允许将c / c ++代码转换为独立于机器的抽象汇编程序,从中可以轻松转换到多种不同的指令集体系结构
  • 当人们可以使用现有的软件[组件]时,它会消除验证CISC架构的正确操作码,前缀,r / m等指令编码的负担。

该书的第1版是从2000年开始的,但也可以谈谈90年代早期,当时c ++本身被翻译成c并且gnu /自由软件的想法(包括编译器的源代码)并不是真的知道

编辑:GCC使用的几个荒谬abstract machine independent languages之一是RTL - Register Transfer Language

答案 1 :(得分:1)

这是编译器实现的问题。汇编代码是高级语言(正在编译的语言)和生成的二进制输出之间的中间步骤。通常,首先转换为汇编更容易,之后转换为二进制代码,而不是直接创建二进制代码。

答案 2 :(得分:1)

TL:DR不同的对象文件格式/从历史上更容易移植到新的Unix平台,这是gcc保持汇编程序与编译器分离的主要原因之一。在gcc之外,大多数编译器直接使用机器代码。


是的,as是一个独立的程序,gcc前端实际上是与cc1(生成文本asm的C预处理程序+编译器)分开运行的。

这使gcc更具模块化,使编译器本身成为文本->文本程序。

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

那为什么要停止组装呢?这意味着GCC不需要为同一目标知道不同的目标文件格式。例如,不同的x86-64 OS使用ELF,PE / COFF,MachO64目标文件和历史上as将相同的文本汇编成同一机器代码,并在不同目标上的不同目标文件元数据包围。 (gcc必须知道一些细微的差异,例如是否在符号名称前加上_,是否可以使用32位绝对地址,以及代码是否必须为PIC。)

binutils可以保留任何平台特定的怪癖,或者gcc可以使用系统随附的供应商提供的汇编器。

从历史上看,有许多不同的Unix系统具有不同的CPU,尤其是相同的CPU,但目标文件格式却有不同的特点。更重要的是,一组相当兼容的汇编器伪指令,例如.globl main.asciiz "Hello World!\n"等。 GAS语法来自Unix汇编程序。

过去,确实有可能仅使用OS随附的汇编程序将GCC移植到新的Unix平台而无需移植as

没人愿意将汇编程序作为库集成到GCC的cc1编译器中。这是为C预处理器完成的(历史上也曾在单独的进程中完成),但不是汇编程序。


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

clang / LLVM的设计比GCC更新得多。它被设计为作为优化的JIT后端工作,因此需要内置的汇编程序来快速生成机器代码。作为一个预先的编译器,添加对不同目标文件格式的支持大概是一件小事,因为内部软件体系结构可以直接用于二进制机器代码。

在寻找后端特定的优化之前,LLVM当然会在内部使用LLVM-IR进行与目标无关的优化,但是同样,如果您需要,它只会将该格式写为文本。


半相关:Why do we even need assembler when we have compiler?

asm对于人类查看机器代码很有用,而不是C->机器代码的必要部分。

答案 3 :(得分:0)

Gcc确实将汇编代码创建为临时文件,调用汇编程序,也可以根据您在命令行上执行或不添加的内容来调用汇编程序。这使得一个对象然后如果启用了二进制文件,则清除所有临时文件。使用-save-temps来查看实际情况(有许多临时文件)。

在没有任何选项的情况下运行gcc绝对会创建一个asm文件。

对此没有“需要”,只是它们如何设计它。我假设出于多种原因,在开始使用编译器之前你已经想要/需要一个汇编器和链接器(在马之前推车,在某种其他语言之前在处理器上运行)。 “unix方式”是不重新创建工具或库,但只是添加一点,所以这意味着去asm然后让汇编器和链接器完成剩下的工作。你不必以这种方式重新发明这么多的汇编程序工作(多次传递,解析标签等)。开发人员更容易调试ascii asm而不是位。人们一直在为这几代编译器这样做。及时编译器是这种习惯的主要例外,根据定义,它们必须能够转到机器代码,因此它们可以或者可以。直到最近,llvm才为命令行工具(llc)提供了一种直接转向对象的方法,而不是停止在asm(或者至少它以这种方式出现在用户身上)。

相关问题