【发布时间】:2011-04-29 03:22:08
【问题描述】:
我想深入了解编译器、链接器和加载器的含义和工作原理。 参考任何语言,最好是 c++。
【问题讨论】:
标签: compiler-construction linker terminology loader
我想深入了解编译器、链接器和加载器的含义和工作原理。 参考任何语言,最好是 c++。
【问题讨论】:
标签: compiler-construction linker terminology loader
=====> COMPILATION PROCESS <======
|
|----> Input is Source file(.c)
|
V
+=================+
| |
| C Preprocessor |
| |
+=================+
|
| ---> Pure C file ( comd:cc -E <file.name> )
|
V
+=================+
| |
| Lexical Analyzer|
| |
+-----------------+
| |
| Syntax Analyzer |
| |
+-----------------+
| |
| Semantic Analyze|
| |
+-----------------+
| |
| Pre Optimization|
| |
+-----------------+
| |
| Code generation |
| |
+-----------------+
| |
| Post Optimize |
| |
+=================+
|
|---> Assembly code (comd: cc -S <file.name> )
|
V
+=================+
| |
| Assembler |
| |
+=================+
|
|---> Object file (.obj) (comd: cc -c <file.name>)
|
V
+=================+
| Linker |
| and |
| loader |
+=================+
|
|---> Executable (.Exe/a.out) (com:cc <file.name> )
|
V
Executable file(a.out)
C 预处理是编译的第一步。它处理:
#define 声明。#include 声明。本单元的目的是将C源文件转换为纯C代码文件。
单元中有六个步骤:
它将源文件中的字符组合起来,形成一个“TOKEN”。一种 token 是一组没有“空格”、“制表符”和“换行符”的字符。 因此这个编译单元也被称为“TOKENIZER”。它还删除 cmets,生成符号表和重定位表条目。
本单元检查代码中的语法。例如:
{
int a;
int b;
int c;
int d;
d = a + b - c * ;
}
上面的代码会产生解析错误,因为等式不是 均衡。该单元通过将解析器树生成为 如下:
=
/ \
d -
/ \
+ *
/ \ / \
a b c ?
因此这个单元也被称为解析器。
本单元检查语句中的含义。例如:
{
int i;
int *p;
p = i;
-----
-----
-----
}
以上代码生成错误“Assignment of incompatible type”。
这个单元独立于CPU,即有两种优化方式
本单元将代码优化成以下形式:
例如:
{
int a = 10;
if ( a > 5 ) {
/*
...
*/
} else {
/*
...
*/
}
}
这里,编译器在编译时就知道 'a' 的值,因此它也 知道 if 条件始终为真。因此它消除了其他 部分代码。
例如:
{
int a, b, c;
int x, y;
/*
...
*/
x = a + b;
y = a + b + c;
/*
...
*/
}
可以优化如下:
{
int a, b, c;
int x, y;
/*
...
*/
x = a + b;
y = x + c; // a + b is replaced by x
/*
...
*/
}
例如:
{
int a;
for (i = 0; i < 1000; i++ ) {
/*
...
*/
a = 10;
/*
...
*/
}
}
在上面的代码中,如果'a'是本地的并且没有在循环中使用,那么它可以是 优化如下:
{
int a;
a = 10;
for (i = 0; i < 1000; i++ ) {
/*
...
*/
}
}
在这里,编译器生成汇编代码,以便更多 常用的变量存放在寄存器中。
这里的优化取决于 CPU。假设如果有多个 在代码中跳转,然后将它们转换为:
-----
jmp:<addr1>
<addr1> jmp:<addr2>
-----
-----
控件直接跳转到。
最后一个阶段是链接(创建可执行文件或库)。 当可执行文件运行时,它需要的库被加载。
【讨论】:
ASCII 表示:
[Source Code] ---> Compiler ---> [Object code] --*
|
[Source Code] ---> Compiler ---> [Object code] --*--> Linker --> [Executable] ---> Loader
| |
[Source Code] ---> Compiler ---> [Object code] --* |
| |
[Library file]--* V
[Running Executable in Memory]
【讨论】:
希望这对您有所帮助。
首先,看一下这张图:
(img source->internet)
你制作一段代码并保存文件(源代码),然后
预处理 :- 顾名思义,它不是编译的一部分。它们指示编译器在实际编译之前进行所需的预处理。您可以将此阶段称为文本替换或解释由 # 表示的特殊预处理器指令。
编译 :- 编译是将用一种语言编写的程序翻译成另一种目标语言的过程。如果有错误,编译器会检测到并报告。
汇编:- 汇编代码被翻译成机器码。您可以将汇编器称为特殊类型的编译器。
链接:- 如果这些代码需要链接其他源文件,链接器链接它们以使其成为可执行文件。
在它之后发生了许多过程。是的,你猜对了,加载器的作用就在这里:
Loader:- 将可执行代码加载到内存中;创建程序和数据栈,初始化寄存器。
Little Extra info :- http://www.geeksforgeeks.org/memory-layout-of-c-program/ ,你可以看到那里的内存布局。
【讨论】:
编译器:它是将高级语言程序翻译成机器语言程序的程序。编译器比汇编器更智能。它检查各种限制,范围,错误等。但它的程序运行时间更多,占用内存更大。它的速度很慢。因为编译器会遍历整个程序,然后将整个程序翻译成机器代码。如果编译器在计算机上运行并为同一台计算机生成机器代码,则它被称为自编译器或常驻编译器。另一方面,如果编译器在一台计算机上运行并为其他计算机生成机器代码,则称为交叉编译器。
链接器:在高级语言中,存储了一些内置的头文件或库。这些库是预定义的,它们包含执行程序所必需的基本功能。这些函数通过名为 Linker 的程序链接到库。如果链接器没有找到函数库,则它会通知编译器,然后编译器会生成错误。作为编译程序的最后一步,编译器会自动调用链接器。 不是内置库,它还将用户定义的函数链接到用户定义的库。通常一个较长的程序被分成更小的子程序,称为模块。并且这些模块必须组合起来才能执行程序。组合模块的过程由链接器完成。
Loader:Loader是将程序的机器码加载到系统内存中的程序。在计算中,加载程序是操作系统的一部分,负责加载程序。这是启动程序过程中的重要阶段之一。因为它将程序放入内存并为执行做好准备。加载程序涉及将可执行文件的内容读入内存。加载完成后,操作系统通过将控制权传递给加载的程序代码来启动程序。所有支持程序加载的操作系统都有加载器。在许多操作系统中,加载程序永久驻留在内存中。
【讨论】:
维基百科应该有一个很好的答案,这是我的想法:
【讨论】:
*
*
来自 LinuxJournal 的Linkers and Loaders 清晰地解释了这个概念。它还解释了经典名称 a.out 的来历。 (汇编器输出)
快速总结,
c program --> [compiler] --> objectFile --> [linker] --> executable file (say, a.out)
我们得到了可执行文件,现在将此文件提供给您的朋友或需要此软件的客户:)
当他们运行这个软件时,比如说在命令行中输入 ./a.out
execute in command line ./a.out --> [Loader] --> [execve] --> program is loaded in memory
一旦程序加载到内存中,通过使 PC(程序计数器)指向 a.out 的第一条指令,控制权就会转移到该程序
【讨论】:
它将读取可能是 .c 或 .cpp 等类型的源文件,并将其转换为称为目标文件的 .o 文件。
它将可能为多个源文件生成的几个 .o 文件组合成一个可执行文件(GCC 中的 ELF 格式)。有两种类型的链接:
将可执行文件加载到机器主内存的程序。
如需详细了解 Linux 程序执行的这三个阶段,请read this。
【讨论】:
链接器和解释器是互斥的 解释器逐行获取代码,逐行执行。
【讨论】:
编译器更改检查您的源代码是否有错误并将其更改为目标代码。这是操作系统运行的代码。
您通常不会在单个文件中编写整个程序,因此链接器会链接您的所有目标代码文件。
你的程序不会被执行,除非它在主内存中
【讨论】:
编译器将代码行从编程语言翻译成机器语言。
链接器在两个程序之间创建链接。
A Loader将程序加载到主数据库、程序等内存中
【讨论】:
【讨论】:
编译器是一种特殊的程序,它处理以特定编程语言编写的语句并将它们转换为计算机处理器使用的机器语言或“代码”
【讨论】:
编译器 它将源代码转换为目标代码。
链接器 它将多个目标文件组合成一个可执行程序文件。
加载器 它将可执行文件加载到主内存中。
【讨论】:
编译器:它是一个系统软件,用于纠正程序、目标文件、消息等的错误
链接器:它是一种系统软件,它将一个或多个目标文件和可能的一些库代码组合成一些可执行的一些库或错误列表
Loader:将可执行文件加载到机器主内存的程序
【讨论】: