据我了解,当一个程序(例如用 C 编写的)被编译时,它首先被翻译成汇编语言,然后被翻译成机器语言。为什么不能(不是)跳过“汇编语言步骤”?
7 回答
您的理解是错误的,编译器不一定将 C 代码翻译成汇编程序。它们通常执行多个阶段并具有内部表示,但这不一定类似于人类可读的汇编程序。
在这里,我找到了LLVM的一个很好的介绍。LLVM 是用于 clang 的编译器工具包。
对于编译器开发人员来说更容易。
可以编写一个可以读取 C 并编写目标代码的编译器。但是,这需要编译器编写者编写所有对指令进行编码的计算。指令编码在某些机器上很复杂。此外,还有一些需要填写的字段取决于其他交互,例如分支目标的距离,这取决于分支和目标之间的指令。
此外,编写编译器的部分方式是使用诸如“要递增对象 x,请发出递增指令”之类的模式。为了直接编写目标代码,您必须将要写入的所有指令编码到这些模式中。这意味着你的模式必须有某种语言来描述指令。
好吧,我们已经有了一种语言:汇编语言。因此,以“增加对象 x,发出”之类的方式编写模式会更容易inc x
。</p>
现代编译器有很多层。有一个前端可以读取 C 文本(或其他语言)并将其转换为编译器内部的语言。有一个优化器对内部语言(或它的表示)进行操作并尝试改进代码。有一个后端可以将内部语言转换为汇编语言。有一个汇编程序可以将程序集转换为目标代码。还有一个链接器将目标代码链接到可执行文件中。
与许多复杂的任务一样,当复杂的任务被分成很好的部分时,人类的大脑更容易处理它。这减少了错误并缩短了使用软件所需的时间。它还使软件变得灵活,因为我们可以更改前端以支持新的语言(例如,Java 代替 C)或更改后端以支持新的处理器(从 Intel 汇编更改为 PowerPC 汇编)。更改一个优化器可以改进所有编译器,包括 Java 和 C 以及 Intel 和 PowerPC。
我们用来编译的gcc命令实际上只是一个驱动程序,它调用其他执行前端处理、优化、汇编和链接的程序。您也可以单独调用这些阶段中的大多数,或者使用开关告诉 gcc 向您显示它正在使用的命令。
此外,GCC 具有允许开发人员直接插入与 C 代码混合的汇编语言的功能。这迫使 GCC 包含一个汇编程序。
操作系统不会做这样的事情。这是编译器的工作。事实上,许多确实直接发出目标文件——你必须明确要求它们发出汇编代码。其他人选择不这样做,因为发出功能齐全的目标文件需要有关为此存在的各种格式的专业知识。汇编器具有各种方便的功能,使工作更容易,可以(有时?)针对多种目标文件格式而无需更改汇编代码。此外,发出带注释的汇编代码是一个非常有用的功能,因此没有单独的代码生成器仅用于直接目标文件的发出可以在没有任何限制的情况下节省您的时间(除了需要汇编程序),这使得它在您受到限制时成为一个有吸引力的选择资源。
取决于编译器;实际上不需要汇编代码。
也许您正在谈论的任何编译器(GNU-CC?)的作者认为,如果他们不必自己解决某些问题(例如分支),对他们自己来说会稍微容易一些。
汇编代码纯粹是机器代码以及链接器在将不同翻译单元的输出放在一起时所需的符号引用和重定位的一种方便的、有点人类可读的表示。如果没有中间的汇编语言步骤,编译器还将负责以链接器所需的形式生成重定位,这是可行的,但很痛苦。由于已经存在具有这种能力的汇编器来处理手写的汇编代码,因此使用它是有意义的。
通常没有汇编阶段。MSVC (cl.exe) 和 GCC 立即生成机器代码 (.obj, .o)。
交叉编译器可以直接生成机器代码,而无需安装交叉编译器的操作系统的帮助。
例如windows中安装的tornado包可以为vxworks生成机器码。