Jump to content
ghici

[Curs] C - Despre compilator

Recommended Posts

Avand in vedere ca e prima lectie din curs, sa va spun despre ce e vorba. Cursul il fac pe un sistem UNIX (FreeBSD 6.1) si folosesc ca si compilator cc. Nu e obligatoriu sa folositi si voi acelasi sistem si acelasi compilator, dar e de preferat sa aveti la dispozitie un shell UNIX pentru a nu aparea pe parcurs probleme de incompatibilitate. In principiu nu ar trebui sa apara probleme daca folositi ca sistem de operare orice alt sistem UNIX sau UNIX-like sau daca in loc de cc folositi gcc.

Daca singurul sistem de operare care il aveti la dispozitie e un Windows aveti doua variante... fie va faceti rost de un LiveCD cu care rulati Linux pe perioada testelor fie va faceti un cont la arbornet.org (sau oriunde altundeva puteti) si faceti testele "remote".

Pentru prima lectie avem nevoie de sursa unui program simplu. Cel mai simplu program (corect) posibil este urmatorul:

int main(){

       return 0;

}

Ce face programul ? Absolut nimic. Si prin nimic inteleg: nu accepta nici un fel de date de intrare si (la prima vedere) nu da nici un fel de date de iesire. Intram mai in amanunt mai tarziu, momentan sa vedem ce face un compilator.

Compilatoarele sunt de multe feluri fiecare cu avantajele si dezavantajele lui. Probabil ati auzit de cele mai comune compilatoare sub UNIX, cc, CC, gcc, g++ sau altele. Ce fac compilatoarele astea ?

Ca sa intelegeti ce fac compilatoarele, intru putin in dedesubturile programelor. Un program este facut in cod masina. Adica, un cod care il intelege doar sistemul de operare, un cod in care fiecare caracter (octet) reprezinta ceva, o instructiune, ceva ce trebuie facut. Daca deschideti un executabil cu un editor de texte obisnuit va dati seama despre ce vorbesc...

Codul masina e destul de greu de inteles pentru oamenii de rand si foarte greu de depanat, asa ca s-au facut limbaje de programare. Limbajele de programare sunt niste reguli de compozitie care puse cap-la-cap pot fi prelucrate de un alt program (compilator) pentru a fi transformate din cuvinte usor de inteles in cod masina. Primul limbaj de programare care a aparut, limbajul cel mai apropiat de codul masina, este limbajul de asamblare. Limbajul de asamblare este cel mai "brut" limbaj posibil... adica atunci cand programati in limbaj de asamblare lucrati direct cu registrii procesorului, cu intreruperile BIOS (sau apelurile de sistem in UNIX), de fapt... vorbiti pur si simplu cu procesorul si componentele care le aveti in PC.

Oricat de rapid si apropiat de codul masina ar fi limbajul de asamblare, este totusi greoi. Chiar daca este mult mai usor de inteles decat codul masina, trebuie multe cunostinte de functionare interna a CPU-ului pentru a putea programa in limbaj de asamblare. Astfel, s-au facut alte limbaje de nivel inalt (BASIC, Fortran, Pascal, etc). Limbajele de nivel inalt au avantajul ca inteleg ce vrem noi sa spunem chiar daca nu vorbim direct cu procesorul si chiar daca spunem doar 2 cuvinte in loc de o pagina de instructiuni de genul jne, mov, push etc. De fapt, ce fac limbajele de nivel inalt ? Asta urmeaza sa vedem mai departe.

Limbajele de nivel inalt nu valoreaza nimic fara un compilator. Compilatorul este cel care da putere limbajului. A invata un limbaj de programare e ca si cum ati invata o limba straina. E un lucru foarte util mai ales daca e vorba de limba engleza sau franceza dar e complet inutil sa stii o limba straina daca nu exista o persoana care sa asculte si sa inteleaga ceea ce spui. In cazul calculatoarelor, "persoana" care intelege si aplica ceea ce spunem este compilatorul. Un compilator ia informatia care o dam intr-o anumita forma (adica scrisa intr-un limbaj de nivel inalt) si o transforma intr-un limbaj necunoscut noua... transforma codul dat de noi in Fortran, C, Pascal, Basic in limbaj de asamblare.

