什么是编译器,链接器,加载器?
我想深入了解编译器,链接器和加载器的含义和工作。 参考任何语言,最好是c ++。
=====> 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预处理器: –
C预处理是编译的第一步。 它处理:
-
#define
语句。 -
#include
语句。 - 有条件的陈述。
- macros
该单元的目的是将C源文件转换为纯C代码文件。
C编译:
单位有六个步骤:
1)词法分析器:
它将源文件中的字符组合起来,形成一个“TOKEN”。 令牌是一组没有“空格”,“标签”和“新行”的字符。 因此这个汇编单位也被称为“TOKENIZER”。 它也删除注释,生成符号表和重定位表项。
2)句法分析器:
本机检查代码中的语法。 例如:
{ int a; int b; int c; int d; d = a + b - c * ; }
上面的代码会产生parsing错误,因为方程式不平衡。 这个单元通过生成parsing器树来进行内部检查,如下所示:
= / \ d - / \ + * / \ / \ abc ?
因此这个单位也被称为PARSER。
3)语义分析器:
这个单位检查报表中的含义。 例如:
{ int i; int *p; p = i; ----- ----- ----- }
上面的代码会生成错误“不兼容types的赋值”。
4)预优化:
这个单元是独立于CPU的,即有两种types的优化
- 预优化(独立于CPU)
- 后优化(取决于CPU)
本机以下列forms优化代码:
- I)死码消除
- II)子代码消除
- 三)循环优化
I)死码消除:
例如:
{ int a = 10; if ( a > 5 ) { /* ... */ } else { /* ... */ } }
在这里,编译器在编译时知道'a'的值,因此它也知道if条件总是为真。 因此它消除了代码中的其他部分。
II)子代码消除:
例如:
{ 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 /* ... */ }
III)循环优化:
例如:
{ int a; for (i = 0; i < 1000; i++ ) { /* ... */ a = 10; /* ... */ } }
在上面的代码中,如果“a”是本地的,并且没有在循环中使用,那么它可以被优化如下:
{ int a; a = 10; for (i = 0; i < 1000; i++ ) { /* ... */ } }
5)代码生成:
在这里,编译器生成汇编代码,以便更频繁使用的variables存储在寄存器中。
6)后期优化:
这里的优化是与CPU相关的。 假设如果代码中有多个跳转,那么它们被转换为:
----- jmp:<addr1> <addr1> jmp:<addr2> ----- -----
控件直接跳转到。
然后最后一个阶段是链接(创build可执行文件或库)。 当可执行文件运行时,它需要的库是Loaded。
- 编译器读取,分析代码并将其转换为对象文件或错误消息列表。
- 链接器将一个或多个目标文件和可能的某些库代码组合成一些可执行文件,一些库或一系列错误消息。
- 加载程序将可执行代码读入内存,执行一些地址转换并尝试运行程序,从而导致运行程序或错误消息(或两者)。
ASCII表示forms:
[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)
然后制作一段代码并保存文件(源代码)
预处理 : – 顾名思义,它不是编译的一部分。 他们指示编译器在实际编译之前做必要的预处理。 您可以调用此阶段的“文本replace”或解释由#表示的特殊预处理器指令。
编译 :编译是用一种语言编写的程序翻译成另一种目标语言的过程。 如果有一些错误,编译器会检测到并报告。
汇编 : – 汇编代码被翻译成机器代码。 你可以调用汇编器一个特殊types的编译器。
链接 : – 如果这段代码需要链接其他源文件,链接器链接它们使其成为可执行文件。
之后有很多过程发生。 是的,你猜对了,装载机的作用是:
加载程序 : – 它将可执行代码加载到内存中; 程序和数据堆栈被创build,寄存器被初始化。
小额外的信息: – http://www.geeksforgeeks.org/memory-layout-of-c-program/ ,你可以看到那里的内存布局。
编译器:这是一个将高级语言程序翻译成机器语言程序的程序。 编译器比汇编器更聪明。 它检查各种限制,范围,错误等,但其程序运行时间更多,占用了大部分内存。 速度慢。 因为编译器遍历整个程序,然后将整个程序翻译成机器码。 如果一个编译器在一台计算机上运行,并为同一台计算机生成机器码,那么它被称为自编译器或驻留编译器。 另一方面,如果编译器在计算机上运行并为其他计算机生成机器码,则称为交叉编译器。
链接器:在高级语言中,存储一些内置的头文件或库。 这些库是预定义的,它们包含执行程序所必需的基本function。 这些函数通过称为链接器的程序链接到库。 如果连接器没有find一个函数的库,那么它会通知编译器,然后编译器会产生一个错误。 编译器自动调用链接器作为编译程序的最后一步。 不是在库中构build的,它也将用户定义的函数链接到用户定义的库。 通常较长的程序被分成较小的称为模块的子程序。 而这些模块必须结合起来才能执行程序。 组合模块的过程由链接器完成。
Loader:Loader是一个将程序的机器码载入系统内存的程序。 在Computing中,加载器是负责加载程序的操作系统的一部分。 这是启动程序的关键阶段之一。 因为它将程序放入内存并准备执行。 加载程序涉及将可执行文件的内容读入内存。 加载完成后,操作系统通过将控制权交给加载的程序代码来启动程序。 所有支持程序加载的操作系统都有加载器。 在许多操作系统中,加载程序永久驻留在内存中。
维基百科应该有一个很好的答案,这是我的想法:
- 编译器:读取something.c源码,写入something.o对象。
- 链接器:将几个* .o文件join到可执行程序中。
- Loader:将可执行文件加载到内存并启动它运行的代码。
编译:
它将读取可能是.c或.cpp等types的源文件,并将其转换为.o文件,称为目标文件。
链接:
它将可能为多个源文件生成的几个.o文件组合成可执行文件(GCC中的ELF格式)。 有两种types的链接:
- 静态链接
- dynamic链接
装载机:
将可执行文件加载到机器主存的程序。
有关Linux中这三个程序执行阶段的详细研究,请阅读本文 。
*
对于基于linux / unix的系统进行了解释,尽pipe这是所有其他计算系统的基本概念。
*
LinuxJournal的链接器和装载器清楚地解释了这个概念。 它也解释了经典名称a.out是如何来的。 (汇编输出)
快速总结,
c program --> [compiler] --> objectFile --> [linker] --> executable file (say, a.out)
我们得到了可执行文件,现在把这个文件给你的朋友或者需要这个软件的客户:)
当他们运行这个软件时,比方说在命令行input./a.out
execute in command line ./a.out --> [Loader] --> [execve] --> program is loaded in memory
一旦程序被加载到内存中,通过使PC(程序计数器)指向a.out
的第一条指令,将控制转移到该程序
编译器更改会检查源代码中的错误,并将其更改为对象代码。这是操作系统运行的代码。
你通常不会在单个文件中编写一个完整的程序,因此链接程序会链接所有的目标代码文件。
你的程序不会被执行,除非它在主内存中
- 编译器 :将人类可理解的格式转换成机器可理解的格式
- 链接器 :将机器可理解的格式转换成操作系统可理解的格式
- Loader :是实际加载和运行程序到RAM的实体
链接器和解释器是互斥的解释器,逐行获取代码并逐行执行。
编译器是将程序源代码文件编译成可执行程序的软件程序。 它作为集成开发环境IDE的一部分包含在大多数编程软件包中。 编译器将采用高级语言(如C,BASIC或Java)编写的源代码文件编译为低级语言,如机器代码或汇编代码。 此代码是为特定处理器types创build的,例如Intel Pentium或PowerPC。 程序可以被处理器识别并从操作系统运行。
装载程序是一个操作系统实用程序,可将程序从存储设备复制到主内存,并在其中执行。 除了将程序复制到主存储器之外,加载器还可以用物理地址replace虚拟地址。 大多数加载器是透明的,即不能直接执行它们,但操作系统在必要时使用它们。
Linker是一个调整两个或两个以上机器语言程序段的程序,以便它们可以同时作为一个单元加载和执行。也称为链接编辑器和联编程序,链接程序是将目标模块组合成可执行程序的程序。 许多编程语言都允许您分别编写不同的代码片段(称为模块)。 这简化了编程任务,因为你可以把一个大的程序分解成小的,更易于pipe理的部分。 但最终,你需要把所有的模块放在一起。 这是链接器的工作。
操作系统:操作系统(OS)是pipe理计算机硬件和软件资源并为计算机程序提供通用服务的系统软件。 操作系统是计算机系统中系统软件的组成部分。 应用程序通常需要一个操作系统来运行。
编译器:编译器是一种将用编程语言(源语言)编写的源代码转换成另一种计算机语言(目标语言)的计算机程序(或一组程序),后者通常具有被称为对象的二进制forms码。
口译员:口译员是一种计算机程序,可以直接执行,即执行用编程语言或脚本语言编写的指令,而无需事先将其编译成机器语言程序。
汇编程序:汇编程序是一种程序,它接受基本的计算机指令,并将其转换为计算机处理器可用来执行其基本操作的位模式。
加载程序:加载程序是负责加载程序和库的操作系统的一部分。 这是程序启动过程中的一个重要阶段,因为它将程序放入内存并准备执行。
链接器:链接器是一个程序,它结合了目标模块来形成一个可执行的程序。
预处理程序:预处理程序是一种文本replace工具,它指示编译器在实际编译之前执行所需的预处理。
编译器是一种特殊的程序,它处理用特定编程语言编写的语句,并将它们转换成计算机处理器使用的机器语言或“代码”
编译器将编程语言的代码行翻译成机器语言。
链接器创build两个程序之间的链接。
一个Loader将程序加载到主数据库,程序等的内存中。
编译器:是一个纠正程序,目标文件,消息等错误的系统软件
链接器:这是一个系统软件,它结合了一个或多个对象文件,并可能一些库代码到一些exicutable某些库或一个错误列表
Loader:将可执行文件加载到机器主存的程序