Sunteți pe pagina 1din 15

Laborator 2

2.1 Arhitectura Intel x86


2.1.1 Structura unui sistem de calcul (consideraii generale) Majoritatea sistemelor de calcul din zilele noastre (i nu numai) sunt constituite din 3 tipuri de componente: memoria principal unitatea central de prelucrare (n englez Central Processing Unit CPU) dispozitive de intrare/ieire

Memoria principal a sistemului este direct accesibil de ctre unitatea central de prelucrare, i poate conine date sau cod (vom vedea ulterior c acesta este doar un tip mai special de date). Acest tip de memorie se mai numete i memorie RAM (Random Access Memory), deoarece orice locaie aleatoare din aceasta, poate fi adresat n timp constant (spre deosebire de discurile magnetice, care favorizeaz citirea datelor secvenial, sau de memoriile asociative, unde datele sunt accesate prin coninut, nu prin adres). O alt caracteristic a memoriei principale este volatilitatea. Atunci cnd alimentarea cu energie a sistemului este ntrerupt, coninutul acesteia se pierde. Unitatea central de prelucrare este un circuit care execut instruciunile dintr-un program, citind sau scriind date din memorie, efectund diverse operaii asupra acestora, sau accesnd dispozitivele de intrare/ieire. Dispozitivele de intrare/ieire fac diferena dintre un sistem de calcul i alte aparate care consum energie electric i produc cldur. Cele mai ntlnite astfel de dispozitive sunt tastatura, mouse-ul, monitorul, respectiv mediile de stocare. Prin acestea se asigur interaciunea cu utilizatorul.

2.1.2 Familia Intel x86 Familia de procesoare x86 este, n prezent, cea mai folosit pe piaa calculatoarelor desktop (n timp ce procesoarele ARM domin piaa dispozitivelor mobile). Dei aceste procesoare au evoluat de-a lungul timpului, suferind diverse modificri arhitecturale, s-a pus un accent deosebit pe pstrarea compatibilitii. Astfel, un program scris pentru generaia '386 va rula fr probleme pe un procesor Intel de ultim generaie.

Procesoarele mai vechi au fost procesoare pe 16 bit, ceea ce nsemna c registrele acestora (vom vedea ce nseamn registru n seciunea urmtoare) aveau o lungime de 16 bit, iar instruciunile erau mai scurte. Generaia a 3-a (80386) a adus procesoare pe 32 bit, n care regitrii au lungimi pe 32 bit, iar setul de instruciuni este mbogit. Se pstreaz compatibilitatea cu procesoarele pe 16 bit, dar apar instruciuni noi, precum i concepte noi, cum ar fi modul virtual de operare. Unul din principalele dezavantaje ale sistemelor pe 32 bit este faptul c nu pot adresa mai mult de 4GB de memorie RAM (un sistem pe 16 bit putea adresa maxim 1MB de memorie convenional). Aplicaiile moderne, ce proceseaz volume mari de date au nevoie de spaii de memorie mai largi. Au aprut astfel procesoarele pe 64 bit, care pot adresa pn la 256 TB (se folosesc doar 48, din cei 64 bit pentru adrese).

2.1.3 Arhitectura setului de instruciuni n continuare, se vor discuta componentele procesorului, vizibile pentru un programator n limbaj de asamblare. Astfel, un procesor dispune de un set de regitri interni folosii pentru pstrarea temporar a datelor, a adreselor sau a instruciunilor. Exist regitri generali folosii n majoritatea operaiilor aritmetico-logice i regitri speciali, care au o destinaie special. Procesoarele x86 conin 8 regitri de uz general: EAX Accumulator EBX Base ECX Counter EDX Data ESI Source Index EDI Destination Index EBP Base Pointer ESP Stack Pointer

Fiecare dintre acetia poate stoca o valoare pe 32 bit. Denumirea acestor regitri ncepe cu litera E (de la Extended), deoarece sunt extensii ale regitrilor de uz general pe 16 bit: AX, BX, CX, DX, SI, DI, BP, SP. Dac se doresc doar cei mai puin semnificativi 16 bit dintr-un astfel de registru, se pot folosi aceste denumiri pe 16 bit. n plus, pentru primii 4 dintre aceti regitri se pot adresa separat cei mai puin semnificativi 2 octei, adic biii 0..7, respectiv 8..15, folosind

