Pab*_*uez 3 c compiler-construction assembly gcc compilation
编译C程序的主要步骤是什么?通过编译,我的意思是(可能是错误的)使用gcc从包含C代码的纯文本中获取二进制文件.
我很想了解这个过程的一些关键点:
到那天结束时,我需要将我的C代码转换为我的CPU应该理解的语言.那么,谁在乎了解我的CPU特定指令呢?操作系统?
gcc是否将任何C转换为汇编语言?
我知道(实际猜测)对于每种处理器类型,我将需要一个汇编程序来解释(?)汇编代码并转换为我的CPU特定指令.这个汇编程序(谁发货)在哪里?它是否附带操作系统?
如果我用文本编辑器打开二进制文件,为什么我看不到0和1?
发生了很多:)
以下是一些关键步骤(顺便说一句,这些是我对编译的看法,以下步骤只与标准中定义的步骤有相似之处).
该预处理器对源文件运行.
预处理器为我们做了各种各样的事情,包括:
#define)#include行所在的位置.在Linux下,执行此操作的程序是m4,使用gcc您可以在此步骤之后使用该-E标志停止.
在预处理器运行之后,我们有一个文件,其中包含解析器运行和检查语法所需的所有信息,并发出汇编.在Linux下,最有可能执行此操作的程序是cc1,使用gcc此-s标志可以在此步骤之后停止使用.
程序集(GNU Assembler)很可能将程序集转换为目标代码,使用此标志可以在此步骤中停止.gasgcc-c
最后,链接器将一个或多个目标文件以及库转换为可执行文件.Linux下的链接器是正常的,并且在没有任何特殊标志的情况下使用它会一直运行.ldgcc
既然你特别提到'到一天结束时我需要将我的C代码转换成我的CPU应该理解的语言',我将解释一下编译器的工作原理.
典型的编译器做了一些事情.
首先,他们做了一些叫做lexing的事情.这个步骤采用单个字符并将它们组合成"令牌",这是下一步所理解的事物.此步骤区分语言关键字(如C中的'for'和'if'),运算符(如'+'),常量(如整数和字符串文字)以及其他内容.它的区别究竟取决于语言本身.
下一步是解析器,它获取词法分析器产生的令牌流,并(通常)将其转换为称为"抽象语法树"或AST的东西.AST表示程序使用编译器可以导航的数据结构完成的计算.通常,AST是与语言无关的,像GCC这样的编译器可以将不同的语言解析为下一步(代码生成器)可以理解的常见AST格式.
最后,代码生成器通过AST并输出代表AST语义的代码,即实际执行AST表示的计算的代码.
对于GCC,可能还有其他编译器,编译器实际上并不生成机器代码.相反,它输出传递给汇编程序的汇编代码.汇编程序经历了类似的lexing,解析和代码生成过程,以实际生成机器代码.毕竟,汇编程序只是编译汇编代码的编译器.
在C(和许多其他)的情况下,汇编程序通常不是最后一步.汇编程序生成称为目标文件的东西,其中包含对其他目标文件或库中函数的未解析引用(如C标准库中的printf或项目中其他C文件的函数).这些目标文件被传递给称为"链接器"的东西,其作用是将所有目标文件组合成单个二进制文件,并解析目标文件中的所有未解析的引用.
最后,在完成所有这些步骤后,您将拥有完整的可执行二进制文件.
请注意,这是GCC和许多其他编译器工作的方式,但并不一定如此.您可以编写的任何程序都准确地接受C代码流并输出一些等效的其他代码(程序集,机器代码,甚至是javascript)的流程,这是一个编译器.
而且,这些步骤并不总是完全分开的.而不是lexing和整个文件,然后解析整个结果,然后为整个AST生成代码,编译器可能会做一些lexing,然后在它有一些令牌时开始解析,然后当解析器需要更多令牌时再回到lexing .当解析器感觉它足够了解时,它可以在让词法分析器为它产生更多标记之前进行一些代码生成.
| 归档时间: |
|
| 查看次数: |
966 次 |
| 最近记录: |