Odpowiedzi:
=====> 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)
Wstępne przetwarzanie C jest pierwszym krokiem w kompilacji. Obsługuje:
#define
sprawozdania.#include
sprawozdania.Zadaniem urządzenia jest konwersja pliku źródłowego w języku C do pliku z kodem Pure C.
Jednostka składa się z sześciu kroków:
Łączy znaki w pliku źródłowym, tworząc „TOKEN”. Token to zestaw znaków bez „spacji”, „tabulacji” i „nowej linii”. Dlatego ta jednostka kompilacji jest również nazywana „TOKENIZER”. Usuwa również komentarze, generuje tablicę symboli i wpisy w tablicy relokacji.
Ta jednostka sprawdza składnię w kodzie. Na przykład:
{
int a;
int b;
int c;
int d;
d = a + b - c * ;
}
Powyższy kod wygeneruje błąd analizy, ponieważ równanie nie jest zrównoważone. Ta jednostka sprawdza to wewnętrznie, generując drzewo parsera w następujący sposób:
=
/ \
d -
/ \
+ *
/ \ / \
a b c ?
Dlatego ta jednostka jest również nazywana PARSER.
Ta jednostka sprawdza znaczenie w instrukcjach. Na przykład:
{
int i;
int *p;
p = i;
-----
-----
-----
}
Powyższy kod generuje błąd „Przypisanie niezgodnego typu”.
Jednostka ta jest niezależna od procesora, tzn. Istnieją dwa rodzaje optymalizacji
Ta jednostka optymalizuje kod w następujących formach:
Na przykład:
{
int a = 10;
if ( a > 5 ) {
/*
...
*/
} else {
/*
...
*/
}
}
Tutaj kompilator zna wartość „a” w czasie kompilacji, dlatego wie również, że warunek if jest zawsze prawdziwy. Dlatego eliminuje inną część kodu.
Na przykład:
{
int a, b, c;
int x, y;
/*
...
*/
x = a + b;
y = a + b + c;
/*
...
*/
}
można zoptymalizować w następujący sposób:
{
int a, b, c;
int x, y;
/*
...
*/
x = a + b;
y = x + c; // a + b is replaced by x
/*
...
*/
}
Na przykład:
{
int a;
for (i = 0; i < 1000; i++ ) {
/*
...
*/
a = 10;
/*
...
*/
}
}
W powyższym kodzie, jeśli `` a '' jest lokalna i nie jest używana w pętli, można ją zoptymalizować w następujący sposób:
{
int a;
a = 10;
for (i = 0; i < 1000; i++ ) {
/*
...
*/
}
}
W tym przypadku kompilator generuje kod asemblera, dzięki czemu częściej używane zmienne są przechowywane w rejestrach.
Tutaj optymalizacja zależy od procesora. Załóżmy, że jeśli w kodzie jest więcej niż jedno skoki, są one konwertowane na jeden jako:
-----
jmp:<addr1>
<addr1> jmp:<addr2>
-----
-----
Sterowanie przeskakuje bezpośrednio do.
Następnie ostatnią fazą jest Linkowanie (które tworzy plik wykonywalny lub bibliotekę). Po uruchomieniu pliku wykonywalnego, biblioteki, których wymaga, są ładowane.
Reprezentacja 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]
Mam nadzieję, że to pomoże ci trochę bardziej.
Najpierw przejrzyj ten diagram:
(img source->internet)
Następnie tworzysz fragment kodu i zapisujesz plik (kod źródłowy)
Przetwarzanie wstępne : - Jak sama nazwa wskazuje, nie jest to część kompilacji. Instruują kompilator, aby wykonał wymagane wstępne przetwarzanie przed właściwą kompilacją. Możesz wywołać tę fazę podstawianie tekstu lub interpretację specjalnych dyrektyw preprocesora oznaczonych #.
Kompilacja : - Kompilacja to proces, w którym program napisany w jednym języku jest tłumaczony na inny język docelowy. Jeśli wystąpią jakieś błędy, kompilator je wykryje i zgłosi.
Assemble : - Kod asemblacji jest tłumaczony na kod maszynowy. Możesz nazwać asemblera specjalnym typem zgodności.
Łączenie : - Jeśli ten fragment kodu wymaga połączenia innego pliku źródłowego, linker łączy je, aby uczynić go plikiem wykonywalnym.
Po tym następuje wiele procesów. Tak, zgadłeś, że tutaj pojawia się rola ładowarki:
Loader : - ładuje kod wykonywalny do pamięci; program i stos danych są tworzone, rejestr zostaje zainicjowany.
Małe dodatkowe informacje: - http://www.geeksforgeeks.org/memory-layout-of-c-program/ , możesz tam zobaczyć układ pamięci.
Kompilator: Jest to program, który tłumaczy program w języku wysokiego poziomu na program w języku maszynowym. Kompilator jest bardziej inteligentny niż asembler. Sprawdza wszelkiego rodzaju limity, zakresy, błędy itp. Jednak jego czas wykonywania programu jest większy i zajmuje większą część pamięci. Ma małą prędkość. Ponieważ kompilator przechodzi przez cały program, a następnie tłumaczy cały program na kody maszynowe. Jeśli kompilator działa na komputerze i tworzy kody maszynowe dla tego samego komputera, jest znany jako samodzielny kompilator lub kompilator rezydentny. Z drugiej strony, jeśli kompilator działa na komputerze i tworzy kody maszynowe dla innego komputera, jest znany jako kompilator krzyżowy.
Linker: W językach wysokiego poziomu przechowywane są niektóre wbudowane pliki nagłówkowe lub biblioteki. Biblioteki te są predefiniowane i zawierają podstawowe funkcje, które są niezbędne do wykonania programu. Funkcje te są połączone z bibliotekami za pomocą programu o nazwie Linker. Jeśli konsolidator nie znajdzie biblioteki funkcji, informuje o tym kompilator, a następnie kompilator generuje błąd. Kompilator automatycznie wywołuje konsolidator jako ostatni krok w kompilacji programu. Nie wbudowane biblioteki, łączy także funkcje zdefiniowane przez użytkownika z bibliotekami zdefiniowanymi przez użytkownika. Zwykle dłuższy program jest podzielony na mniejsze podprogramy zwane modułami. A te moduły muszą być połączone, aby wykonać program. Proces łączenia modułów jest wykonywany przez konsolidator.
Loader: Loader to program, który ładuje kody maszynowe programu do pamięci systemu. W informatyce moduł ładujący jest częścią systemu operacyjnego odpowiedzialną za ładowanie programów. Jest to jeden z podstawowych etapów procesu uruchamiania programu. Ponieważ umieszcza programy w pamięci i przygotowuje je do wykonania. Ładowanie programu polega na wczytaniu zawartości pliku wykonywalnego do pamięci. Po zakończeniu ładowania system operacyjny uruchamia program, przekazując sterowanie do załadowanego kodu programu. Wszystkie systemy operacyjne obsługujące ładowanie programów mają programy ładujące. W wielu systemach operacyjnych moduł ładujący jest trwale rezydentny w pamięci.
Wikipedia powinna mieć dobrą odpowiedź, oto moje przemyślenia:
*
*
Konsolidatory i programy ładujące z LinuxJournal wyjaśniają tę koncepcję w przejrzysty sposób. Wyjaśnia również, w jaki sposób powstała klasyczna nazwa a.out. (wyjście asemblera)
Krótkie podsumowanie,
c program --> [compiler] --> objectFile --> [linker] --> executable file (say, a.out)
mamy plik wykonywalny, teraz przekaż ten plik znajomemu lub klientowi, który potrzebuje tego oprogramowania :)
kiedy uruchamiają to oprogramowanie, powiedzmy, wpisując je w wierszu poleceń ./a.out
execute in command line ./a.out --> [Loader] --> [execve] --> program is loaded in memory
Po załadowaniu programu do pamięci sterowanie jest przenoszone do tego programu poprzez wskazanie przez komputer PC (licznik programu) pierwszej instrukcji a.out
Odczyta plik źródłowy, który może być typu .c lub .cpp itp. I przetłumaczy go na plik .o nazywany plikiem obiektowym.
Łączy kilka plików .o, które mogą być generowane dla wielu plików źródłowych w plik wykonywalny (format ELF w GCC). Istnieją dwa rodzaje łączenia:
Program, który ładuje plik wykonywalny do pamięci podstawowej maszyny.
Aby uzyskać szczegółowe informacje na temat tych trzech etapów wykonywania programu w systemie Linux, przeczytaj to .
zmiany kompilatora sprawdzają kod źródłowy pod kątem błędów i zmieniają go w kod obiektowy. to jest kod, który uruchamia system operacyjny.
Często nie piszesz całego programu w jednym pliku, więc konsolidator łączy wszystkie pliki z kodem obiektowym.
twój program nie zostanie wykonany, chyba że znajduje się w pamięci głównej
Linker i Interpreter wzajemnie się wykluczają Interpreter pobierający kod wiersz po wierszu i wykonujący wiersz po wierszu.
Kompilator Konwertuje kod źródłowy na kod wynikowy.
Konsolidator Łączy wiele plików obiektowych w jeden wykonywalny plik programu.
Loader Ładuje plik wykonywalny do pamięci głównej.
Kompilator to specjalny program, który przetwarza instrukcje napisane w określonym języku programowania i zamienia je na język maszynowy lub „kod” używany przez procesor komputera
Kompilator tłumaczy wiersze kodu z języka programowania na język maszynowy.
Linker tworzy łącze między dwoma programami.
Loader ładuje program do pamięci w głównej bazie danych, programie itp.
Kompilator: jest to oprogramowanie systemowe, które koryguje błędy programów, pliku obiektowego, komunikatów itp
Linker: jest to oprogramowanie systemowe, które łączy jeden lub więcej plików obiektowych i być może jakiś kod biblioteki w jakąś możliwą do wykonania bibliotekę lub listę błędów
Program ładujący: program, który ładuje plik wykonywalny do pamięci podstawowej maszyny