denumirile *L, respectiv *H, unde * poate fi una din literele A, B, C sau D. n figura de mai jos sunt exemplificate prile adresabile ale registrului EAX.

Un alt registru important este EFLAGS, n care sunt reinui diveri indicatori de stare sau control ai sistemului.

O parte din aceste flag-uri sunt:

CF Carry Flag este setat pe 1, dac la operaia anterioar, s-a generat un transport

PF Parity Flag indic paritatea rezultatului generat anterior AF Auxiliary Carry Flag indic faptul c la operaia anterioar, pe cei mai puin semnificativi 4 bii, s-a generat un transport ZF Zero Flag se seteaz dac rezultatul operaiei anterioare este 0 SF Sign Flag indic semnul rezultatului generat anterior OF Overflow Flag indic o depire de capacitate, la ultima operaie aritmetic

Registrul EIP (Instruction Pointer), pe 32 bit, indic locaia n memorie a urmtoarei instruciuni ce va fi executat. Acest registru se mai numete uneori i PC (Program Counter). EIP nu poate fi modificat direct, precum regitrii de uz general, dar se modific indirect, prin instruciuni de control al fluxului de instruciuni. Regitrii segment (denumii selectori, n asamblarea pe 32 bit) sunt regitri pe 16 bit, i particip la formarea unei adrese, sau pointeaz ctre o tabel de descriptori. Aceti regitri sunt: CS (Code Segment), DS (Data Segment), SS (Stack Segment), ES (Extended Segment), FS, respectiv GS. Procesorul tie s execute diverse tipuri de instruciuni, avnd ca operanzi regitri, adrese sau date din memoria principal, sau date imediate: instruciuni aritmetice i logice Spre exemplu, ADD EAX, EBX adun valoarea din registrul EBX, la cea din registrul EAX, registrul EAX coninnd rezultatul obinut. SUB AH, 5 va scdea 5 din valoarea coninut n registrul AH. instruciuni de transfer a datelor Sunt folosite pentru a copia date dintr-un registru n altul, sau din/n memorie. MOV EDX, EAX va copia coninutul registrului EDX n EAX. MOV ECX, [123456H] va copia n registrul ECX valoarea aflat n memoria principal la adresa 123456H. instruciuni de control al fluxului de instruciuni Se folosesc atunci cnd se dorete ca urmtoarea instruciune executat s fie alta dect urmtoarea instruciune din program. De exemplu JZ 100 (Jump if Zero) va sri peste urmtorii 100 de octei din program, dac rezultatul operaie anterioare a fost 0, altfel va executa instruciunea urmtoare.

2.1.4 Organizarea memoriei La organizarea memoriei, se ntlnesc 2 moduri de adresare: modul real i modul protejat:

n modul real spaiul maxim de adresare al memoriei este de 1MB. Aceast memorie este mprit n segmente de lungime fix de 64KB. Adresa de nceput a unui segment se pstreaz n unul dintre regitrii segment (CS, DS, SS, ...). Deoarece un registru segment are doar 16 bit, n el se pstreaz doar partea mai semnificativ a adresei de segment, ultimii 4 bit considerndu-se n mod implicit 0. Adresa unei locaii de memorie se calculeaz ca o sum ntre adresa de segment i o adres de offset. Adresa de segment se obine prin multiplicarea coninutului registrului segment cu 16 (deplasarea la stnga cu 4 poziii binare). Adresa de ofset se calculeaz pe baza modului de adresare i eventual a adresei coninute in codul de instruciune. Prin adunare se obine o adres fizic pe 20 bit, suficient pentru adresarea unui spaiu de 1 MB (1M=220). n exemplul de mai jos, pentru claritate, valorile de adrese sunt exprimate n hexazecimal.
1 2 5 1 7 3 6 9 4 7 B 0 8 8 Adresa de segment Adresa de offset Adresa fizic