Deci, ca sa tragem o concluzie, un compilator al unui limbaj de nivel inalt ia codul scris de noi si il transforma intr-un cod echivalent scris in limbaj de asamblare. Asta ar fi prima faza prin care trece un program... orice program ati scrie, in orice limbaj, inainte de a-l putea rula este "translatat" in limbaj de asamblare.

Al doilea pas care il face compilatorul e sa ia codul translatat si din el sa genereze un fisier obiect care poate fi inclus mai apoi intr-un executabil. In UNIX fisierele obiect le recunoasteti dupa extensia .o. Stiu, peste tot ati citit ca in UNIX nu conteaza extensia, dar ca regula toate fisierele obiect au extensia .o.

Al treilea pas care il face compilatorul e sa ia fisierul obiect generat, si impreuna cu alte fisiere obiect (daca sunt specificate) sa formeze un program executabil, acesta fiind ultimul pas.

Probabil, cei mai experimentati, stati si va intrebati "Cum naiba face atatia pasi ? ca eu ii dau comana si imi da executabilul..." Aveti dreptate. Orice compilator nou mascheaza tot procesul de compilare si afiseaza doar rezultatul final, dar este important sa intelegeti toate etapele prin care trece un program de la creerea lui pana la punerea in utilizare.

OK, acum ca ati inteles (sper) ideea de compilare sa facem si cateva exemple sa vedem concret cum se comporta compilatorul:

Compilare standard



bash2-2.05b$ cat l1.c

int main(){

       return 0;

}

bash2-2.05b$ cc l1.c -o l1

bash2-2.05b$ ./l1

bash2-2.05b$

* l1.c este fisiul care contine codul prezentat mai sus

Ce am facut ? Prima data am folosit comanda cat care imi arata continutul fisierului l1.c. Nu e obligatorie... am facut-o doar pentru a intelege "cine" e l1.c

apoi am rulat comanda cc l1.c -o l1. cc este compilatorul standard in UNIX. In FreeBSD si in majoritatea distributiilor de Linux, cc este de fapt un alias pentru gcc (GNU C Compiler). Am apelat comanda cc si i-am dat ca parametru fisierul l1.c (fisierul sursa) si -o l1 care ii spune compilatorului sa puna rezultatul final in fisierul l1.

Compilarea a decurs fara probleme, am rulat fisierul rezultat ( ./l1 ) care nu a facut nimic (dupa cum v-am spus si mai sus) si acum suntem din nou fata-in-fata cu promptul.

Bun, hai sa trecem mai departe sa vedem concret ce s-a intamplat. Vom forta compilatorul sa ne arate fiecare pas care il face.

Primul pas

Dupa cum am spus, primul pas este "transformarea" codului C in limbaj de asamblare. Ca sa fortam compilatorul sa ne arate acest pas, folosim parametru -S care ii spune sa salveze sursa in limbaj de asamblare iar apoi sa se opreasca (adica nu compileaza programul). Sa vedem ce iasa:



bash2-2.05b$ cat l1.c

int main(){

       return 0;

}

bash2-2.05b$ cc -S l1.c

bash2-2.05b$ cat l1.s

       .file   "l1.c"

       .text

       .p2align 2,,3

.globl main

       .type   main, @function

main:

       pushl   %ebp

       movl    %esp, %ebp

       subl    $8, %esp

       andl    $-16, %esp

       movl    $0, %eax

       addl    $15, %eax

       addl    $15, %eax

       shrl    $4, %eax

       sall    $4, %eax

       subl    %eax, %esp

       movl    $0, %eax

       leave

       ret

       .size   main, .-main

       .ident  "GCC: (GNU) 3.4.4 [FreeBSD] 20050518"

bash2-2.05b$

Dupa cum vedeti, am folosit din nou comanda cat pentru a vedea continutul fisierului l1.c. Apoi am executat comanda cc -S l1.c care a luat fisierul l1.c (sursa programului) si a generat sursa echivalenta in limbaj de asamblare care a salvat-o in fisierul l1.s. Din nou am folosit comanda cat pentru a vedea continutul fisierului l1.s (daca nu intelegeti nimic, nu-i nici o problema... foarte probabil nu veti avea nevoie de asa ceva niciodata).

