我主要对流行的和广泛使用的编译器感兴趣,比如gcc.但如果不同的编译器对事情做了不同的事情,我也想知道.
以gcc为例,它是否将用C编写的简短程序直接编译为机器代码,或者首先将其转换为人类可读的汇编,然后才使用(内置?)汇编程序将汇编程序转换为二进制,机器代码 - CPU的一系列指令?
使用汇编代码创建二进制可执行文件是一项非常昂贵的操作吗?或者这是一个相对简单快速的事情?
(假设我们只处理x86系列处理器,所有程序都是为Linux编写的.)
我对此事的任何帮助和想法都非常感激.谢谢!
gcc实际上生成汇编程序并使用as汇编程序汇编它.并非所有编译器都这样做 - MS编译器直接生成目标代码,但您可以使它们生成汇编程序输出.将汇编程序转换为目标代码是一个非常简单的过程,至少与编译相比.
一些编译器生成其他高级语言代码作为其输出 - 例如,cfront,第一个C++编译器生成C作为其输出,然后由C编译器编译.
请注意,直接编译或汇编实际上都不会生成可执行文件.这是由链接器完成的,它接受编译/汇编产生的各种目标代码文件,解析它们包含的所有名称并生成最终的可执行二进制文件.
几乎所有编译器(包括gcc)都会生成汇编代码,因为它更容易 - 生成和调试编译器.主要的例外情况通常是即时编译器或交互式编译器,其作者不希望性能开销或分支整个进程运行汇编程序的麻烦.一些有趣的例子包括
新泽西州的标准ML,它以交互方式运行并动态编译每个表达.
该tinycc编译器,它被设计成足够快的编译,下载,并在远低于100毫秒运行C脚本,因此不希望调用汇编程序和连接的开销.
这些案例的共同点是对"瞬时"反应的渴望.汇编程序和链接器速度很快,但不足以进行交互式响应.然而.
还有一大类语言,例如Smalltalk,Java和Lua,它们编译为字节码,而不是汇编代码,但是它的实现稍后可以将该字节码直接转换为机器代码,而无需汇编程序的好处.
(脚注:在20世纪90年代早期,Mary Fernandez和我编写了新泽西机器代码工具包,其代码在线,它生成C库,编译器编写者可以使用它来绕过标准汇编器和链接器.Mary使用它大致加倍生成时优化链接器的速度a.out
.如果你不写入磁盘,速度会更快......)
通常,编译器将源代码解析为抽象语法树(AST),然后解析为某种中间语言.只有这样,通常在一些优化之后,它们才会发出目标语言.
关于gcc,它可以编译到各种各样的目标.我不知道对于x86它是否首先编译成汇编,但我确实给了你一些关于编译器的见解 - 你也问过这个问题.
根据第二章的介绍逆向工程软件(由Mike Perry和Nasko Oskov),GCC和cl.exe时(后端编译器MSVC++)已在-S开关,您可以使用输出每个编译器生成的程序集.
您还可以在详细模式(gcc -v
)中运行gcc 以获取它执行的命令列表,以查看它在幕后执行的操作.
GCC编译成汇编程序.其他一些编译器则没有.例如,LLVM-GCC编译为LLVM-assembly或LLVM-bytecode,然后将其编译为机器代码.几乎所有编译器都有某种内部表示,LLVM-GCC使用LLVM,而IIRC,GCC使用称为GIMPLE的东西.