Acest mod de calcul a adresei fizice are cteva consecine: spaiul maxim de adresare este 1MB un segment trebuie s nceap la o adresa multiplu de 16 un segment are maxim 64KB segmentele se pot suprapune parial sau total aceeai locaie fizic se poate exprima prin mai multe variante de perechi de adrese (segment:offset) - exist puine posibiliti de protejare a zonelor de memorie - orice program poate adresa orice locaie de memorie, neputndu-se impune restricii (lucru nedorit ntr-un sistem multitasking) Modul protejat s-a introdus odat cu procesorul '386 i apoi s-a perfecionat la procesorul '486. Acest mod a fost necesar pentru a soluiona limitrile modului real, n special n ceea ce privete spaiul limitat de adresare i posibilitile reduse de protecie. n modul protejat exprimarea adresei se face la fel prin adres de segment i adresa de offset, ns cu anumite amendamente: - un registru segment pstreaz un selector de segment i nu adresa de nceput a segmentului; - selectorul este un indicator care arat locul unde se afl o structur de date care descrie un segment i care poarta numele de descriptor de segment

- un descriptor de segment conine: adresa segmentului (pe 32 de bii) lungimea segmentului (pe 20 de bii), indicatori pentru determinarea drepturilor de acces i indicatori care arat tipul i modul de utilizare a segmentului - adresa de offset se exprim pe 32 de bii Aceste modificri genereaz urmtoarele consecine: spaiul maxim de adresare al memoriei se extinde la 4GB (4G = 232) un segment are o lungime variabil, n interval larg de la 1 octet la 4GB se definesc trei nivele de protecie (0, cel mai prioritar) un segment este accesibil numai taskului alocat i eventual sistemului de operare anumite segmente pot fi blocate la scriere (ex: segmentele de cod) rezult un mecanism complex de alocare i de protecie a zonelor de memorie
Registru segment
Selector : Adresa de offset Memoria Descriptor de segment Adresa segmentului Lungimea Indicatori

Adresa fizic

Calculul adresei fizice n modul protejat

n sistemele de operare Windows i Linux, pe 32 bit, s-a ales modelul memoriei flat. Acest lucru nseamn c n cadrul programului, toi descriptorii de segment, cu excepia segmentului FS, descriu un segment a crui adres de nceput este 0, iar lungimea este 232-1. Segmentul FS este un segment special, care n sistemul de operare Windows conine structura TIB (Thread Information Block), i are alt adres de nceput i alt lungime. Fiecare program are acces la o memorie virtual de 4GB (din care doar prima jumtate este adresabil n mod utilizator), n care este izolat de celelalte programe. Acest lucru nu nseamn c fiecare program folosete 4 GB de memorie fizic. Sistemul menine o tabel cu corepondena dintre paginile de memorie virtual (specifice programului) i cadrele de memorie fizic (specifice ntregului sistem).

Astfel, fiecare program are propriul spaiu de adrese. Dac un program scrie o dat la adresa 123456H n memorie, iar un alt program, ce ruleaz n paralel cu primul scrie alt valoare, la aceeai adres, cele dou valori nu se vor suprascrie una pe alta. Dei ambele programe scriu la adresa virtual 123456H, n memoria fizic, cele dou adrese virtuale vor avea corespondente diferite.

2.2 Elementele de baz ale limbajului de asamblare


2.2.1 Construcii de baz O instruciune n limbaj de asamblare are urmtorul format: [<etichet>:] [<operaie>[<operanzi>]] [;<comentarii>] <etichet> este un nume format din litere, cifre sau caractere speciale, care ncepe neaprat cu o liter sau cu un caracter special. Etichetele sunt folosite pentru a ne referi la o anumit poziie, din cadrul programului. <operaie> este mnemonica unei instruciuni n asamblare. <operanzi> pot fi zero, unu sau mai muli, i reprezint entitile asupra crora se efectueaz operaia. Pot fi regitiri, locaii de memorie, date imediate sau constante.

