답변:
=====> 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 소스 파일을 Pure C 코드 파일로 변환하는 것입니다.
단위에는 6 개의 단계가 있습니다 :
소스 파일의 문자를 결합하여 "TOKEN"을 형성합니다. 토큰은 '공백', '탭'및 '새 줄'이없는 문자 집합입니다. 따라서이 컴파일 단위를 "TOKENIZER"라고도합니다. 또한 주석을 제거하고 기호 테이블 및 재배치 테이블 항목을 생성합니다.
이 단위는 코드의 구문을 확인합니다. 예 :
{
int a;
int b;
int c;
int d;
d = a + b - c * ;
}
위의 코드는 방정식이 균형을 이루지 않기 때문에 구문 분석 오류를 생성합니다. 이 유닛은 다음과 같이 파서 트리를 생성하여 내부적으로이를 확인합니다.
=
/ \
d -
/ \
+ *
/ \ / \
a b c ?
따라서이 장치를 PARSER라고도합니다.
이 단위는 문장의 의미를 확인합니다. 예 :
{
int i;
int *p;
p = i;
-----
-----
-----
}
위 코드는 "호환되지 않는 유형 할당"오류를 생성합니다.
이 장치는 CPU와 독립적입니다. 즉, 두 가지 유형의 최적화가 있습니다.
이 단위는 다음 형식으로 코드를 최적화합니다.
예 :
{
int a = 10;
if ( a > 5 ) {
/*
...
*/
} else {
/*
...
*/
}
}
여기서 컴파일러는 컴파일 타임에 'a'의 값을 알고 있으므로 if 조건이 항상 참인 것도 알고 있습니다. 따라서 코드에서 else 부분을 제거합니다.
예 :
{
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)
코드 조각을 만들고 파일 (소스 코드)을 저장 한 다음
전처리 :-이름에서 알 수 있듯이 컴파일의 일부가 아닙니다. 실제 컴파일 전에 필요한 사전 처리를 수행하도록 컴파일러에 지시합니다. 이 단계를 텍스트 대체라고 부르거나 #으로 표시된 특수 전 처리기 지시문을 해석 할 수 있습니다.
컴파일 :-컴파일은 한 언어로 작성된 프로그램이 다른 대상 언어로 번역되는 과정입니다. 오류가있는 경우 컴파일러는 오류를 감지하고보고합니다.
조립 :-조립 코드는 기계 코드로 변환됩니다. 어셈블러를 특수 유형의 컴파일러라고 부를 수 있습니다.
연결 :-이 코드 조각에 다른 소스 파일을 연결해야하는 경우 링커를 연결하여 실행 파일로 만듭니다.
그 후에 일어나는 많은 과정이 있습니다. 예, 바로 여기에 로더의 역할이 있다고 짐작하셨습니다.
짐을 싣는 사람 :-실행 코드를 메모리에로드합니다. 프로그램 및 데이터 스택이 생성되고 레지스터가 초기화됩니다.
약간의 추가 정보 :-http: //www.geeksforgeeks.org/memory-layout-of-c-program/ , 저기 메모리 레이아웃을 볼 수 있습니다.
컴파일러 : 고급 언어 프로그램을 기계 언어 프로그램으로 변환하는 프로그램입니다. 컴파일러는 어셈블러보다 지능적입니다. 모든 종류의 제한, 범위, 오류 등을 확인합니다. 그러나 프로그램 실행 시간이 더 길고 메모리의 더 많은 부분을 차지합니다. 속도가 느립니다. 컴파일러는 전체 프로그램을 거쳐 전체 프로그램을 기계 코드로 변환하기 때문입니다. 컴파일러가 컴퓨터에서 실행되고 동일한 컴퓨터에 대한 기계 코드를 생성하는 경우 자체 컴파일러 또는 상주 컴파일러라고합니다. 반면에 컴파일러가 컴퓨터에서 실행되고 다른 컴퓨터에 대한 기계어 코드를 생성하는 경우 크로스 컴파일러라고합니다.
링커 : 고급 언어에서는 일부 내장 헤더 파일 또는 라이브러리가 저장됩니다. 이러한 라이브러리는 미리 정의되어 있으며 프로그램 실행에 필수적인 기본 기능을 포함합니다. 이러한 함수는 링커라는 프로그램에 의해 라이브러리에 연결됩니다. 링커가 함수 라이브러리를 찾지 못하면 컴파일러에 알리고 컴파일러에서 오류를 생성합니다. 컴파일러는 프로그램 컴파일의 마지막 단계로 링커를 자동으로 호출합니다. 라이브러리에 내장되어 있지 않으며 사용자 정의 함수를 사용자 정의 라이브러리에 연결합니다. 일반적으로 긴 프로그램은 모듈이라고하는 더 작은 하위 프로그램으로 나뉩니다. 그리고 이러한 모듈은 프로그램을 실행하기 위해 결합되어야합니다. 모듈 결합 프로세스는 링커에 의해 수행됩니다.
로더 : 로더는 프로그램의 기계 코드를 시스템 메모리로로드하는 프로그램입니다. 컴퓨팅에서 로더는 프로그램로드를 담당하는 운영 체제의 일부입니다. 프로그램을 시작하는 과정에서 필수적인 단계 중 하나입니다. 프로그램을 메모리에 저장하고 실행할 준비를하기 때문입니다. 프로그램로드에는 실행 파일의 내용을 메모리로 읽어들이는 작업이 포함됩니다. 로드가 완료되면 운영 체제는로드 된 프로그램 코드에 제어를 전달하여 프로그램을 시작합니다. 프로그램 로딩을 지원하는 모든 운영 체제에는 로더가 있습니다. 많은 운영 체제에서 로더는 메모리에 영구적으로 상주합니다.
Wikipedia는 좋은 대답을 가져야합니다. 여기 내 생각이 있습니다.
*
*
링커 및 로더LinuxJournal의 는이 개념을 명확하게 설명합니다. 또한 고전적인 이름 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
컴파일러 소스 코드를 객체 코드로 변환합니다.
링커 여러 개체 파일을 단일 실행 프로그램 파일로 결합합니다.
로더 메인 메모리에 실행 파일을로드합니다.
컴파일러는 특정 프로그래밍 언어로 작성된 명령문을 처리하여 컴퓨터 프로세서가 사용하는 기계어 또는 "코드"로 변환하는 특수 프로그램입니다.
컴파일러 는 프로그래밍 언어의 코드 줄을 기계어로 번역합니다.
링커 는 두 프로그램 사이에 링크를 만듭니다.
로더 는 프로그램을 주 데이터베이스, 프로그램 등의 메모리로로드합니다.