This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
laboratoare:laborator-02 [2015/10/21 01:16] razvan.deaconescu [4.[40p] C: GOTOs] |
laboratoare:laborator-02 [2015/10/23 19:05] (current) razvan.deaconescu [4. [40p] C: GOTOs] |
||
---|---|---|---|
Line 1: | Line 1: | ||
====== Laborator 02: Toolchain ====== | ====== Laborator 02: Toolchain ====== | ||
+ | |||
În acest laborator, vom trece prin fiecare nivel de procesare a unui limbaj de nivel înalt și prin toolchain-ul pe care îl vom folosi de acum încolo. | În acest laborator, vom trece prin fiecare nivel de procesare a unui limbaj de nivel înalt și prin toolchain-ul pe care îl vom folosi de acum încolo. | ||
===== C basics: GOTOs ===== | ===== C basics: GOTOs ===== | ||
+ | |||
Un concept mai puțin abordat în tutoriale de C este instrucțiunea **goto**. | Un concept mai puțin abordat în tutoriale de C este instrucțiunea **goto**. | ||
- | Prin instrucțiunea **goto**, un program poate sării în puncte intermediare în cadrul unei funcții. | + | Prin instrucțiunea **goto**, un program poate sări în puncte intermediare în cadrul unei funcții. |
- | Aceste puncte intermediare se numesc **label**-uri (etichete).\\ | + | Aceste puncte intermediare se numesc **label**-uri (etichete). |
Un exemplu de cod: | Un exemplu de cod: | ||
<code c> | <code c> | ||
Line 23: | Line 26: | ||
} | } | ||
</code> | </code> | ||
+ | |||
Programul execută un job prin **work()**. În caz că mai sunt alte joburi neterminate, programul sare la labelul **do_some_work**.\\ | Programul execută un job prin **work()**. În caz că mai sunt alte joburi neterminate, programul sare la labelul **do_some_work**.\\ | ||
**do_some_work** este punctul din program în care începe procesarea unui nou job. Acesta e marcat printr-un nume urmat de **:**. | **do_some_work** este punctul din program în care începe procesarea unui nou job. Acesta e marcat printr-un nume urmat de **:**. | ||
- | Pentru a sării la acest punct din program se folosește instrucțiunea **goto** urmată de numele etichetei declarate. | + | Pentru a sări la acest punct din program se folosește instrucțiunea **goto** urmată de numele etichetei declarate. |
Prin diferite combinații de **if**-uri si **goto**-uri se pot echivala alte instrucțiuni din C, cum ar fi **else**, **for** si **while**.\\ | Prin diferite combinații de **if**-uri si **goto**-uri se pot echivala alte instrucțiuni din C, cum ar fi **else**, **for** si **while**.\\ | ||
Codul dat exemplu mai sus ar putea fi un candidat care să înlocuiască o instrucțiune ''%%do { /* ... */ } while ();%%'': | Codul dat exemplu mai sus ar putea fi un candidat care să înlocuiască o instrucțiune ''%%do { /* ... */ } while ();%%'': | ||
Line 152: | Line 156: | ||
În cazul compilatorului **gcc** este de ajuns să adăugați flag-ul **-S** și vă va genera un fișier ***.s** cu codul aferent. | În cazul compilatorului **gcc** este de ajuns să adăugați flag-ul **-S** și vă va genera un fișier ***.s** cu codul aferent. | ||
- | În arhiva de [[|aici]] aveți un exemplu de trecere a unui program foarte simplu ''hello.c'' prin cele patru faze. Îl puteți testa pe un sistem Unix/Linux și pe un sistem Windows cu suport de MinGW. Pe sistemele din laborator există suport MinGW și îl veți putea testa folosind comanda ''make'' la fel ca mai jos și apoi diversele fișiere:<code> | + | În arhiva de {{:laboratoare:compiler-phases.zip|aici}} aveți un exemplu de trecere a unui program foarte simplu ''hello.c'' prin cele patru faze. Îl puteți testa pe un sistem Unix/Linux și pe un sistem Windows cu suport de MinGW. Pe sistemele din laborator există suport MinGW și îl veți putea testa folosind comanda ''make'' la fel ca mai jos și apoi diversele fișiere:<code> |
$ make | $ make | ||
cc -E -o hello.i hello.c | cc -E -o hello.i hello.c | ||
Line 229: | Line 233: | ||
</note> | </note> | ||
===== Toolchain ===== | ===== Toolchain ===== | ||
- | În cadrul laboratorului vom folosii asamblorul [[http://www.nasm.us/|NASM]]. Acesta este foarte folosit în tutoriale și cărți legate de scrierea programelor în limbaje de asamblare.\\ | + | În cadrul laboratorului vom folosi asamblorul [[http://www.nasm.us/|NASM]]. Acesta este foarte folosit în tutoriale și cărți legate de scrierea programelor în limbaje de asamblare.\\ |
- | Ca IDE vom folosii [[http://dman95.github.io/SASM/english.html|SASM]]. Pe Windows dispune de un installer de tipul next-next-next. Vine cu tool-urile aferente(inclusiv NASM) și este preconfigurat corespunzător.\\ | + | Ca IDE vom folosi [[http://dman95.github.io/SASM/english.html|SASM]]. Pe Windows dispune de un installer de tipul next-next-next. Vine cu tool-urile aferente(inclusiv NASM) și este preconfigurat corespunzător.\\ |
Ambele programe menționate sunt open-source și valabile pe toate platformele cunoscute (Windows, Linux și MacOS). | Ambele programe menționate sunt open-source și valabile pe toate platformele cunoscute (Windows, Linux și MacOS). | ||
===== Exerciții: ===== | ===== Exerciții: ===== | ||
- | ==== 1. [20p] online C compiling ==== | + | ==== 1. [20p] Online C Compiling ==== |
Un tool interesant pentru a observa cum se traduce codul C în limbaj de asamblare este **Compiler Explorer**. | Un tool interesant pentru a observa cum se traduce codul C în limbaj de asamblare este **Compiler Explorer**. | ||
- Intrați pe [[http://gcc.godbolt.org/|Compiler Explorer]]. | - Intrați pe [[http://gcc.godbolt.org/|Compiler Explorer]]. | ||
- | - Încărcați programul "sum over array" de la exemple, adică selectați combobox-ul ''Name''. | + | - Încărcați programul "sum over array" din exemple (accesibile folosind intrările ''Source: Examples'' și ''Name: sum over array''). |
- Asigurați-vă că **x86 gcc 4.8.2** este selectat la **Compiler:**. | - Asigurați-vă că **x86 gcc 4.8.2** este selectat la **Compiler:**. | ||
- Selectați **Intel syntax**. Acesta este un format mai ușor de digerat și mai asemănător formatului acceptat de NASM. | - Selectați **Intel syntax**. Acesta este un format mai ușor de digerat și mai asemănător formatului acceptat de NASM. | ||
Line 246: | Line 250: | ||
- Treceți, pe rând, prin compilatoarele corespunzătoare următoarelor arhitecturi: ARM, ARM64, AVR, PowerPC. Se poate observa cum codul generat diferă de la o arhitectură la alta. | - Treceți, pe rând, prin compilatoarele corespunzătoare următoarelor arhitecturi: ARM, ARM64, AVR, PowerPC. Se poate observa cum codul generat diferă de la o arhitectură la alta. | ||
- Mai încercați și următoarele compilatoare: **clang** și **icc**. După cum se poate observa, deși este același cod C și aceeași arhitectură, codul generat diferă. Acest lucru se întâmplă pentru că fiecare compilator poate avea o strategie de optimizare și generare de cod diferită. | - Mai încercați și următoarele compilatoare: **clang** și **icc**. După cum se poate observa, deși este același cod C și aceeași arhitectură, codul generat diferă. Acest lucru se întâmplă pentru că fiecare compilator poate avea o strategie de optimizare și generare de cod diferită. | ||
- | + | ||
<note> | <note> | ||
[[http://clang.llvm.org/|clang]] este un compilator open-source de C\C++. Adesea este folosit în IDE-uri datorită mesajelor de eroare de compilare foarte sugestive pe care le produce. | [[http://clang.llvm.org/|clang]] este un compilator open-source de C\C++. Adesea este folosit în IDE-uri datorită mesajelor de eroare de compilare foarte sugestive pe care le produce. | ||
Line 254: | Line 258: | ||
**icc** este compilatorul de C\C++ al celor de la compania Intel. | **icc** este compilatorul de C\C++ al celor de la compania Intel. | ||
</note> | </note> | ||
+ | |||
+ | ---- | ||
+ | |||
+ | Scrieți în zona ''Code editor'' următoarea secvență de cod:<code> | ||
+ | int simple_fn(void) | ||
+ | { | ||
+ | int a = 1; | ||
+ | a++; | ||
+ | return a; | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Observați codul în limbaj de asamblare atunci când opțiunile de compilare (''Compiler options'') sunt ''-m32'', respectiv atunci când opțiunile de compilare sunt ''-m32 -O2''. Observați ce efect au opțiunile de optimizare asupra codului în limbaj de asamblare generat. | ||
==== 2.[20p] Microsoft Visual Studio: from C to assembly ==== | ==== 2.[20p] Microsoft Visual Studio: from C to assembly ==== | ||
+ | |||
La exercițiul anterior am abordat compilatoarele gcc, clang și icc pentru a observa cam ce cod de asamblare produc. În acest exercițiu vom trece în revistă și compilatorul celor de la Microsoft (valabil pe Microsoft Windows, evident).\\ | La exercițiul anterior am abordat compilatoarele gcc, clang și icc pentru a observa cam ce cod de asamblare produc. În acest exercițiu vom trece în revistă și compilatorul celor de la Microsoft (valabil pe Microsoft Windows, evident).\\ | ||
- | În primă fază deschideți Microsoft Visual Studio și creați un nou proiect gol. Creați un fișier nou **main.cpp** și adăugați următorul cod: | + | În primă fază deschideți Microsoft Visual Studio și creați un nou proiect gol. |
+ | |||
+ | <note tip> | ||
+ | Pentru a crea un proiect gol, folosiți ''File -> New project'', apoi selectați ''Win32 Console Application'' și selectați ''Empty Project''. | ||
+ | </note> | ||
+ | |||
+ | Pentru a adăuga un fișier nou în cadrul proiectului mergeți cu mouse-ul în zona ''Solution Explorer'' (din partea dreapta sus a ecranului) și apoi folosiți click dreapta pe intrarea ''Source files'', apoi folosiți ''Add'' și apoi, după caz, ''New Item'' sau ''Existing Item''. Adăugați un fișier nou în **cadrul proiectului**, numit ''main.cpp'' și adăugați următorul cod în fișier: | ||
<code c> | <code c> | ||
#define DATA_LEN 100 | #define DATA_LEN 100 | ||
Line 289: | Line 313: | ||
Dați **Clean Project** și apoi **Build Project**. În acest moment vi s-a generat un fișier ***.asm**, dar care nu va apărea în Visual Studio.\\ | Dați **Clean Project** și apoi **Build Project**. În acest moment vi s-a generat un fișier ***.asm**, dar care nu va apărea în Visual Studio.\\ | ||
- | Pentru a vizualiza fișierul în cauză, dați click dreapta pe **Solution //nume_proiect//** și selectați **Open Folder in File Explorer**. În folderul **//nume_proiect//\Debug** veți găsi fișierul **Source.asm** corespunzător programului scris în C. După cum puteți observa, acesta conține codul de asamblare intercalat cu comentarii în care este prezentat codul original. | + | Pentru a vizualiza fișierul în cauză, dați click dreapta pe **Solution //nume_proiect//** și selectați **Open Folder in File Explorer**. În directoare **//nume_proiect//\Debug** veți găsi fișierul **Source.asm** corespunzător programului scris în C. După cum puteți observa, acesta conține codul de asamblare intercalat cu comentarii în care este prezentat codul original. |
+ | |||
+ | <note important> | ||
+ | Există două directoare cu numele ''Debug'': unul aferent soluției și altul aferent proiectului. Alegeți directorul ''Debug'' aferent proiectului. | ||
+ | </note> | ||
+ | ==== 3. [20p] SASM: walkthrough ==== | ||
- | ==== 3.[20p] SASM: walktrough ==== | ||
=== 3.1 Proiect nou === | === 3.1 Proiect nou === | ||
- | Pentru a crea un proiect nou intrați la **File -> New** | + | |
+ | Pentru a crea un proiect nou intrați la **File -> New**. | ||
=== 3.2 Ferestre === | === 3.2 Ferestre === | ||
+ | |||
{{ :laboratoare:sasm-window.png |}} | {{ :laboratoare:sasm-window.png |}} | ||
+ | |||
Legendă: | Legendă: | ||
- editorul | - editorul | ||
- fereastră în care se pot transmite date programului | - fereastră în care se pot transmite date programului | ||
- fereastră în care se afișează outputul programului | - fereastră în care se afișează outputul programului | ||
- | - logging pentru build, clean, run | + | - logging pentru build, clean, run |
=== 3.3 Butoane === | === 3.3 Butoane === | ||
+ | |||
- {{:laboratoare:build.png|Build}} Build - construiește executabilul | - {{:laboratoare:build.png|Build}} Build - construiește executabilul | ||
- {{:laboratoare:run.png|Run}} Run - rulare normală a programului | - {{:laboratoare:run.png|Run}} Run - rulare normală a programului | ||
Line 309: | Line 343: | ||
- {{:laboratoare:stepover.png|Step over}} Step over - dacă instrucțiunea curentă apelează o funcție, debugger-ul va executa funcția ca și cum ar fi o singură instrucțiune | - {{:laboratoare:stepover.png|Step over}} Step over - dacă instrucțiunea curentă apelează o funcție, debugger-ul va executa funcția ca și cum ar fi o singură instrucțiune | ||
- {{:laboratoare:continue.png|Continue}} Continue - continuă execuția până la următorul breakpoint sau până se termină programul | - {{:laboratoare:continue.png|Continue}} Continue - continuă execuția până la următorul breakpoint sau până se termină programul | ||
+ | |||
=== 3.4 Modul debugging === | === 3.4 Modul debugging === | ||
+ | |||
În modul debugging (programul rulat cu {{:laboratoare:debug.png|Debug}}), vă mai apare o ferestră cu resursele procesorului (starea registrelor sale):\\ | În modul debugging (programul rulat cu {{:laboratoare:debug.png|Debug}}), vă mai apare o ferestră cu resursele procesorului (starea registrelor sale):\\ | ||
{{:laboratoare:registers-window.png|}}\\ | {{:laboratoare:registers-window.png|}}\\ | ||
Line 323: | Line 359: | ||
==== 4. [40p] C: GOTOs ==== | ==== 4. [40p] C: GOTOs ==== | ||
- | Implementați algoritmii de mai jos în C **fără a folosi apeluri de funcţii (exceptând //scanf()// şi //printf()//), else, for, while, do {} while; și construcțiile cu if nu pot conține return**. Adică va trebui să folosiți multe instrucțiuni ''goto''. | + | <note important> |
- | - maximul dintr-un vector [20p] | + | |
- | - căutare binară [20p] | + | Când scrieți cod cu etichete (label-uri) țineți cont de următoarele recomandări de indentare: |
+ | * Nu indentați etichetele (label-urile). "Lipiți-le" de marginea din stânga a ecranului de editare. | ||
+ | * O etichetă este singură pe linie. Nu există cod după etichetă. | ||
+ | * Nu țineți cont de indentare în indetarea codului. Codul trebuie indendat în același mod și cu etichete și fără etichete. | ||
+ | * Puneți o linie liberă înaintea linie care conține o etichetă. | ||
+ | |||
+ | </note> | ||
+ | |||
+ | Pentru algoritmii de mai jos scrieți cod în C **fără** a folosi: | ||
+ | * apeluri de funcţii (exceptând //scanf()// şi //printf()//) | ||
+ | * else | ||
+ | * for | ||
+ | * while | ||
+ | * do {} while; | ||
+ | * construcțiile ''if'' care conțin return | ||
+ | |||
+ | Adică va trebui să folosiți ''if'' și multe instrucțiuni ''goto''. | ||
+ | |||
+ | **[20p]** Implementați maximul dintr-un vector folosind cod C și constrângerile de mai sus. | ||
+ | |||
+ | **[20p]** Implementați căutare binară folosind cod C și constrângerile de mai sus. | ||
<note warning> | <note warning> | ||
Reiterăm ideea că scenariile de utilizare ale instrucțiunii ''goto'' sunt limitate. Exercițiile acestea au valoare didactică pentru a vă acomoda cu instrucțiuni de salt (//jump//) pe care le vom folosi în dezvoltarea în limbaj de asamblare. | Reiterăm ideea că scenariile de utilizare ale instrucțiunii ''goto'' sunt limitate. Exercițiile acestea au valoare didactică pentru a vă acomoda cu instrucțiuni de salt (//jump//) pe care le vom folosi în dezvoltarea în limbaj de asamblare. | ||
+ | </note> | ||
+ | |||
+ | <note tip> | ||
+ | Pentru scrierea de programe puteți folosi orice editor indicat pe Desktop sau IDE-urile Code::Blocks sau Visual Studio. | ||
+ | |||
+ | Pentru compilarea/rularea codului puteți folosi IDE-urile Code::Blocks sau Visual Studio sau puteți folosi linia de comandă ca mai jos. | ||
+ | |||
+ | Pentru a compila un fișier cod sursă C/C++ în linia de comandă folosind Visual Studio, urmați pașii: | ||
+ | - Deschideți butonul de start, selectați ''All apps'' , apoi mergeți la litera ''V'', selectați directorul ''Visual Studio 2015'' și alegeți opțiunea ''Visual Studio x86 Native Command Prompt''. | ||
+ | - Accesați directorul în care aveți codul sursă. | ||
+ | - Folosiți comanda<code> | ||
+ | cl <nume-fisier>.cpp | ||
+ | </code> unde ''<nume-fisier>'' este numele fișierului. | ||
+ | - Rulați executabilul obținut folosind comanda<code> | ||
+ | .\nume-fisier | ||
+ | </code> unde ''<nume-fisier>'' este numele fișierului. | ||
+ | |||
+ | /* | ||
+ | Pentru a compila un fișier cod sursă C/C++ în linia de comandă folosind GCC, urmați pașii: | ||
+ | - Deschideți un Command Prompt. | ||
+ | - Adăugați calea către GCC la ''PATH'' folosind comanda<code> | ||
+ | PATH=%PATH%;C:\MinGW\bin | ||
+ | </code> | ||
+ | - Folosiți comanda<code> | ||
+ | g++ <nume-fisier>.cpp | ||
+ | </code> unde ''<nume-fisier>'' este numele fișierului. Sau puteți folosi<code> | ||
+ | gcc <nume-fisier>.c | ||
+ | </code> pentru fișier cod sursă scris în C (nu în C++). | ||
+ | - Rulați executabilul obținut folosind comanda<code> | ||
+ | .\nume-fisier | ||
+ | </code> unde ''<nume-fisier>'' este numele fișierului. | ||
+ | |||
+ | */ | ||
+ | |||
</note> | </note> | ||