Al doilea pas

Al doilea pas in compilarea programului presupune sa luam sursa generata (l1.s) si sa creem un fisier obiect. Pentru asta folosim compilatorul cc cu parametrul -c. Mai jos vedeti exemplul:

bash2-2.05b$ cc l1.s -c

bash2-2.05b$ ls

l1.c  l1.o  l1.s

bash2-2.05b$ file l1.o

l1.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (FreeBSD),

not stripped

bash2-2.05b$

Ce am facut ? Am dat comanda cc l1.s -c care a preluat fisierul l1.s (care contine programul in limbaj de asamblare) si am generat fisierul obiect ( parametrul -c ). Dupa cum vedeti, a aparut fisierul l1.o care il putem include intr-un alt program sau il putem trece prin faza de link-are, adica de creare a programului. Am folosit comanda file pentru a verifica tipul fisierului. Rezultatul ne confirma ca este un fisier ELF 32-bit LSB reloctable, adica un fisier obiect.

Al treilea pas - ultimul

Si, intr-un final, folosim din nou comanda cc pentru a genera fisierul executabil din fisierul l1.o. Asta se face in felul urmator:

bash2-2.05b$ cc l1.o -o l1

bash2-2.05b$ ls

l1*   l1.c  l1.o  l1.s

bash2-2.05b$ file l1

l1: ELF 32-bit LSB executable, Intel 80386, version 1 (FreeBSD),

for FreeBSD 6.1, dynamically linked (uses shared libs), not stripped

bash2-2.05b$

Ce am facut ? Am apelat comanda cc l1.o -o l1 care a preluat fisierul l1.o si a creat un executabil caruia i-a dat numele l1. Daca nu specificam -o l1 compilatorul salva executabilul cu numele a.out. Dupa cum se poate vedea, din nou am folosit comanda file care ne arata de data asta ca fisierul este de tipul ELF 32-bit LSB executable, adica un "executabil cu acte in regula".

Rezumat

1. Un compilator este un program care ia codul sursa scris de noi intr-un limbaj de nivel inalt (in cazul nostru C) si il transforma intr-un cod sursa echivalent in limbajul de asamblare care apoi este transformat intr-un fisier obiect care este apoi inclus intr-un executabil scris in cod masina.

2. Pentru a studia fiecare pas care il face compilatorul putem folosi parametrii -S pentru a salva sursa in limbaj de asamblare si -o pentru a salva fisierul obiect inainte ca acesta sa fie inclus intr-un fisier executabil.

3. Pentru a ne usura treaba, compilatoarele moderne ne dau direct executabilul facand restul fazelor de compilare transparente pentru utilizator.

4. Chiar daca e mult text, compilarea nu are nimic mistic sau filosofic in ea si e la mintea oricui

Link to comment
Share on other sites

Bravo, ghici !

Keep it up ! Buna treaba !

Astept si urmatoarele lectii ! :@

P.S.

In caz ca nu esti la curent, nu mai scriu lectii pana cand nu am destui useri. Cand ma reapuc sa le scriu te anunt ca sa le poti posta fara credite !

-- Operabilus

Pentru restu userilor, cursul se tine pe http://sunthacer.gay.com/ nu aici. Ghici e doar unu care mi-a "imprumutat" cursul. Daca va intereseaza si daca vreti mai multe lectii anuntati-ma. Daca nu, cursul se opreste la "Lectia 02" :@

Link to comment
Share on other sites

<div class='quotetop'>QUOTE("6CMNWW")</div>

Bravo, ghici !

Keep it up ! Buna treaba !

Astept si urmatoarele lectii !  :@  

P.S.

In caz ca nu esti la curent, nu mai scriu lectii pana cand nu am destui useri. Cand ma reapuc sa le scriu te anunt ca sa le poti posta fara credite !

-- Operabilus

Pentru restu userilor, cursul se tine pe http://sunthacer.gay.com/  nu aici. Ghici e doar unu care mi-a "imprumutat" cursul. Daca va intereseaza si daca vreti mai multe lectii anuntati-ma. Daca nu, cursul se opreste la "Lectia 02"  :@

Neinteresant!

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...