<comentarii> sunt orice text, ce ncepe cu ;, i continu pn la sfritul rndului. Acestea sunt ignorate de ctre asamblor, i utile pentru lizibilitatea codului. Constantele numerice sunt specificate printr-un ir de cifre i litere, ce ncepe obligatoriu cu o cifr. Un numr zecimal se specific pur i simplu printr-un ir de cifre. Un numr binar se specific printr-un ir de cifre binare, terminate cu litera B. Analog se folosete litera Q pentru octal, respectiv H pentru hexazecimal. Dac un numr hexazecimal ncepe cu o liter (A..F), aceasta trebuie precedat de cifra 0. Exemple: 010010100B, 26157Q, 4921, 4B52H, 0AB3H. Caracterele sau irurile de caractere se scriu ntre apostroafe () sau ghilimele(). n mod intern, un ir de caractere este echivalent cu un ir de numere, pe 8 bit. Simbolurile reprezint poziii n memorie. Acestea pot fi etichete sau variabile. Etichetele pot fi definite n zona de cod, i sunt folosite pentru a indica o anumit linie de cod. Pentru programator, e mai uor s indice un salt la o anumit instruciune, dect s indice adresa, sau deplasamentul fa de adresa curent. Variabilele sunt definite n zona de date. Acestea trebuie s aib unul din tipurile simple: BYTE(1 octet), WORD(2 octei), DWORD(4 octei), QWORD(8 octei), TWORD(10 octei) sau un tip compus, STRUC sau RECORD. Pentru a defini o variabil, se scrie numele acesteia, urmat de un cuvnt cheie, care indic tipul variabilei: DB (de la Define Byte) pentru BYTE, DW pentru WORD, DD pentru DWORD, etc. Pentru a scrie un vector n locul unei variabile simple, valorile se pot scrie, separate de virgul: vect DB 1, 2, 3, 4, 5 Pentru a defini <n> elemente, cu valoarea <x>, se poate scrie <n> DUP(<x>), de exemplu: vect DB 5 DUP(0) Pentru a defini o constant, se folosete cuvntul cheie EQU, ntr-o expresie de genul: <nume_const> EQU <expresie> De exemplu, se poate scrie ZECE EQU 10 Valoarea constantei nu se va stoca n memoria programului, ci asamblorul va nlocui n codul surs numele acesteia, cu valoarea (similar cu #define din C, nu cu const).

2.2.2 Structura general a unui program MASM Un program MASM, are urmtoarea structur:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 .386 .model flat, stdcall ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;includem biblioteci, si declaram ce functii vrem sa importam includelib msvcrt.lib extern exit: proc ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;declaram simbolul start ca public - de acolo incepe executia public start ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;sectiunile programului, date, respectiv cod .data ;aici declaram date .code start: ;aici se scrie codul ;terminarea programului push 0 call exit end start

Pe prima linie a programului ntlnim directiva .386, care spune asamblorului s genereze un fiier binar, compatibil cu procesoarele din generaia 386. Linia a doua conine directiva .model, prin care se specific tipul memoriei, respectiv tipul limbajului. Modelul flat este cel folosit n Windows i implic folosirea ntregului spaiu de adrese, pentru toate selectoarele, cu excepia selectorului FS. stdcall reprezint convenia de apel a funciilor i a altor simboluri exportate de program. Linia 6 conine directiva includelib, prin care se include n programul nostru biblioteca msvcrt. Aceast bibliotec conine funii i proceduri standard, cum ar fi printf, exit. Pentru a folosi o astfel de funcie, aceasta trebuie declarat ca simbol extern, dup cum se observ n linia 7. Atunci cnd un program ruleaz, sistemul de operare trebuie s tie de unde s nceap execuia. Din acest motiv, trebuie s marcm acest lucru n mod explicit, n programul nostru, printr-o etichet (linia 19), apoi s exportm aceast etichet ca simbol public (linia 11).

Directiva .data de la linia 15 marcheaz nceputul seciunii de date. n aceast seciune se pot declara variabilele i constantele folosite de program. Analog, directiva .code de la linia 18 marcheaz nceputul seciunii de cod. Acolo se vor scrie toate instruciunile programului.

2.3 Instrumentele de lucru pentru compilare i depanare


2.3.1 Asamblorul i linker-ul Pentru ca un program scris n limbaj de asamblare s se transforme n cod binar, care va fi executat direct de ctre procesor, este nevoie de un program special numit asamblor. n cadrul acestui laborator, asamblorul folosit este MASM (Microsoft Macro Assembler). n directorul masm_minimal, se gsete fiierul ml.exe, cu ajutorul cruia se asambleaz fiierele surs. Pentru asamblare, se tasteaz urmtoarea comand, n Command Prompt: >ml.exe sursa.asm unde sursa.asm este numele fiierului ce conine codul surs. Rezultatul acestui apel nu genereaz un fiier executabil, ci un fiier obiect, ce conine codul binar, dar nu poate ru la. Pentru a se obine un fiier executabil, trebuie editate legturile programului. Pentru aceast operaie, exist fiierul link.exe din folderul masm_minimal. Asamblarea i link-editarea se pot face printr-o singur comand: >ml.exe sursa.asm /link /subsystem:console /entry:start msvcrt.lib Aceast comand asambleaz fiierul sursa.asm, genernd programul de consol sursa.exe, ce are codul de la eticheta start, ca punct de pornire, i include biblioteca msvcrt.lib. Pentru a nu fi necesar scrierea acestei comenzi de fiecare dat, n masm_minimal se gsete script-ul build_masm.bat, care primete ca parametru numele sursei, fr extensie, i ncearc s genereze programul executabil. Pentru a asambla i link-edita fiierul hellow.asm, i genera hellow.exe, se folosete comanda: >build_masm hellow Rezultatul comenzii, se poate observa n figura de mai jos:

n caz de eroare, n linia de comand se va afia eroarea, i linia din codul surs la care s -a produs eroarea respectiv. Se recomand folosirea unui editor special pentru a scrie codul surs (de exemplu, Notepad++), care numeroteaz liniile de cod.

2.3.2 Depanarea programelor Pentru a putea nelege mai bine execuia unui program n limbaj de asamblare, sau pentru depistarea erorilor, se folosesc programe de tip debugger. Acestea permit ncrcarea unui fiier executabil, execuia acestuia instruciune cu instruciune, vizualizarea coninutului memoriei i a regitrilor, la fiecare pas, i chiar modificarea unor instruciuni sau date, n timp ce programu l ruleaz. Debugger-ul folosit la acest laborator va fi Olly Debugger. Lansarea acestuia n execuie se face fcnd dublu-click pe executabilul acestuia, numit OLLYDBG.EXE. ncrcarea unui program pentru depanare, se va face folosind tasta F3. Eventualele argumente cu care trebuie rulat programul se pot specifica n fereastra de dialog care apare. Dac dup ncrcarea programului nu apare codul acestuia, se poate ajunge la el, folosind combinaia de taste Ctrl+F9.

Fereastra debugger-ului arat ca n figura de mai sus, i este mprit n 4 zone: Zona 1 conine regitrii procesorului, mpreun cu valorile acestora, la momentul curent al execuiei. Regitrii ai cror valori s-au modificat la instruciunea anterioar sunt marcai cu rou, iar restul cu gri. Flag-urile sunt afiate i separat. Tot n aceast zon sunt afiai i regitrii coprocesorului matematic.

Zona 2 numit i dump, poate afia diverse poriuni din memoria programului. La nceputul execuiei, aici se afieaz seciunea de date. Dump-ul este afiat prin 3 coloane. n prima avem adresa de nceput a liniei, n a doua, coninutul memoriei la adresa respectiv n format hexazecimal, iar n a 3-a, acelai coninut, n format text. Dac dorim s vedem coninutul memoriei de la o anumit adres, care apare n una din cele 4 zone ale debugger-ului, se face click dreapta pe acea adres, i din meniul aprut se alege opiunea Follow in Dump. Zona 3 conine stiva programului (zon de memorie cu o ntrebuinare special, ce va fi dezbtut ntr-o lucrare viitoare). Pe prima coloan sunt afiate adresele, iar pe a doua valorile, n hexazecimal (cte un DWORD). Adresa vrfului stivei este evideniat. Se poate observa c adresa vrfului stivei este valoarea din registrul ESP. Ca i pentru zona de dump, orice adres ce aparine de stiv poate fi urmrit n aceasta, fcnd click dreapta i alegnd Follow in Stack. Zona 4 este zona de afiare a codului. n prima coloan se gsesc adresele instruciunilor, n hexazecimal. Adresa instruciunii urmtoare este evideniat. n a doua coloan se gsete codul binar, aferent instruciunii de la adresa respectiv. Codurile binare ale instruciunilor au lungimi variabile. Pe a 3-a coloan se regsete codul programului, dezasamblat. Ar trebui s se observe aceleai instruciuni ca i n programul surs, eventual scrise ntr-o alt ordine.

Comenzi pentru depanare: Step Into F7 trece la instruciunea urmtoare a programului, intrnd n funcii, acolo unde se ntlnesc. Step Over F8 trece la instruciunea urmtoare, srind peste funcii (se execut ntreaga funcie, ca i cum ar fi o singur instruciune). Breakpoint F2 atunci cnd cursorul se afl pe o anumit linie (acea linie este evideniat prin culoarea gri deschis), se plaseaz o ntrerupere la acea linie. Atunci cnd programul, n timpul rulrii, ajunge la o instruciune pe care s-a pus un breakpoint, se va ntrerupe execuia. Run F9 pornete execuia normal a programului, de la poziia curent, pn la primul breakpoint ntlnit, sau pn la final. Execute till Return Ctrl+F9 la fel cu Run, dar execuia se oprete i la ntlnirea unei instruciuni RETN. Restart Ctrl+F2 repornete programul depanat.

Instruciunile sau datele unui program pot fi modificate n timpul depanrii. Se face click pe instruciunea sau datele dorite, pentru a poziiona cursorul acolo, apoi se apas tasta Space. n fereastra de dialog aprut, se pot face modificrile. Pentru a vizualiza ntreg coninutul memoriei, se apas combinaia de taste Alt+M. n tabelul aprut este descris fiecare seciune. Coloanele Address i Size indic adresa, respectiv

dimensiunea seciunii. n coloana owner, apare numele modulului ce conine acea seciune. Modulul principal are acelai nume ca i numele programului executabil. Coloana Section indic numele efectiv al seciunii, n timp ce coloana Contains indic ce se gsete n aceasta. Fcnd dublu-click pe o linie a tabelului, se poate vizualiza coninutul seciunii respective. Olly Debugger va ncerca s ghiceasc tipul de coninut, afind implicit datele n format hexazecimal i ASCII, respectiv dezasamblnd codul. n cazul n care utilizatorul dorete vizualizarea informaiei n alt format, poate face click dreapta n zona de afiare, i alegerea formatului dorit.

Pentru revenirea n mod CPU (fereastra principal, cu cele 4 zone), se apas combinaia de taste Alt+C.

2.4 Mersul lucrrii


1. Discuii legate de arhitectura Intel x86. 2. Prezentarea modului n care se execut o instruciune de ctre procesor. 3. Se va deschide fiierul s2model.asm cu Notepad++. Fiierul conine un model de program n limbaj de asamblare. 4. Se va deschide fiierul s2ex1.asm cu Notepad++. Probleme de urmrit: a. Modul n care sunt declarate datele, tipuri de date b. Modul n care sunt declarate constantele c. Structura programului d. Se vor identifica directivele importante, etichetele, formatul instruciunilor 5. Se va compila s2ex1.asm cu MASM i se va executa cu Olly Debugger. a. Fiecare student i va crea propriul director de lucru avnd ca denumire propriul nume. Se recomand ca numele folderelor i fiierelor utilizate s nu conin spaii. b. Se va deschide o consol. Din Total Commander, se poate deschide o consol, n directorul curent, tastnd cmd i apsnd tasta Enter. c. Se va asambla s2ex1.asm, scriind n linie de comand, linia urmtoare: >build_masm s2ex1 d. Dac programul s-a asamblat cu succes, executabilul acestuia se va deschide n Olly Debugger. e. Se vor identifica zonele n care se gsete codul programului, memoria, regitrii, stiva i flagurile. f. Se va executa programul instruciune cu instruciune. Pentru execuia unei instruciuni se va apsa tasta F8 o dat. g. Se va urmari modul in care sunt pastrate datele in memorie. Fiecare patrat de mai jos reprezint un octet din zona de date a programului s2ex1.exe. S se completeze fiecare octet cu coninutul corespunztor i s se delimiteze variabilele declarate.