Sunteți pe pagina 1din 380

Programarea procesoarelor IA-32 n limbaj de asamblare

!tefan Gabriel !origa

Iulian B"descu

UNIVERSITATEA POLITEHNICA BUCURE!TI

PROGRAMAREA PROCESOARELOR IA-32 N LIMBAJ DE ASAMBLARE

PREFA#$
Limbajul de asamblare reprezint! o metod! de codificare simbolic!, relativ u"or de citit "i de interpretat de c!tre om, a instruc#iunilor n format binar executate de procesor. Spre deosebire de alte limbaje de programare, limbajul de asamblare nu reprezint! un limbaj de sine st!t!tor, ci, mai degrab!, o categorie de limbaje. Fiecare familie de procesoare are propriul limbaj n asamblare. Din aceast! rela#ie de cauzalitate rezult! c! programatorul, pe lng! no#iunile specifice limbajului, trebuie s! de#in! "i cuno"tin#e minime legate de structura intern! a procesorului. Devine evident c! programarea n limbaj de asamblare este mult mai dificil! dect programarea ntr-un limbaj de nivel nalt. De fapt, limbajul de asamblare trebuie utilizat numai atunci cnd este absolut necesar. Deoarece asamblarea este o etap! intermediar! a procesului de compilare, instrumentele folosite la translatarea codului scris n limbaj de nivel nalt n limbaj ma"in! sunt capabile s! gestioneze "i programe hibride, n care codul limbajului de nivel nalt con#ine secven#e scrise n limbaj de asamblare. Altfel spus, compilatorul accept! introducerea de linii scrise n limbaj de asamblare direct n textul surs! al limbajului de nivel nalt, iar editorul de leg!turi poate combina module obiect generate din surse scrise n limbaj de nivel nalt cu module obiect ob#inute din surse scrise n limbaj de asamblare. Aceste construc#ii hibride apar din cteva considerente, dintre care amintim: optimiz!ri atunci cnd sunt necesare secven#e critice sub aspectul timpului de execu#ie "i consumului de memorie; acces la instruc#iuni specifice procesorului; n prezent, chiar "i n aceste situa#ii, eficien#a compilatoarelor a crescut pn! la nivelul n care acestea concureaz! cu orice programator n asamblare, cu excep#ia unuia foarte bun, iar evolu#iile tehnologice fac ca avantajul codului ma"in! optimizat prin instruc#iuni n asamblare s! fie minim. Pe de alt! parte, odat! cu r!spndirea unor platforme relativ s!race n resurse de procesare "i memorie, cum ar fi telefoanele mobile inteligente sau microcontrolere, se preconizeaz! o cre"tere a cererii de speciali"ti capabili s! foloseasc! ct mai eficient resursele existente. Totodat!, sunt "i situa#ii n care programarea n limbaj de asamblare nu poate fi evitat!. De exemplu, anumite componente ale sistemului de operare au restric#ii stricte n ce prive"te performan#a "i consumul de resurse. Acestea nu se pot realiza dect prin utilizarea ct mai eficient! a instruc#iunilor "i caracteristicilor procesorului. n general, programatorii de sistem au nevoie de cuno"tin#e avansate de programare n limbaj de asamblare. n cazul programatorilor de aplica#ii, principalele motive pentru care se recomand! experien#a program!rii n limbaj de asamblare const! n familiarizarea cu modul de organizare a programelor n memorie, cu principiile de func#ionare a diverselor componente hardware sau cu rolul sistemului de operare. Toate ajut! programatorul de aplica#ii s! scrie programe mai eficiente. De asemenea, depanarea unui program de nivel nalt poate dep!"i nivelul textului surs!, ajungndu-se la

depanarea codului obiect, proces care necesit! cunoa"terea limbajului de asamblare. Evident, dac! se dore"te ca o aplica#ie s! profite ct mai mult de beneficiile limbajului de asamblare (cod compact "i rapid, consum de resurse minim), aceasta poate fi scris! complet n limbaj de asamblare. Un astfel de caz este aplica#ia antivirus NOD32. Cartea de fa#! abordeaz! limbajul de asamblare corespunz!tor familiei de procesoare Intel de 32 de bi#i, de la 80386 pn! la Pentium 4. Indiferent de particularit!#ile limbajului de asamblare specific arhitecturilor Intel, no#iunile de baz! "i principiile generale se aplic! "i altor categorii de procesoare "i chiar microcontrolerelor. Gradul de complexitate al informa#iilor cre"te gradual, pe parcursul desf!"ur!rii capitolelor. Publicul #int! este reprezentat de studen#ii de anul II de la specializarea Telecomenzi "i electronic! n transporturi din cadrul Facult!#ii Transporturi, dar "i de studen#i de la alte facult!#i, de exemplu, Facultatea de Automatic! "i Calculatoare sau Electronic! "i Telecomunica#ii, care au n program! cursuri de Arhitectura microprocesoarelor sau Calculatoare "i sisteme de operare. Lucrarea este dedicat! celor care iau contact pentru prima dat! cu limbajul de asamblare "i, chiar dac! publicul #int! a urmat cel pu#in un curs introductiv de programare, nu se fac presupuneri cu privire la cuno"tin#ele acumulate anterior. Conceptele sunt prezentate simplu "i concis, natura intrinsec! a domeniului necesit! oricum un grad ridicat de concentrare "i exerci#iu. Programele sunt la fel de simple, orientate c!tre ilustrarea conceptelor. n final, pentru a for#a cititorul s! editeze programele manual, am ales ca volumul s! nu fie acompaniat de un CD. Se "tie c! tenta#ia de a copia codul cu ajutorul mouse-ului e mare. Cititorul trebuie s! con"tientizeze faptul c! obiectivul s!u este s! "i nsu"easc! informa#iile "i conceptele prezente n acele programe, nu s! le ruleze pur "i simplu. Autorii recomand! parcurgerea secven#ial! a c!r#ii, ntotdeauna cu calculatorul n fa#!. Aceast! carte nu se cite"te, se execut!. Conceptele noi sunt prezentate pe baza celor dinainte, iar capitolele sunt scrise astfel nct s! conduc! ct mai repede la exemple practice. Cu o atitudine adecvat!, la finalul c!r#ii, n cel mai pesimist scenariu, cititorul va cunoa"te conceptele generale de dezvoltare a programelor n asamblare, func#iile sistemului de operare "i organizarea calculatorului din perspectiva unui programator. Consider!m c! platforma hardware "i software cea mai indicat! pentru nsu"irea conceptelor teoretice este cea real!. De aceea, toate uneltele de programare discutate n aceast! carte sunt disponibile pe orice distribu#ie Linux. Linux ofer! un excelent mediu de studiu "i dezvoltare. n plus, contactul cu Linux reprezint! o oportunitate n sine. Executabilele sunt generate "i rulate chiar de procesorul calculatorului (cu excep#ia cazului n care alege#i s! folosi#i o ma"in! virtual!). Cerin#a obligatorie este s! fac! parte din familia Intel de 32 sau 64 de bi#i. Deoarece procesoarele moderne de 64 de bi#i sunt compatibile napoi, toate informa#iile prezentate pentru arhitecturile de 32 de bi#i r!mn valabile.

Mediul de dezvoltare n procesul de dezvoltare a programelor, majoritatea programatorilor folosesc un mediu integrat de dezvoltare (IDE - Integrated Development Environment). Acesta pune la dispozi#ie toate uneltele necesare gener!rii executabilului din codul surs!, dar, totodat!, ascunde detaliile acestui proces. n aceast! carte folosim componentele (editor de text, compilator, asamblor, editor de leg!turi, depanator) individual, astfel nct rolul fiec!ruia s! poat! fi observat direct. Sistemul de operare este Ubuntu, orice variant! ntre 10.04 "i 13.04. Organizarea capitolelor Primul capitol prezint! sistemele de numera#ie "i modul de reprezentare a caracterelor alfanumerice n sistemele de calcul. Sunt oferite numai informa#ii strict necesare. Scopul este s! ne nsu$im rapid un set de cuno"tin#e minim pe baza c!ruia s! putem asimila, prin exemple practice, conceptele ulterioare. Al doilea capitol prezint! arhitectura sistemelor de calcul, cu cele dou! fa%ete ale sale, hardware $i software. Subiectul este abordat din perspectiva programatorului. Ne concentr!m asupra structurii interne a procesoarelor Intel de 32 de bi#i. Al treilea capitol prezint! limbajul de asamblare n contextul interac%iunii utilizator - calculator $i al pozi%ei sale n ierarhia limbajelor de programare. Capitolul poate fi privit ca o ncercare de definire a limbajului de asamblare prin gen $i diferen%! specific!, unde genul este reprezentat de clasa limbajelor de programare, iar diferen%a specific! de propriet!%ile caracteristice. Din acest capitol se desprinde faptul c! limbajul de asamblare este o etap! parcurs! de compilatoare n procesul de translatare a codului surs! n cod ma$in!. A"adar, fie c! dorim s!-l folosim sau nu, el este oricum utilizat de compilatoare n procesul de generare a codului obiect. Al patrulea capitol prezint! procesul de dezvoltare a programelor n limbaj de asamblare "i uneltele utilizate n etapele acestuia. Sunt prezentate numai informa#ii esen#iale legate de limbajul de asamblare. Toate capitolele urm!toare vor face referire la acestea. Al cincilea capitol este dedicat conceptului central al program!rii n orice limbaj, cu att mai mult al program!rii n limbaj de asamblare: organizarea "i adresarea memoriei principale. Al "aselea capitol prezint! formatul instruc#iunilor ma"in!. Pe lng! aceste informa#ii, rolul acestui capitol este s! familiarizeze cititorul cu modul de prezentare a informa#iilor n documenta#ia oficial! Intel1. Al "aptelea "i al optulea capitol acoper! toate instruc#iunile dedicate
1

The Intel 64 and IA-32 Architectures Software Developers Manual, Volumes 2A & 2B: Instruction Set Reference

opera#iilor cu numere ntregi, respectiv cu numere reale. Ultimele trei capitole acoper! no#iuni mai avansate, precum definirea func#iilor "i interac#iunea limbajului de asamblare cu sistemul de operare "i limbajul de nivel nalt C.

Cuprins 1.! REPREZENTAREA INFORMA&IEI N SISTEMELE DE CALCUL14! 1.1.! Sisteme de numera#ie ......................................................................14! 1.1.1.! Sistemul zecimal......................................................................15! 1.1.2.! Sistemul binar ..........................................................................15! 1.1.3.! Sistemul hexazecimal ..............................................................16! 1.2.! Opera%ii de conversie ......................................................................16! 1.2.1.! Conversia numerelor din zecimal n binar ..............................16! 1.2.2.! Conversia numerelor din zecimal n hexazecimal ...................17! 1.2.3.! Conversia numerelor din hexazecimal n binar .......................17! 1.2.4.! Conversia numerelor din binar n hexazecimal .......................18! 1.2.5.! Conversia numerelor reale.......................................................19! 1.3.! Reprezentarea caracterelor alfanumerice .......................................20! 1.4.! Exerci%ii ..........................................................................................22! 2.! ARHITECTURA CALCULATOARELOR..........................................24! 2.1.! Structura unui sistem de calcul .......................................................24! 2.1.1.! Arhitectura von Neumann .......................................................24! 2.1.2.! Modelul bazat pe magistral!....................................................26! 2.1.1.! Magistrala de sistem ................................................................27! 2.1.2.! Unitatea de intrare/ie"ire .........................................................28! 2.1.3.! Memoria ..................................................................................29! 2.2.! Arhitectura IA-32 ...........................................................................30! 2.2.1.! Arhitectur! "i microarhitectur! ................................................31! 2.2.2.! Structura de principiu a procesorului ......................................33! 2.2.3.! Func#ionarea procesorului .......................................................37! 2.2.4.! Registrele procesorului ............................................................38! 2.2.5.! ntreruperile .............................................................................42! 2.3.! Exerci#ii ..........................................................................................43! 3.! LIMBAJUL DE ASAMBLARE ...........................................................44! 3.1.! Tipuri de limbaje de programare ....................................................46! 3.1.1.! Limbajul ma"in! ......................................................................46! 3.1.2.! Limbajul de asamblare ............................................................48! 3.1.3.! Limbaje de nivel nalt ..............................................................48! 3.2.! Procesul de compilare.....................................................................51! 3.2.1.! Preprocesarea...........................................................................53! 3.2.2.! Compilarea ..............................................................................53!

3.2.3.! Asamblarea ..............................................................................55! 3.2.4.! Editarea leg!turilor ..................................................................57! 3.2.5.! Formatul fi"ierelor executabile ................................................57! 3.3.! Avantajele limbajului de asamblare ...............................................58! 3.4.! Exerci#ii ..........................................................................................59! 4.! DEZVOLTAREA PROGRAMELOR N LIMBAJ DE ASAMBLARE 60! 4.1.! Sintaxa limbajului de asamblare .....................................................60! 4.2.! Structura programului .....................................................................61! 4.3.! Structura procesului ........................................................................64! 4.3.1.! Memoria virtual! n Linux ......................................................65! 4.4.! Tipuri de date ..................................................................................67! 4.4.1.! Date ini#ializate........................................................................67! 4.4.2.! Date neini#ializate ....................................................................74! 4.5.! Procesul de dezvoltare al programelor ...........................................75! 4.5.1.! Editarea textului ......................................................................75! 4.5.2.! Asamblarea ..............................................................................81! 4.5.3.! Editarea leg!turilor ..................................................................85! 4.5.4.! Automatizarea sarcinilor cu GNU Make .................................86! 4.5.5.! Execu#ia programului ..............................................................89! 4.5.6.! Depanarea fi"ierului executabil ...............................................90! 4.6.! ntreb!ri "i exerci#ii.......................................................................100! 5.! MEMORIA ..........................................................................................101! 5.1.! Declararea datelor n bloc .............................................................101! 5.2.! Adresarea memoriei n modul protejat .........................................103! 5.2.1.! Adresare imediat! "i adresare la registre ...............................104! 5.3.! Optimizarea accesului la memorie ...............................................117! 6.! ARHITECTURA SETULUI DE INSTRUC&IUNI ............................122! 6.1.! Simboluri cheie .........................................................................122! 6.2.! Codificarea instruc#iunilor ............................................................124! 6.2.1.! Spa#iul codurilor opera#ionale ...............................................126! 6.2.2.! Octetul ModR/M ...................................................................128! 6.2.3.! Spa#iul codurilor 386 (0F + ...) ..............................................129! 6.2.4.! Prefix de dimensiune operand ...............................................130! 6.3.! Codificarea adreselor de memorie ................................................131! 6.3.1.! Octetul SIB ............................................................................132!

6.4.! Formatul instruc#iunilor ................................................................133! 6.4.1.! Prefixele de instruc#iune ........................................................133! 6.4.2.! Modurile de adresare prin octetul ModR/M ..........................134! 6.4.3.! Modurile de adresare prin octetul SIB ..................................137! 6.5.! Studiu de caz.................................................................................139! 7.! OPERA&II CU NUMERE NTREGI .................................................145! 7.1.! Reprezentarea numerelor cu semn................................................145! 7.1.1.! Reprezentarea cu bit de semn "i magnitudine .......................146! 7.1.2.! Reprezentarea n complement fa#! de unu.............................146! 7.1.3.! Reprezentarea n complement fa#! de doi .............................147! 7.2.! Extinderea ntregilor .....................................................................151! 7.3.! Indicatori de stare .........................................................................153! 7.3.1.! Indicatorul de zero .................................................................153! 7.3.2.! Indicatorul de transport .........................................................154! 7.3.3.! Indicatorul de dep!"ire ..........................................................155! 7.3.4.! Indicatorul de semn ...............................................................156! 7.3.5.! Indicatorul de transport la jum!tate .......................................156! 7.3.6.! Indicatorul de paritate ............................................................157! 7.4.! Instruc#iuni de transfer condi#ionat ...............................................158! 7.5.! Opera#ii aritmetice ........................................................................160! 7.5.1.! Instruc#iuni de adunare ..........................................................160! 7.5.2.! Instruc%iuni de sc!dere ...........................................................165! 7.5.3.! Instruc%iuni de comparare ......................................................170! 7.5.4.! Incrementare "i decrementare ................................................170! 7.5.5.! Instruc#iuni de nmul#ire ........................................................171! 7.5.6.! Instruc#iuni de mp!r#ire ........................................................172! 7.6.! Instruc#iuni de interschimbare a datelor .......................................173! 7.7.! Instruc%iuni de prelucrare la nivel de bit .......................................178! 7.7.1.! Instruc#iuni logice ..................................................................178! 7.7.2.! Instruc#iuni de deplasare ........................................................181! 7.7.3.! Instruc#iuni de rota%ie.............................................................185! 7.7.4.! Instruc#iuni de testare "i modificare a unui bit ......................185! 7.7.5.! Instruc#iuni de scanare pe bit .................................................186! 7.7.6.! Instruc#iuni de setare condi#ionat! .........................................186! 7.8.! Instruc%iuni de transfer al controlului ...........................................187! 7.8.1.! Instruc#iuni de salt necondi#ionat ..........................................188! 7.8.2.! Instruc#iuni de salt condi#ionat ..............................................189! 7.8.3.! Instruc#iuni de ciclare ............................................................191! 7.9.! Procesarea "irurilor .......................................................................193!

7.9.1.! Instruc#iuni de transfer...........................................................193! 7.9.2.! Instruc#iuni de transfer la/de la acumulator ...........................197! 7.9.3.! Instruc#iuni de comparare ......................................................200! 7.9.4.! Instruc#iuni de parcurgere ......................................................201! 7.10.! Opera#ii cu stiva ..........................................................................202! 7.10.1.! Introducerea "i extragerea datelor .......................................203! 7.10.2.! Introducerea "i extragerea registrelor ..................................205! 7.10.3.! Exemple de lucru cu stiva ...................................................206! 7.11.! Exerci#ii ......................................................................................208! 8.! OPERA&II CU NUMERE N VIRGUL' MOBIL' .........................209! 8.1.! Reprezentarea numerelor reale .....................................................209! 8.1.1.! Formatul n virgul! mobil! ....................................................209! 8.1.2.! Standardul IEEE 754 .............................................................214! 8.1.3.! Valori n virgul! mobil! specifice IA-32 ..............................218! 8.2.! Arhitectura unit!#ii n virgul! mobil! ...........................................219! 8.2.1.! Registre de date .....................................................................219! 8.2.2.! Registre de control "i stare ....................................................220! 8.3.! Instruc#iuni n virgul! mobil! .......................................................224! 8.3.1.! Transferul datelor n virgul! mobil! ......................................224! 8.3.2.! Opera#ii aritmetice n virgul! mobil! ....................................230! 8.3.3.! Instruc#iuni transcedentale .....................................................235! 8.3.4.! Instruc#iuni de comparare ......................................................236! 8.3.5.! Instruc#iuni FPU de transfer condi#ionat ...............................240! 8.4.! Exerci#ii ........................................................................................244! 9.! FUNC&II .............................................................................................247! 9.1.! Modularizarea programelor ..........................................................247! 9.2.! Apelarea func#iilor ........................................................................248! 9.3.! Definirea func#iilor .......................................................................249! 9.4.! Transferul controlului ...................................................................250! 9.5.! Metode de transfer al parametrilor ...............................................251! 9.5.1.! Prin registre ...........................................................................251! 9.5.2.! Prin variabile globale.............................................................253! 9.5.3.! Prin stiv! ................................................................................254! 9.5.4.! Structura func#iei ...................................................................262! 9.6.! Mecanisme de transfer al parametrilor .........................................266! 9.6.1.! Transfer prin valoare .............................................................266! 9.6.2.! Transfer prin referin#! ...........................................................269!

9.7.! Conservarea st!rii registrelor ........................................................271! 9.8.! Scrierea func#iilor n fi"iere separate ............................................271! 9.9.! Exerci#ii ........................................................................................275! 10.! INTERFA&A CU SISTEMUL DE OPERARE ................................278! 10.1.! ntreruperi software ....................................................................278! 10.2.! Formatul apelurilor de sistem .....................................................281! 10.2.1.! Alocarea static! a bufferelor................................................288! 10.2.2.! Macroinstruc#iuni ................................................................289! 10.2.3.! Func#ii de lucru cu transferuri de intrare/ie"ire ...................296! 10.2.4.! Opera#ii cu fi"iere ................................................................303! 10.2.5.! Argumente n linia de comand!...........................................307! 10.3.! Opera#ii aritmetice n reprezent!ri ASCII "i BCD .....................311! 10.3.1.! Formatul BCD .....................................................................312! 10.3.2.! Erori "i corec#ii n ASCII.....................................................312! 10.3.3.! Erori "i corec#ii n BCD compactat .....................................320! 10.3.4.! Conversia ASCII binar ........................................................322! 10.3.5.! Conversia caracterelor ASCII n binar ................................324! 10.3.6.! Conversia numerelor din binar n ASCII ............................331! 10.4.! Biblioteci de func#ii ....................................................................335! 10.4.1.! Crearea bibliotecilor statice .................................................335! 10.4.2.! Crearea bibliotecilor partajate .............................................337! 10.4.3.! Procesul de generare a bibliotecilor partajate......................344! 10.4.4.! Instalarea "i utilizarea bibliotecilor partajate.......................346! 10.5.! Apelul func#iilor de sistem prin biblioteca standard C ...............348! 10.5.1.! Editarea leg!turilor cu func#iile C .......................................352! 11.! INTERFA&A CU LIMBAJELE DE NIVEL NALT .......................355! 11.1.! Apelarea modulelor n asamblare din C ....................................356! 11.1.1.! Structura func#iei n asamblare ............................................357! 11.1.2.! Cadrul de stiv! .....................................................................359! 11.1.3.! Compilarea modulelor .........................................................361! 11.2.! Linii de asamblare n codul surs! C............................................364! 11.2.1.! Sintaxa AT&T .....................................................................364! 11.2.2.! Formatul de baz! .................................................................368! 11.2.3.! Formatul extins ....................................................................373! Bibliografie .................................................................................................379!

1. REPREZENTAREA INFORMA!IEI N SISTEMELE DE CALCUL

Oamenii comunic! prin intermediul unui num!r apreciabil de simboluri: cifre, litere, semne de punctua"ie, operatori aritmetici, alte semne speciale. Calculatorul nu este capabil s! utilizeze dect dou! simboluri (0 #i 1). Pentru a reu#i s! comunice cu un calculator, omul trebuie s! converteasc! simbolurile #i comenzile sale ntr-o form! pe care calculatorul s! o poat! n"elege. Capitolul ncepe cu studiul diferitelor sisteme de numera"ie utilizate n interac"iunea cu calculatorul. Cnd se lucreaz! cu mai multe sisteme de numera"ie, adeseori este nevoie s! convertim un num!r dintr-o reprezentare n alta. Prezent!m detalii cu privire la aceste conversii. Apoi ne concentr!m asupra reprezent!rii caracterelor alfanumerice. n general, prin caractere alfanumerice se n"eleg toate caracterele care pot fi introduse de la tastatura unui calculator. ncheiem cu un set de exerci"ii destinat s! mijloceasc! re"inerea conceptelor #i procedeelor utilizate de-a lungul capitolului.

1.1. Sisteme de numera"ie


n mare, sistemul de calcul poate fi considerat o sum! de circuite electronice. ntr-un circuit electronic, prezen#a unui anumit voltaj poate indica 1, n timp ce lipsa acestuia, n acela"i punct, poate indica 0. Ra#ionamentul poate fi extins la prezen#a sau lipsa unui curent electric, a unei capacit!#i, etc.. Oricare ar fi suportul electronic, putem spune c! sistemele de calcul stocheaz! informa#ia sub forma unor "iruri de 0 "i 1. De exemplu: 0101001101101001011011010111000001101100011101010010000 0011000110110000100100000010000100111010101101110011000 01001000000111101001101001011101010110000100101110 Sistemul de numera#ie care utilizeaz! numai aceste dou! simboluri (digi#i, cifre) poart! numele de sistem binar. Num!rul de simboluri constituie baza sistemului de numera%ie. Calculatoarele stocheaz! toat! informa#ia n baza 2 limbajul nativ al ma"inilor de calcul. Pe de alt! parte, pentru noi, fiin#e dotate cu

zece degete "i obi"nuite cu sistemul zecimal, operarea n reprezentare binar! este incomod!.

1.1.1. Sistemul zecimal


Numerele n baza 10 sunt reprezentate folosind zece simboluri: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. Fiecare digit al num!rului zecimal are asociat! o putere a lui 10, n func#ie de pozi#ia sa n "irul de cifre al reprezent!rii (astfel de sisteme de numera#ie se mai numesc "i pozi$ionale). Pozi#ia cifrei n num!r este evaluat! de la dreapta la stnga, ncepnd cu zero. !"#!" ! ! ! !"! ! ! ! !"! ! ! ! !!!

1.1.2. Sistemul binar


Numerele n baza 2 sunt compuse din doi digi#i: 0 "i 1. Fiecare digit al unui num!r, n func#ie de pozi#ia sa, are asociat! o putere a lui 2. !!"!"! ! ! ! !! ! ! ! !! ! ! ! !! ! ! ! !! ! ! ! !! ! !" ! ! ! ! ! !"!! Exemplul ilustreaz! "i conversia unui num!r din binar n zecimal. Un singur digit binar se nume"te bit (binary digit) "i se prescurteaz! cu litera b. Pentru a lucra mai u"or cu numerele binare, putem grupa mai mul#i bi#i mpreun!: un "ir de 4 bi#i formeaz! un nibble, un "ir de 8 bi#i un byte sau octet, un "ir de 16 bi#i formeaz! un word sau un cuvnt, 32 de bi#i un double word sau un dublu cuvnt, 64 de bi#i un quad word (cuvnd cvadruplu), 80 de bi#i un ten byte. (irul binar de la nceputul capitolului are un num!r de 20 de octe#i. Dac! l mp!r#im n octe#i "i convertim fiecare octet n zecimal ob#inem "irul: 83 66 105 117 109 110 112 97 108 32 117 122 32 105 99 117 9 97 32 46

Acela"i "ir de bi#i, structurat n grupuri de cuvinte (16 bi#i) reprezentate zecimal, devine:

21329 17013

28016 28257

27765 8314

8291 26997

24864 24878

n grupuri de dublu cuvinte: 1399418224 1851859066 1819615331 1769300270 1629504117

Cu ct "irurile de bi#i devin mai lungi, cu att ne este mai greu s! le convertim n zecimal. De aceea, folosim ca intermediar sistemul hexazecimal.

1.1.3. Sistemul hexazecimal


n sistemul de numera%ie hexazecimal se utilizeaz! 16 simboluri: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F. Semnifica%ia zecimal! a simbolurilor A, B, C, D, E, F este, n ordine, 10, 11, 12, 13, 14, 15. Similar celorlalte sisteme de numera#ie, fiecare digit al num!rului hexazecimal are asociat! o putere a lui 16, n func#ie de pozi#ie: !!"!" ! ! ! !"! ! ! ! !"! ! ! ! !"! !!!!!!!!!!!!!! !"# ! !" ! !" ! !" ! ! !!!!!!!!!! !"# ! !"# ! !" ! !"#!" Exemplul ilustreaz! "i conversia unui num!r din hexazecimal n zecimal. Este acela"i algoritm de conversie folosit anterior la trecerea din binar n zecimal. S-a schimbat numai baza.

1.2. Opera#ii de conversie


Am v!zut cum putem transforma un num!r din baza 2 n baza 10 sau din baza 16 n baza 10. n continuare vom demonstra alte conversii utile.

1.2.1. Conversia numerelor din zecimal n binar


Pentru a converti un num!r zecimal n binar, nu trebuie dect s!-l mp!r#im succesiv la 2 pn! ob%inem ctul 0, iar grupul resturilor ob#inute, scrise de la stnga la dreapta, ncepnd cu ultimul, formeaz! reprezentarea acestuia n baza 2. Exemplu:

135 67 33 16 8 4 2 1

: : : : : : : :

2 2 2 2 2 2 2 2

= = = = = = = =

67 33 16 8 4 2 1 0

rest rest rest rest rest rest rest rest

1 1 1 0 0 0 0 1

=> => => => => => => =>

!! = !! = !! = !! = !! = !! = !! = !! =

1 1 1 0 0 0 0 1

Grupnd resturile n ordinea invers! ob#inerii lor, rezult!: !"#!" = !! !! !! !! !! !! !! !! = !""""!!!! . Verific!m: !""""!!!! ! ! ! !! ! ! ! !! ! ! ! !! ! ! ! !"# ! ! ! ! ! ! ! !"#!"

1.2.2. Conversia numerelor din zecimal n hexazecimal


Transform!m num!rul zecimal 1345 n hexazecimal. Algoritmul de trecere din zecimal n hexazecimal este identic cu cel folosit la conversia din zecimal n binar, dar mp!r#im la noua baz!, 16. 1345 : 16 = 84 rest 1 => !! = 1 84 : 16 = 5 rest 4 => !! = 4 5 : 16 = 0 rest 5 => !! = 5 n concluzie, !"#$!" = !! !! !! = !"#!" Verific!m: !"#!" ! ! ! !"! ! ! ! !" ! ! ! ! ! !"# ! !" ! ! ! !"#$ ! !" ! !"#$!"

1.2.3. Conversia numerelor din hexazecimal n binar


Reprezentarea hexazecimal! este folosit! de obicei ca nota#ie prescurtat! pentru anumite grupuri de bi#i. Tabelul 1.1 ne ajut! s! n#elegem mecanismul prin care se converte"te un num!r hexazecimal n binar.

Tabelul 1.1 Reprezentarea numerelor n diferite sisteme de numera$ie

Zecimal 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

Binar 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111

Hexazecimal 0 1 2 3 4 5 6 7 8 9 A B C D E F

Deoarece sistemul hexazecimal are 16 digi%i, fiecare cifr! hexazecimal! poate specifica un grup unic de patru bi#i. Din calculele precedente a reie$it c! !"#!" este 87 n hexazecimal $i 10000111 n binar. A"adar, putem deduce c! reprezentarea binar! a num!rului !"!" este 10000111. Din tabel observ!m c! reprezentarea binar! a lui !!" este 1000, iar reprezentarea binar! a lui !!" este 0111. Cu alte cuvinte, 10000111 reprezint! al!turarea echivalentului binar al cifrelor hexazecimale 8 $i 7. n concluzie, pentru a converti orice num!r hexazecimal n binar, nu trebuie dect s! identific!m reprezentarea binar! a numerelor hexazecimale. De exemplu, !!!!!" : !!" ! !!!"! !!" ! !"!"! !!" ! !!""! !!" ! !"!!! rezult! !!!!!" ! !!!""!"!!!""!"!!!

1.2.4. Conversia numerelor din binar n hexazecimal


Pentru a converti un num!r din binar n hexazecimal trebuie numai s! invers!m procesul. Grup!m bi#ii num!rului binar cte patru, de la dreapta la stnga, dac! este nevoie complet!m cu 0 bi#ii ultimului grup, "i identific!m echivalentul n hexazecimal pentru fiecare nibble. De exemplu, num!rul binar 10010001011010 poate fi grupat de la dreapta

la stnga astfel: 10 0100 0101 1010. Complet!m la stnga cu doi de zero, 0010 0100 0101 1010, "i identific!m pentru fiecare nibble echivalentul n hexazecimal. Rezultatul este !"#!!" . Aplic!m aceast! regul! pe "irul de bi#i dat la nceputul capitolului. mp!r#it n octe#i, ob#inem: 53 42 69 75 6d 6e 70 61 6c 20 75 7a 20 69 63 75 61 61 20 2e

mp!r#it n cuvinte (unirea doi cte doi a octe#ilor de mai sus): 5369 612e 6d70 6c75 2063 6120 4275 6e61 207a 6975

mp!r#it n dublu cuvinte (unirea dou! cte dou! a cuvintelor de mai sus): 53696d70 6c752063 61204275 6e61207a 6975612e

Din ultimele conversii deducem avantajul conversiei din binar n hexazecimal fa#! de conversia din binar n zecimal. Reprezentarea n hexazecimal este mult mai u"or de ob#inut. n plus, reprezentarea hexazecimal! a grupurilor de numere binare este transparent!: putem forma cuvinte prin al!turarea octe#ilor, dublu cuvinte prin al!turarea cuvintelor, ".a.m.d.. Aceste avantaje pozi#ioneaz! sistemul hexazecimal ca excelent intermediar ntre sistemul binar, utilizat de calculator, "i sistemul zecimal, nativ utilizatorului uman. De aici reiese un concept foarte important sistemul hexazecimal este modalitatea cea mai convenabil! prin care omul poate reprezenta "iruri de bi#i. Un num!r nu este intrinsec binar, zecimal sau hexazecimal. O valoare poate fi exprimat! la fel de precis n toate cele trei sisteme de numera#ie. Din acest punct de vedere, ea poate fi exprimat! la fel de precis n orice sistem de numera#ie.

1.2.5. Conversia numerelor reale


Conversia unui num!r cu parte ntreag! "i parte frac%ionar! se face prin conversia separat! a celor dou! p!r#i. Conversia num!rului subunitar (partea frac#ionar! a unui num!r) din baza 10 ntr-o baz! oarecare se face prin nmul#irea succesiv! a p!r#ilor frac#ionare cu baza respectiv!, pn! cnd se ajunge la zero, la

perioad!, sau se dep!"e"te capacitatea de reprezentare (se ob#in cifre suficiente de"i algoritmul nu s-a finalizat). Cifrele care dep!"esc partea frac%ionar! la fiecare nmul#ire formeaz! num!rul n baza c!tre care se face conversia. Exemplul care urmeaz! converte"te num!rul 0.57 n binar "i hexazecimal. Cum partea ntreag! este deja 0, convertim numai partea frac#ionar!. 0,57 0,14 0,28 0,56 0,12 0,24 0,48 0,96 0,92 0,84 0,68 0,36 * * * * * * * * * * * * 2 2 2 2 2 2 2 2 2 2 2 2 = = = = = = = = = = = = 1.14 0.28 0.56 1.12 0.24 0.48 0.96 1.92 1.84 1.68 1.36 0.72 => => => => => => => => => => => => !! = 1 !! = 0 !! = 0 !! = 1 !! = 0 !! = 0 !! = 0 !! = 1 !! = 1 !! = 1 !!" = 1 !!! = 0

A"adar, !!!"!" = !! !! !! !! !! !! !! !! !! !! !! !!" !!! = !!!""!"""!!!!"! = !!!"!!"

1.3. Reprezentarea caracterelor alfanumerice


Deoarece calculatorul poate reprezenta informa#ia numai sub form! de "iruri de 0 "i 1, toate simbolurile alfanumerice (literele mari "i mici ale alfabetului, cifrele de la 0 la 9, semnele de punctua#ie, operatori aritmetici "i de rela#ie, alte caractere speciale) trebuie traduse n format binar. Reprezentarea informa#iei conform unui anumit format se nume"te codificare. Rezultatul codific!rii este un cod - un set de simboluri elementare mpreun! cu o serie de reguli care specific! modul de formare al acestor simboluri. Un astfel de cod, bazat pe alfabetul englez, este ASCII (American Standard Code for Information Interchange). ASCII este definit de Institutul American de Standarde "i recomandat de ISO (International Standard Organization) ca standard actual de codificare alfanumeric!. Codul ISO pentru ASCII este ISO 8859. Ini#ial, caracterele ASCII au fost codificate pe 7 bi#i, ceea ce nsemna un num!r maxim de 128 !!! ! de simboluri. Ulterior, a fost extins de IBM la 8 bi#i, rezultnd 256 de simboluri (codul fiec!rui simbol este reprezentarea n binar a num!rului s!u de ordine). Chiar extins la 8 bi#i, multe limbi con#in simboluri care nu pot fi condensate n 256 de caractere. De aceea, au fost create variante care con%in caractere "i simboluri regionale. De exemplu, tabela ASCII cunoscut! sub numele

de ISO 8859-1 cuprinde caractere pentru limbile indo-europene apusene (America de Nord, Europa Occidental!, Australia "i Africa). Pentru limba romn! se utilizeaz! tabela ISO 8859-2, destinat! limbilor indo-europene r!s!ritene, sau ISO 8859-16, zona est-european!.
Tabelul 1.2 Codul ASCII Dec Hex Char 0 0 NULL (null) 1 1 SOH (start of heading) 2 2 STX (start of text) 3 3 ETX (end of text) 4 4 EOT (end of transmission) 5 5 ENQ (enquiry) 6 6 ACK (acknowledge) 7 7 BEL (bell) 8 8 BS (backspace) 9 9 TAB (horizontal tab) 10 A LF (NL line feed, new line) 11 B VT (vertical tab) 12 C FF (NP form feed, new page) 13 D CR (carriage return) 14 E SO (shift out) 15 F SI (shift in) 16 10 DLE (data link escape) 17 11 DC1 (device control 1) 18 12 DC2 (device control 2) 19 13 DC3 (device control 3) 20 14 DC4 (device control 4) 21 15 NAK (negative acknowledge) 22 16 SYN (synchronous idle) 23 17 ETB (end of trans. block) 24 18 CAN (cancel) 25 19 EM (end of medium) 26 1A SUB (substitute) 27 1B ESC (escape) 28 1C FS (file separator) 29 1D GS (group separator) 30 1E RS (record separator) 31 1F US (unit separator) Dec Hex Char 32 20 Space 33 21 ! 34 22 35 23 # 36 24 $ 37 25 % 38 26 & 39 27 ' 40 28 ( 41 29 ) 42 2A * 43 2B + 44 2C 45 2D 46 2E . 47 2F / 48 30 0 49 31 1 50 32 2 51 33 3 52 34 4 53 35 5 54 36 6 55 37 7 56 38 8 57 39 9 58 3A : 59 3B ; 60 3C < 61 3D = 62 3E > 63 3F ? Dec Hex Char 64 40 @ 65 41 A 66 42 B 67 43 C 68 44 D 69 45 E 70 46 F 71 47 G 72 48 H 73 49 I 74 4A J 75 4B K 76 4C L 77 4D M 78 4E N 79 4F O 80 50 P 81 51 Q 82 52 R 83 53 S 84 54 T 85 55 U 86 56 V 87 57 W 88 58 X 89 59 Y 90 5A Z 91 5B [ 92 5C \ 93 5D ] 94 5E ^ 95 5F _ Dec Hex Char 96 60 ` 97 61 a 98 62 b 99 63 c 100 64 d 101 65 e 102 66 f 103 67 g 104 68 h 105 69 i 106 6A j 107 6B k 108 6C l 109 6D m 110 6E n 111 6F o 112 70 p 113 71 q 114 72 r 115 73 s 116 74 t 117 75 u 118 76 v 119 77 w 120 78 x 121 79 y 122 7A z 123 7B { 124 7C | 125 7D } 126 7E ~ 127 7F DEL

Primele 32 de caractere ASCII sunt coduri de control. Printre ele se reg!se$te un grup de caractere albe (whitespace). Caracterele albe dicteaz! structura fi"ierelor text prin mp!r#irea acestora n linii (caracterul de linie nou! newline) sau introduc spa#ii albe ntre cuvinte (caracterul tabulator orizontal TAB, "i caracterul de spa#iu - Space). Fi"ierele text con#in litere mici, mari, digi#i numerici, semne de punctua#ie. n total sunt 94 de caractere vizibile. Nu trebuie s! re%ine%i Tabelul 1.2. Totu$i, este indicat s! v! familiariza%i cu unele din

caracteristicile sale generale. n special, observa%i cum caracterele numerice, 0 9, apar ntr-o secven%! contigu! de coduri, !"!" !"!" . Acela$i lucru este valabil $i pentru majuscule, AZ, $i litere mici, a z. De asemenea, observa%i c! literele mici au valoare numeric! mai mare, iar diferen%a ntre codurile celor dou! reprezent!ri pentru un anumit caracter alfabetic este !"!" . Pe lng! caracterele prezente n codul ASCII trebuie s! reprezent!m simboluri matematice, caractere cu indicatori de accent, litere grece"ti, etc.. Acest lucru a dus la apari#ia unui cod nou, care n prezent se bucur! de r!spndire foarte mare "i este predominant n industria produc!toare de programe de calculator: UTF-8, bazat pe standardul UNICODE. n segmentul dezvoltatorilor de aplica#ii web "i servicii Internet a devenit practic noul standard. UTF-8 codific! fiecare din cele 1.112.069 simboluri din setul de caractere UNICODE folosind unul pn! la patru octe#i. Organiza#ia non-profit care coordoneaz! dezvoltarea UNICODE "i propune s! defineasc! un cod standard pentru simbolurile alfanumerice utilizate n toate #!rile lumii: litere, semne de punctua#ie, semne monetare specifice tuturor limbilor de pe planet!. Avantajul major const! n compatibilitatea cu ASCII. Primele 128 de caractere ale setului UTF-8 sunt reprezentate pe un singur octet "i echivalente unu la unu cu cele ASCII. Astfel, orice text scris anterior cu ASCII devine compatibil cu UTF-8. nainte s! trece#i la sec%iunea urm!toare traduce#i cu ajutorul tabelului ASCII de mai sus semnifica#ia "irului dat la nceputul capitolului. Pentru a v! u"ura misiunea, pute#i folosi reprezentarea hexazecimal! sau zecimal! dedus! n paragrafele anterioare.

1.4. Exerci#ii
1.1. Converti%i n hexazecimal urm!toarele $iruri de bi%i: a) 0100 0001 1110 1100 b) 1011 1111 0011 1001 c) 1010 0101 0100 0010 d) 0000 1101 0111 0110

1.2. Converti%i n binar urm!toarele numere hexazecimale: a) 78CF b) 3A7B c) AAAA d) FFFF e) 5591 f) 66DD

1.3. Converti%i n zecimal urm!toarele valori hexazecimale: a) b) c) d) A1 12 FF 80 e) f) g) h) 0C 10 64 4E i) A000 j) FFFF k) ABCD l) 1234

1.4. Converti%i n reprezent!ri hexazecimale de 8 bi%i urm!toarele numere zecimale: a) 100 e) 32 i) 1024 b) 128 f) 64 j) 513 c) 255 g) 16 k) 32767 d) 85 h) 8 l) 2011 1.5. Converti%i n binar urm!toarele numere reale: a) b) c) d) 32.45 147.83 3.0125 255.255 e) f) g) h) 15.32 7.8 63.25 18.5

1.6. Converti%i n caractere ASCII urm!torul text: Telurile sunt prea marete, Eu sunt mic, uitat, nebagat in seama 1.7. Converti%i n text urm!torul $ir de bi%i reprezentat n hexazecimal: 45 72 61 6D 20 73 74 75 64 65 6E 74 2C 20 65 72 61 20 73 74 75 64 65 6E 74 61 20 0D 0A 65 72 61 6D 20 65 6D 69 6E 65 6E 74 2C 20 65 72 61 20 69 6D 69 6E 65 6E 74 61 20 0D 0A 73 69 20 65 72 61 75 20 73 74 65 6C 75 74 65 20 EE 6E 20 67 65 6E 65 6C 65 20 65 69 2E Secven#a 0D 0A denot! trecerea la rnd nou (valabil pentru textul scris n Windows; n Linux, rndul nou este anun#at numai de 0A, caracterul standard \n). 1.8. Scrie%i urm!toarele numere sub form! de caractere ASCII: a) 123 b) 430 c) 15 d) 1094 e) 1452 f) 9966

1.9. Efectua%i opera%iile date mai jos folosind coduri ASCII hexazecimale. Exprima%i rezultatul tot ca reprezentare ASCII. a) b) c) d) F + !"!" F - !"!" o - !"!" m - !"!" 4D e) q Q f) g F g) h a + !"!" h) 4 + 6

2. ARHITECTURA CALCULATOARELOR

Capitolul de fa$! prezint! arhitectura calculatorului, v!zut ca platform! de dezvoltare a programelor. Capitolul ncepe cu descrierea structurii hardware a sistemelor de calcul. Se pune accent pe arhitectura Intel de 32 de bi"i. Func"ionalitatea #i organizarea intern! a componentelor hardware sunt prezentate din perspectiva procesului de dezvoltare a programelor.

2.1. Structura unui sistem de calcul


n capitolul precedent am subliniat faptul c! sistemele de calcul lucreaz! numai cu "iruri de cifre binare 0 sau 1 "i am ar!tat cum pot acestea reprezenta numere sau caractere. Acest tip de informa#ie poart! numele de date. Pe de alt! parte, sistemele de calcul nu sunt simple dispozitive de stocare a datelor. De exemplu, pot fi comandate s! execute toate opera#iile realizate de noi: conversia dintr-o baz! n alta, interpretarea unui "ir binar n ASCII, etc.. Fiecare opera#ie de prelucrare a datelor este codificat! tot sub form! de "ir binar. Dar pentru c! nu codific! o valoare, ci o comand!, aceste "iruri binare se numesc instruc$iuni. Instruc#iunile specific! opera#iile care trebuie efectuate de procesor. Dar aten#ie, procesorul recunoa"te "i execut! numai instruc#iunile pentru care a fost construit. Ansamblul instruc#iunilor recunoscute formeaz! setul de instruc$iuni caracteristic acelui tip de procesor. Un "ir de instruc#iuni "i/sau date organizate logic dup! un algoritm formeaz! un program. Prin intermediul programului, utilizatorul transmite procesorului o anumit! sarcin!; de exemplu, s! citeasc! date de la tastatur! "i s! le afi$eze la monitor.

2.1.1. Arhitectura von Neumann


La acest nivel, programul const! dintr-o secven#! de coduri instruc#iune stocate n memorie. Dac! programele con#in "i date (majoritatea programelor includ unele date constante), ele sunt de asemenea stocate n memorie. Cnd sistemul de operare lanseaz! n execu#ie un program, codurile instruc#iune sunt copiate (nc!rcate) de pe disc n memorie. Rularea unui program nseamn! c! procesorul extrage fiecare instruc#iune din memorie "i execut! opera#ia codificat! de aceasta. Dac! opera#ia implic! prelucrare de date, acestea sunt extrase de asemenea din memorie. Arhitectura unui sistem de calcul care stocheaz! datele "i instruc#iunile mpreun! ntr-o unitate de memorie separat! de unitatea de procesare

se nume"te arhitectur! von Neumann. Arhitectura poart! numele celui care a descris-o abstract ntr-un studiu din 1945, matematicianul John von Neumann (de"i conceptul a fost men#ionat "i de al#i pionieri din domeniul calculatoarelor). La momentul respectiv, acest model de lucru n care datele de prelucrat "i rezultatele calculelor intermediare sunt stocate al!turi de instruc#iuni ntr-o memorie comun!, era diferit de cel al calculatoarelor cu func#ionalitate predeterminat!, unde programele erau stocate pe medii externe, precum cartele sau benzi perforate. n plus, von Neumann a ar!tat c! sistemul de calcul trebuie s! aib! o structur! fizic! fix!, simpl!, "i s! fie capabil de a executa orice fel de calcule pe baza unui control programat, f!r! a fi necesar! modificarea unit!#ilor fizice. De atunci, aceste idei, numite de obicei tehnica programelor stocate, au devenit esen#iale "i au fost acceptate universal. ntr-un calculator cu arhitectur! von Neumann, programul poate fi interpretat "i manipulat ca date. Acest lucru a dat na"tere la compilatoare "i sisteme de operare "i face posibil! versatilitatea calculatoarelor moderne. Tot de aici pleac! "i principalul dezavantaj: un program poate fi scris astfel nct s! se poat! interpreta pe sine ca date, dnd posibilitatea s! se modifice pe el nsu"i. Sistemele de operare moderne, precum GNU/Linux, interzic aplica#iilor s! se automodifice. Modelul von Neumann const! din cinci componente majore, ilustrate n Figura 2.1.
Unitatea de memorie

Unitatea de intrare

Unitatea Aritmetic! "i Logic!

Unitatea de ie"ire

Unitatea de control

Figura 2.1 Arhitectura von Newmann. S!ge$ile ngro%ate reprezint! c!i de date. S!ge$ile sub$iri reprezint! trasee de control.

Unitatea de intrare reprezint! poarta de intrare a instruc#iunilor "i datelor n sistem. Acestea sunt stocate n unitatea de memorie "i prelucrate de unitatea aritmetic! "i logic! (ALU Arithmetic and Logic Unit) sub coordonarea unit!#ii de control. Rezultatele sunt trimise la unitatea de ie"ire. Structura calculatoarelor poate fi descompus! n aceste cinci unit!#i fundamentale chiar "i n prezent.

2.1.2. Modelul bazat pe magistral$


n modelul von Neumann comunica#ia ntre componentele sistemului se realizeaz! prin leg!turi dedicate ntre perechi de componente. Aceast! abordare este relativ rigid!, limitnd n mare m!sur! scalabilitatea sistemului. Ad!ugarea de noi componente este dificil! "i implic! modificarea componentelor deja existente. De asemenea, proiectarea unei componente noi presupune cunoa"terea n am!nun#ime a func#ion!rii celorlalte componente. Solu#ionarea acestei probleme a venit din partea firmei Digital Equipment Corporation (DEC), care, la sfr"itul anilor 60, a lansat pe pia#! primul calculator (PDP 11) construit n jurul unei magistrale de sistem.

CPU (ALU, Registre !i Control)

Memorie

Intrare !i Ie!ire (I/O)

Magistrala de sistem

Magistrala de date Magistrala de adrese Magistrala de control

Figura 2.2 Modelul bazat pe magistral! al unui calculator

Aceast! rafinare a modelului von Neumann combin! ALU "i unitatea de control ntr-o singur! unitate func#ional!, numit! unitate central! de prelucrare (CPU Central Processing Unit). Totodat!, unit!#ile de intrare "i ie"ire sunt de asemenea combinate ntr-o singur! unitate de intrare "i ie"ire. A"adar, principalele componente hardware2 ale unui sistem de calcul sunt: procesor sau unitate central! de prelucrare; memorie sau unitate de memorare (memoria RAM Random Access Memory3); unitate de intrare/ie"ire (unitate I/O). La aceast! interfa#! sunt conectate dispozitivele de intrare/ie"ire. Elementul definitoriu al acestui model const! n faptul c! toate componentele sistemului comunic! ntre ele prin intermediul unei magistrale de
2 3

Componentele fizice ale unui sistem (structuri mecanice, cabluri, cutii, circuite, etc.). Random se refer! la faptul c! timpul de acces la orice unitate de memorie este constant "i independent de loca#ia fizic! a acesteia sau de secven#ele accesurilor anterioare.

sistem. Din punct de vedere conceptual, magistrala este un mediu comun de comunica#ie ntre componentele unui sistem de calcul; fizic, este alc!tuit! dintr-un set de semnale care faciliteaz! transferul de date "i instruc#iuni, precum "i sincronizarea ntre componentele sistemului.

2.1.1. Magistrala de sistem


Transferul de informa#ii pe magistral! se face pe baza unui set de reguli (un protocol) care stabile"te cine, cnd "i cum se comunic! pe magistral!. A"adar, magistralele sunt ansambluri de conexiuni fizice (fire) prin care circul! informa#ie n conformitate cu un set de reguli, avnd ca suport semnale electrice. Prin termenul de magistral! se mai n#elege de regul! "i ansamblul de circuite electronice care amplific! puterea semnalelor electrice sau aduc nivelul acestora (de ex., tensiunea) la valoarea standard. n func#ie de informa#ie, semnalele electrice sunt de trei tipuri: de date (reprezint! informa#ia propriu zis!), de adrese (semnale care identific! loca#ia la care este transmis! informa#ia) "i de control (descriu aspecte legate de modul "i maniera n care este transmis! informa#ia). Nu este obligatoriu ca o magistral! s! implementeze c!i fizice separate pentru fiecare din aceste trei tipuri de semnale. De exemplu, standardul PCI folose"te acela"i suport fizic att pentru date ct "i pentru adrese, dar la momente diferite. Tipul informa#iilor (sau direc#ia lor) aflate pe magistral! la un moment dat este indicat prin semnale de control. Din acest punct de vedere putem clasifica magistralele n unidirec#ionale "i bidirec#ionale. Magistralele unidirec#ionale pot transmite informa#iile ntr-un singur sens, cele bidirec#ionale n ambele sensuri. Magistrala de adrese este unidirec#ional! (de la procesor spre sistem) iar magistralele de date "i control sunt bidirec#ionale. Un program const! dintr-o secven#! de instruc#iuni stocat! n memorie. Atunci cnd procesorul este preg!tit s! execute urm!toarea instruc#iune, plaseaz! adresa loca#iei de memorie care con#ine acea instruc#iune pe magistrala de adrese. Totodat!, procesorul plaseaz! un semnal de citire pe magistrala de control. Unitatea de memorie r!spunde prin plasarea instruc#iunii pe magistrala de date, de unde poate fi citit!4 de procesor. Dac! procesorul trebuie s! citeasc! date din memorie, are loc aceea"i secven#! de evenimente. Atunci cnd procesorul trebuie s! scrie5 date n memorie, acesta plaseaz! datele pe magistrala de date, adresa loca#iei de memorie (la care trebuie acestea stocate) pe magistrala de adrese, "i un semnal de scriere pe magistrala de control. Unitatea de memorie r!spunde prin copierea pe magistrala de date a datelor prezente la loca#ia specificat!. Dac! o instruc#iune solicit! un transfer de date din/c!tre memorie, urm!toarea instruc#iune nu mai poate fi citit! din memorie pe aceea"i magistral!
4 5

Opera#ia de citire se traduce prin extragerea unei date stocate anterior. Opera#ia de scriere se traduce prin stocarea unei date n memorie.

dect dup! finalizarea acestuia. Acest conflict a dat na"tere la o alt! arhitectur! bazat! pe tehnica programelor stocate, arhitectura Harvard. n arhitectura Harvard, programul "i datele sunt stocate n memorii diferite, fiecare conectat! la procesor prin propria magistral!. Acest lucru permite procesorului s! acceseze simultan att instruc#iunile ct "i datele programului. n calculatoarele moderne, magistrala care conecteaz! procesorul de modulele externe de memorie nu poate #ine pasul cu viteza de execu#ie a procesorului. ncetinirea vitezei de transfer pe magistral! poart! numele de "trangulare von Neumann (von Neumann bottleneck). Interac#iunea procesorului cu dispozitivele de intrare/ie"ire se face prin acela"i mecanism ntlnit la interac#iunea procesorului cu memoria. Dac! procesorul trebuie s! citeasc! date de la un dispozitiv de intrare, plaseaz! adresa acestuia pe magistrala de adrese "i un semnal de citire pe magistrala de control. Dispozitivul r!spunde prin nc!rcarea datelor pe magistrala de date. Cnd procesorul trebuie s! trimit! date la un dispozitiv de ie"ire, plaseaz! datele pe magistrala de date, specific! adresa dispozitivului pe magistrala de adrese "i activeaz! semnalului de scriere pe magistrala de control. Deoarece viteza de r!spuns a diferitelor dispozitive I/O variaz! drastic fa#! de viteza procesorului sau memoriei, programatorul trebuie s! utilizeze tehnici speciale de programare. O alt! caracteristic! de baz! a magistralelor este dimensiunea acestora, adic! num!rul liniilor de conectare; avem magistrale de 8 bi#i (8 linii de conectare), 16 bi#i (16 linii de conectare), etc.. Dimensiunea fiec!rei magistrale este determinat! de tipul de procesor (de 8, 16, 32, 64 de bi#i) "i determin! la rndul s!u num!rul de loca#ii de memorie ce pot fi adresate (capacitatea memoriei) "i structura porturilor din dispozitivele de intrare/ie"ire. De exemplu, o magistral! de 32 de bi#i poate adresa o memorie RAM de !!" ! !!" ! !! ! !!!"!

2.1.2. Unitatea de intrare/ie%ire


Majoritatea programelor trebuie s! comunice cu dispozitive I/O. Tipul dispozitivelor I/O variaz! foarte mult. Unele sunt menite s! interac#ioneze cu utilizatorul (de exemplu, tastatura, monitorul, mouse-ul), altele s! permit! programelor interac#iunea cu unit!#i hardware (de exemplu, stocarea un fi"ier pe disc sau citirea unui fi"ier din re#ea). Toate aceste dispozitive se comport! diferit "i cerin#ele lor de sincronizare difer! drastic de la unul la altul. Din moment ce programarea dispozitivelor I/O este dificil!, dar aproape toate programele au nevoie de acestea, software-ul care gestioneaz! dispozitivele I/O este inclus n sistemul de operare. Sistemele Linux includ un set bogat de func#ii care permit programatorilor de aplica#ii s! efectueze opera#ii de intrare/ie"ire. ntr-un capitol viitor vom apela "i noi la serviciile puse la dispozi#ie de sistemul de operare pentru ndeplinirea unor opera#ii de intrare/ie"ire. A"adar, pe lng! componentele hardware, un sistem de calcul dispune "i de

o component! software6 fundamental!: sistemul de operare. De fapt, termenul arhitectura calculatoarelor define"te grani#a dintre hardware "i software, "i putem afirma, f!r! s! fim acuza#i de partizanat, c! arhitectura calculatorului reprezint! sistemul de calcul v!zut de un programator n limbaj de asamblare.

2.1.3. Memoria
Memoria sistemului, numit! "i memorie principal!, este folosit! la stocarea informa#iilor (instruc#iuni "i date) n format binar "i reprezint! sursa sau destina#ia tuturor informa#iilor. Toate informa#iile ini#iale "i rezultatele prelucr!rilor sunt nc!rcate, generate sau stocate temporar n memorie. Memoria este organizat! ca o colec#ie de loca#ii de memorare, numerotate consecutiv, ncepnd cu zero. Unitatea de baz! a memoriei este octetul. Ne putem imagina memoria ca "ir liniar de octe#i suprapu"i, asemenea unui dulap cu sertare numerotate, fiecare sertar avnd capacitatea de 8 bi#i (Figura 2.3). Num!rul fiec!rui sertar este ceea ce numim n general adres! fizic!, iar sertarul, n programare, se nume"te loca$ie de memorie. Adresele permit identificarea fiec!rui octet din memorie. Mul#imea total! a adreselor fizice constituie spa$iul adreselor fizice, iar num!rul de bi#i dintr-o loca#ie de memorie reprezint! dimensiunea loca$iei sau formatul memoriei. n cazul nostru, consider!m dimensiunea loca#iei ca fiind de 8 bi#i. Figura 2.3 prezint! o memorie adresat! printr-o magistral! de 20 de bi#i. Dimensiunea magistralei, adic! num!rul liniilor de conectare, determin! num!rul de loca#ii de memorie ce pot fi adresate. n acest caz, adresa fizic! a primului octet, de jos n sus, este reprezentat! prin 20 de bi#i de 0.
FFFFFH . . . 00003H 00002H 1 0 0 0 1 0 0 1 00001H 00000H 0 7

Figura 2.3 Reprezentarea memoriei principale

n programare ntotdeauna num!r!m ncepnd cu zero. Urm!torul octet are adresa 1, ".a.m.d, pn! la adresa ultimului octet ce poate fi adresat cu 20 de bi#i, adresa cu to#i bi#ii de 1. n Figura 2.3 adresele sunt reprezentate n hexazecimal. Num!rul total de octe#i de memorie este !!" ! !"#$%&'. n binar, prefixul kilo este asociat
6

Componentele imateriale (programe de sistem "i aplica#ii).

cu !"#$ ! !!" , prefixul Mega "i Giga cu !"#$%&' ! !!" , respectiv !"#$#%!&'% ! !!" . n concluzie, Figura 2.3 ilustratreaz! o memorie RAM cu capacitatea de 1 MB. Pe viitor va fi foarte important s! st!pni#i la perfec#ie puterile lui 2 prezentate n Tabelul 2.1. V! vor ajuta s! evalua#i rapid capacitatea de memorie adresabil! cu o magistral! de 16 sau 32 de bi#i. Memoria se m!soar! n unit!$i de ordinul kilobytes (kB), megabytes (MB), gigabytes (GB).
Tabelul 2.1 Puteri ale lui 2 n binar #i zecimal

Binar 1 10 100 1000 10000 100000 1000000 10000000 100000000 1000000000 10000000000 100000000000 1000000000000 10000000000000 100000000000000 1000000000000000 10000000000000000 100000000000000000 1000000000000000000 10000000000000000000 100000000000000000000

Puteri ale lui 2 !! !! !! !! !! !! !! !! !! !! !!" !!! !!" !!" !!" !!" !!" !!" !!" !!" !!"

Zecimal 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576

2.2. Arhitectura IA-32


n aceast! carte studiem arhitectura procesoarele Intel de 32 de bi#i sau compatibile. Num!rul acestora este impresionant. Intel a produs microprocesoare nc! din 1969. Primul lor microprocesor a fost 4004. Era un procesor de 4 bi#i (capacitatea de memorare a registrelor specific! tipul de procesor). A fost urmat de 8080 "i 8085. Dezvoltarea acestor microprocesoare a dus la apari#ia arhitecturii

Intel (IA Intel Architecture).

2.2.1. Arhitectur$ %i microarhitectur$


Primul procesor al arhitecturii Intel este 8086, ap!rut n 1978. Avea o magistral! de adrese de 20 de bi#i "i o magistral! de date de 16 bi#i. Deoarece registrele interne "i magistrala de date erau de 16 bi#i, 8086 a fost considerat primul procesor de 16 bi#i. Magistrala de adrese de 20 de bi#i i permitea s! adreseze 1 MB de memorie. 8088 a fost versiunea mai ieftin! a lui 8086. Reducerea pre#ului s-a ob#inut prin folosirea unei magistrale de date de 8 bi#i. Cu excep#ia acestei deosebiri, 8088 este identic cu 8086. 80186 a fost varianta mai rapid! a lui 8086. Dispunea de acelea"i magistrale, dar un set mbun!t!#it de instruc#iuni. ns! 80186 nu a fost niciodat! foarte ndr!git de produc!torii de calculatoare. Adev!ratul succesor al lui 8086 a fost 80286, introdus n 1982. Magistrala de adrese de 24 de bi#i i permitea s! adreseze o memorie de 16 MB "i includea cteva posibilit!#i de protec#ie a memoriei. Primul procesor de 32 de bi#i, 80386, apare n 1986. Are o magistral! de adrese de 32 de bi#i "i o magistral! de date tot de 32 de bi#i. Spa#iul de memorie adresabil a crescut la 4 GB "i a fost introdus mecanismul pagin!rii (vom prezenta detalii cu privire la acest aspect ceva mai trziu). Paginarea a permis un model liniar de memorie - spa#iu liniar, continuu de adrese7 (modelul de memorie prezentat de noi n sec#iunea precedent!) "i prin el, posibilitatea port!rii sistemelor de operare din familia Unix pe arhitecturi Intel. Intel 80486 apare n 1989 ca variant! mbun!t!#it! a lui 80386. Pentru prima dat! un procesor Intel ncorpora unitatea de calcul aritmetic n virgul! mobil! (d! posibilitatea efectu!rii opera#iilor cu numere reale). Pn! atunci, unitatea de calcul n virgul! mobil! era prezent! sub forma unui coprocesor extern. 80486 dispune "i de alte mbun!t!#iri tehnologice: unit!#ile de decodificare "i execu#ie a instruc#iunilor cu capacitate de lucru n paralel, 8 kB L1 cache, prezen#a unui cache L2. Versiunile ulterioare includ tehnologii de economisire a consumului de energie (power saving), utile n special laptop-urilor. Pentium/Pentium Pro aduc foarte pu#ine elemente noi. n principal m!resc viteza de execu#ie. Pentium MMX aduce suport MMX (MultiMedia eXtensions) - instruc#iuni ce m!resc viteza opera#iilor grafice. Pentium II este un Pentium Pro cu suport MMX. Pentium III, n esen#! un Pentium II mai rapid, introduce arhitectura SIMD (Single Instruction Multiple Data) pentru execu#ia concurent! a mai multor opera#ii n virgul! mobil!.
7

Adresele pornesc de la zero "i se succed, ntr-un mod liniar, f!r! goluri sau ntreruperi, pn! la limita superioar! impus! de num!rul total de bi#i dintr-o adres! logic!.

Pentium 4 mbun!t!#e"te aceste caracteristici. Tot de la Pentium 4 apar primele modele de 64 de bi#i (arhitectur! botezat! ini#ial EMT64T). Pentium 4 a fost urmat de Pentium Xeon, Pentium II Xeon, Pentium Core, Celeron, Core Duo, Core 2 Duo, Core i3, Core i5, Core i7 "i multe altele. Toate acestea au fost fabricate numai de Intel. Alte companii, n special AMD, au fabricat propriile procesoare compatibile cu cele produse de Intel. Arhitectura n capitolele precedente am afirmat c! programarea n asamblare necesit! cuno"tin#e legate de procesor. Legate de se refer! la ce face un procesor, spre deosebire de cum face un procesor. Perspectiva programatorului include, printre altele, num!rul "i tipul de registre, setul de coduri instruc#iune recunoscut, modul de adresare a memoriei, prezen#a sau lipsa unor unit!#i de uz special precum coprocesorul matematic (cu propriile instruc#iuni "i registre). Toate aceste lucruri sunt definite de produc!tor, iar defini#iile, luate mpreun!, formeaz! arhitectura procesorului. The architecture, as I see it, is the high-level specs of the processor. This consists of the instructions set, memory structure, memory segmentation, register structure, I/O space, interrupt mechanism, instruction operands, memory addressing modes, and so on. Stephen Morse8 Cu timpul, arhitectura este mbog!#it! cu noi instruc#iuni, registre sau alte caracteristici. De obicei, noile caracteristici nu modific! modul de lucru anterior, ci adaug! noi op#iuni. Acest lucru asigur! compatibilitatea noilor platforme cu programele scrise anterior (backward compatibility). Anterior nseamn! c! programe scrise pentru 8086 pot rula "i ast!zi pe un Core i7. Cteodat!, pe lng! ad!ugarea periodic! de noi instruc#iuni, arhitecturile sufer! schimb!ri mai importante. Am v!zut c!, n 1986, o dat! cu apari#ia procesorului 80386, pe lng! introducerea unor noi instruc#iuni "i moduri de operare, Intel dubleaz! capacitatea registrelor. Se f!cea astfel trecerea la arhitectura de 32 de bi#i. Aceast! arhitectur! poart! numele de IA-32 (i386, x86-32). Este arhitectura studiat! de noi n aceast! carte. n 2003, arhitectura x86 se extinde iar!"i, de data aceasta la 64 de bi#i; noi instruc#iuni, noi moduri de operare, registre de capacitate dubl!. P!rintele acesteia este principalul competitor Intel, AMD, care o nume"te AMD64. La acea dat!, Intel lansase deja propria arhitectur! de 64 de bi#i, numit! IA-64 (Itanium), dar incompatibil! cu precedentele procesoare x86 (set de instruc#iuni diferit de x86). Pentru c! nu se bucur! de foarte mult succes, compania Intel este nevoit! s! produc! o familie de procesoare compatibil! cu arhitectura "i specifica#iile AMD. Termenul generic pentru noua arhitectur! de 64 de bi#i, compatibil! cu x86, este x86-64.
8

P!rintele arhitecturii microprocesorului Intel 8086.

Arhitectura x86-64 include arhitectura IA-32, care la rndul s!u include vechea arhitectur! x86 de 16 bi#i. Totu"i, la proiectarea unei aplica#ii, programatorul trebuie s! "tie care sunt procesoare compatibile cu instruc#iunile folosite. Aplica#ia nu va rula pe procesoarele dinaintea apari#iei instruc#iunilor respective. Microarhitectura Problemele ridicate de p!strarea compatibilit!#ii cu programele dezvoltate anterior limiteaz! cre"terea performan#elor prin mijloacele arhitecturii. Dou! din cele mai importante criterii de performan#! constau n num!rul total de instruc#iuni pe care un procesor este capabil s! l execute ntr-un anumit interval de timp (throughput) "i consumul de energie. Num!rul de instruc#ini pe unitate de timp trebuie s! fie ct mai mare (vitez! de procesare mai mare), iar consumul de energie ct mai mic. n cazul celui din urm!, motivul este mai subtil. O bun! parte din energia utilizat! de procesor se pierde sub form! de c!ldur!; aceste pierderi, dac! nu sunt minimizate, pot leza procesorul "i componentele din vecin!tate. Proiectan#ii caut! ntotdeauna solu#ii care s! permit! efectuarea acelora"i sarcini cu consum mai mic de energie. Unele din acestea permit procesorului s! intre n starea de repaus (stand-by) n momentele n care nu este folosit. Puterea de procesare a crescut prin dezvoltarea unor mecanisme precum citirea anticipat! a instruc#iunilor (prefetching), execu#ie n benzi de prelucrare (pipelining), execu#ia paralel! (hyper threading), predic#ia salturilor (branch prediction), execu#ia speculativ!, memorii intermediare L1 "i L2 (cache), "i multe altele. Unele tehnici reduc sau elimin! blocajele din interiorul procesorului, astfel nct acesta s! lucreze permanent (aici, un rol important l are mecanismul de lucru cu memoria), altele permit procesorului s! execute mai multe instruc#iuni n acela"i timp. mpreun!, aceste mecanisme fizice prin care procesorul ndepline"te opera#iile codificate n instruc#iuni, formeaz! microarhitectura procesorului. n vederea cre"terii performan#elor, Intel "i AMD reproiecteaz! constant microarhitecturile procesoarelor. n acest context se nscriu "i eforturile de mbun!t!#ire a tehnicilor de fabrica#ie a pastilelor de siliciu, tehnici ce permit cre"terea num!rului de tranzistoare plasate pe un singur cip. Toate numele exotice, NetBurst, Core, Nehalem, Sandy Bridge, Ivy Bridge, indic! modific!ri ap!rute n microarhitectur!.

2.2.2. Structura de principiu a procesorului


n aceast! sec#iune detaliem modul n care programatorul vede structura procesorului "i modul n care procesorul interac#ioneaz! cu memoria principal!. Figura 2.4 prezint! schema bloc general! a unui procesor. Unit!#ile sunt conectate prin magistrale interne. Re#ine#i c! aceasta este o diagram! extrem de simplificat!. Procesoarele reale sunt mult mai complexe, dar conceptele generale discutate n acest capitol se aplic! tuturor.

Indicatorul de instruc!iune Memorie L1 Cache Registrul de instruc!iune

Unitatea de control Registre Unitatea Aritmetic" #i Logic" Interfa!a cu magistralele

Registrul indicatorilor de stare

c"tre magistralele de adrese, date #i control


Figura 2.4 Structura general! a unui procesor

n continuare descriem pe scurt fiecare unitate n parte. Componentele de interes special pentru programator sunt prezentate pe larg pu#in mai trziu. Unitatea de interfa"$ cu magistrala Unitatea de interfa#! cu magistrala de sistem este mijlocul prin care procesorul comunic! cu restul componentelor din sistem memorie "i dispozitive de intrare/ie"ire. Unitatea con#ine circuite ce permit plasarea adreselor pe magistrala de adrese, plasarea semnalelor de citire "i scriere pe magistrala de control, citirea "i scrierea datelor pe magistrala de date. De obicei, unitatea de interfa#! cu magistrala este conectat! la unit!#i externe de control al magistralelor, care, la rndul lor, sunt conectate la memorie sau la diferite dispozitive I/O (de ex., SATA, PCI-E, etc.). Pentru programator, aceste unit!#ile externe de control sunt invizibile. Unitatea de management a memoriei ncepnd cu procesoarele de 16 bi#i apare no#iunea de adres! logic!. Adresele generate de sistemul de operare sunt considerate adrese logice "i totalitatea acestora formeaz! spa$iul de adrese logice. Aceste no#iuni constrasteaz! cu cele de adres! fizic! (aflat! pe magistrala de adrese) "i spa$iu de adrese fizice discutate n sec#iunea dedicat! memoriei principale. Din punct de vedere al

num!rului de adrese, cele dou! spa#ii, al adreselor fizice "i logice, pot fi egale sau inegale. Ca urmare, procesorul trebuie s! dispun! de un mecanism de conversie a adreselor (un mecanism de translatare a adreselor logice n adrese fizice). La procesoarele Intel x86 mecanismul de translatare este inclus pe acela"i substrat de siliciu cu microprocesorul. Datorit! mecanismului de translatare a adreselor, modul de organizare al memoriei poate fi definit prin software, de c!tre sistemul de operare. Dac! procesorul permite adresarea liniar! a ntregului spa#iu de adrese fizice (adresele fizice ncep de la 0 "i avanseaz! liniar), atunci "i sistemul de operare poate organiza memoria ca structur! liniar! (adresele logice ncep de la 0 "i avanseaz! liniar). Pe de alt! parte, atunci cnd procesorul poate adresa liniar numai anumite segmente de memorie, segmente cu lungimi mai mici dect capacitatea total! a memoriei, vorbim de organizare segmentat!. n acest caz, spa#iul de adrese logice este mp!r#it n mai multe spa#ii cu adresare liniar!, fiecare de lungime diferit!, "i o adres! logic! este calculat! ca sum! ntre adresa de nceput a unui segment (adresa de nceput a unui bloc de memorie) "i un deplasament n cadrul acestuia. Memorii intermediare Cnd procesorul are nevoie de informa#ii aflate n memoria principal! trimite c!tre unitatea de management a memoriei o cerere de citire memorie. Unitatea de management a memoriei trimite cererea respectiv! la memorie "i, atunci cnd informa#ia se afl! pe magistrala de date, anun#! procesorul. Lungimea ntregului ciclu procesor, controler de memorie, memorie, (napoi la) procesor -, variaz! n func#ie de viteza memoriei "i a magistralei de date. A"adar, o memorie cu timp de acces mai mic contribuie semnificativ la performan#a sistemului. Performan$a memoriei este cuantificat! prin intermediul a doi parametrii: timpul de acces - perioada de timp necesar! memoriei s! extrag! datele din loca$ia adresat!, %i timpul unui ciclu la memorie - timpul minim ntre dou! opera$ii succesive de acces la memorie. Totu"i, viteza de lucru a memoriei "i eforturile de cre"tere a acesteia reprezint! numai o fa#et! a problemei. Timpul necesar datelor "i intruc#iunilor s! parcurg! traseul dintre memorie "i procesor este mult mai mare dect timpul consumat de procesor pentru prelucrarea acestora (acest fenomen se nume"te "trangulare von Neumann). De aceea, ntre procesor "i memoria principal! a fost introdus! o memorie intermediar!, numit! cache. Memoria cache este o memorie foarte rapid!, de mici dimensiuni (tipic, mai pu#in de 1MB), plasat! foarte aproape de procesor. Este proiectat! s! p!streze datele "i instruc#iunile solicitate frecvent de procesor. Pentru c! preluarea datelor din cache are loc numai ntr-o frac#iune din timpul necesar acces!rii memoriei principale, prezen#a memoriei cache salveaz! foarte mult timp. Principiul pe care se bazeaz! mecanismul cache este regula 80/20, care spune c!, din toate programele, informa#iile "i datele din calculator, aproximativ 20% sunt utilizate 80% din timp. n consecin#!, este foarte probabil ca datele "i

instruc#iunile folosite de procesor la un moment dat s! fie necesare din nou, la pu#in timp dup!. Memoria cache este ca o list! fierbinte (hot list) de instruc#iuni necesare procesorului. Unitatea de management a memoriei salveaz! n cache fiecare instruc#iune solicitat! de procesor; la o nou! cerere similar!, procesorul prime"te instruc#iunea din cache (cache hit). Totodat!, acea instruc#iune avanseaz! c!tre partea superioar! a listei. Atunci cnd memoria cache este plin! "i procesorul solicit! o nou! instruc#iune, sistemul suprascrie instruc#iunile care nu au fost utilizate de cea mai lung! perioad! de timp. Acest mecanism este valabil "i pentru date. n acest fel, informa#iile cu prioritate ridicat!, folosite des, r!mn n cache, n timp ce informa#iile mai pu#in utilizate sunt eliminate. n prezent, memoriile cache sunt ncorporate chiar n cipul procesorului. Cum majoritatea procesoarelor con#in mai multe nuclee de procesare, numite coreuri, n func#ie de proximitatea sa fa#! de acestea, memoria cache are atribuit un nivel. Memoria cache cea mai aproape de un nucleu se nume"te cache de nivel 1 (L1), urm!torul nivel de cache este notat L2, apoi L3, ".a.m.d.. De exemplu, un procesor Core i7 Quad dispune de 64 kB cache L1 (32 kB pentru instruc#iuni, 32 kB pentru date), 1 MB cache L2, ambele per nucleu, "i de 8 MB cache L3, partajat ntre nuclee. Toate pe pastila procesorului. Totodat!, majoritatea procesoarelor moderne folosesc dou! memorii cache L1, una pentru date "i una pentru instruc#iuni, n configura#ie arhitectural! tip Harvard. Conceptul de cache se aplic! nu numai memoriei principale, ci "i mediului de stocare. De exemplu, sistemul de operare poate folosi memoria principal! ca memorie intermediar! pentru disc. n acest caz, memoria principal! nregistreaz! cele mai recente date citite de procesor de pe disc sau stocheaz! date ce vor fi scrise de procesor pe disc la un moment viitor. Re#inem a"adar c! termenul cache se poate referi att la memorie ct "i la alte tehnologii de stocare. Registre Unele instruc#iuni au nevoie ca datele prelucrate de acestea s! fie memorate chiar n interiorul procesorului. Acest lucru se realizeaz! prin intermediul unor loca#ii de memorie numite registre. Registrele sunt loca$ii de memorie volatil!9 aflate n interiorul procesorului. Procesorul acceseaz! mult mai rapid datele stocate n registre dect pe cele aflate n memoria principal! sau cache. Pe de alt! parte, num!rul de registre este limitat. Dimensiunea registrelor, n bi#i, determin! "i arhitectura procesoarelor - procesoare de 16, 32 sau 64 de bi#i. n aceast! carte ne referim la arhitectura procesoarelor Intel de 32 de bi#i - registrele interne au capacitatea de 4 octe#i. Indicatorul de instruc"iune Indicatorul de instruc#iune este registrul care memoreaz! adresa urm!toarei
9

n lipsa unei surse de energie, informa#iile sunt pierdute. Memoria RAM este tot o memorie volatil!.

instruc#iuni din secven#a de cod executat!. Registrul de instruc"iune Instruc#iunile sunt simple "abloane (pattern) de bi#i. Acest registru con#ine instruc#iunea executat! n acel moment. Modelul s!u de bi#i determin! unitatea de execu#ie s! comande celorlalte unit!#i din procesor o anumit! opera#ie. Odat! ce ac#iunea a fost finalizat!, bi#ii instruc#iunii (bi#ii prin care aceasta a fost codificat!) din registrul de instruc#iune pot fi nlocui#i "i procesorul va efectua opera#ia specificat! de bi#ii noii instruc#iuni. Unitatea de execu"ie Bi#ii din registrul de instruc#iune sunt decodifica#i de unitatea de execu#ie. Aceasta genereaz! semnalele care comand! celorlalte unit!#i din procesor efectuarea ac#iunilor specificate de instruc#iune. De obicei este implementat! sub forma unei ma"ini cu st!ri finite care con#ine decodoare, multiplexoare "i alte circuite logice. Unitatea aritmetic$ %i logic$ (ALU) ALU denot! circuitele electronice care efectueaz! opera#ii aritmetice "i logice pe grupuri de bi#i de date. Registrul indicatorilor de stare Registrul indicatorilor de stare semnaleaz! anumite evenimente ap!rute n cadrul opera#iilor aritmetice "i logice. De exemplu, opera#ia de adunare poate produce un transport. Un anumit bit din registrul indicatorilor de stare va fi setat n zero (nu exist! transport) sau unu (exist! transport) de fiecare dat! cnd ALU a finalizat o astfel de opera#ie.

2.2.3. Func"ionarea procesorului


Setul de instruc#iuni n idiom binar care poate fi executat de un procesor formeaz! limbajul ma%in! al acelui tip de procesor. Instruc$iunile ma%in! sunt "iruri de numere binare pe care procesorul le decodific! "i execut! foarte rapid. Fiecare tip de procesor are propriul limbaj ma"in!. Din aceast! cauz!, programele scrise pentru procesoarele Intel x86 nu pot rula pe alte tipuri de procesoare (POWER, SPARC, Intel Itanium, ARM). Procesorul poate fi privit ca dispozitiv ce execut! la nesfr"it urm!torul proces: Extragere instruc#iune din memorie (fetch); Decodificare instruc#iune (decode); Execu$ie instruc#iune.

Acest proces este numit ciclu de extragere-decodificare-execu#ie sau, simplu, ciclu de execu$ie.
Ciclu de execu!ie Extrage Decodific" Execut" Extrage timp Decodific" Execut"

La primele procesoare, de exemplu 8080, etapele ciclului de execu#ie se realizau secven#ial. ncepnd cu 80286, acestea sunt efectuate n paralel. n plus, fiecare microarhitectur! nou! ad!ug! diferite tehnici de eficientizare. Totu"i, din perspectiva programatorului, mecanismul prezentat aici este tot ce intereseaz!. Extragerea unei instruc#iuni din memorie presupune plasarea adresei sale pe magistrala de adrese "i activarea semnalului de citire pe magistrala de control (lucru care indic! inten#ia de citire a loca#iei respective). Dup! ini#ierea cererii de citire procesorul a"teapt! apari#ia instruc#iunii pe magistrala de date. Decodificarea presupune identificarea instruc#iunii extrase. Pentru facilitarea acestui proces, instruc#iunile ma"in! folosesc o schem! particular! de codificare (un cod de opera#ie). Execu$ia instruc#iunii nseamn! prelucrarea opera#iei aritmetice sau logice. Execu#ia instruc#iunilor este sincronizat! cu ajutorul unui generator de tact, numit ceas10. Generatorul de tact pulseaz! la o frecven#! fix! cunoscut! sub numele de frecven#a ceasului (de"i se utilizeaz! uzual "i termenul de frecven#a procesorului). Ceasul nu contorizeaz! minute sau secunde, doar cicleaz! la o frecven#! constant!. Circuitele electronice din procesor folosesc aceast! frecven#! pentru a executa opera#iile corect, a"a cum un dirijor dicteaz! ritmul unei piese. Frecven#a impulsurilor de tact determin! viteza de execu#ie a instruc#iunilor. Fiecare ciclu de execu#ie a unei instruc#iuni poate fi descompus ntr-o serie de opera#ii elementare efectuate n paralel, pe durata unui singur impuls de tact (ciclu de tact). O asemenea opera#ie elementar! (o singur! prelucrare numeric! a informa#iei sau un transfer de date ntre procesor "i memorie) se nume"te micro-opera#ie. Num!rul de cicli de tact necesari execu#iei unei instruc#iuni depinde att de instruc#iune ct "i de modelul "i genera#ia procesorului. O frecven#! mai mare nu nseamn! neap!rat "i num!r de opera#ii pe secund! mai mare, depinde de arhitectura procesorului.

2.2.4. Registrele procesorului


Arhitectura IA-32 pune la dispozi#ia programatorului zece registre de 32 de bi#i "i "ase registre de 16 bi#i. Aceste registre sunt grupate n urm!toarele categorii: registre de uz general, registre de control "i registre de segment. Registrele de uz general sunt la rndul lor mp!r#ite n registre de date, registre indicator "i registre
10

Generator electronic pilotat de un cristal de cuar#, care asigur! stabilitatea frecven#ei la varia#ia tensiunii de alimentare "i a temperaturii.

index. Registre de date


32 de bi!i # EAX EBX ECX EDX 16 bi!i # AX BX CX DX

31

16

15 AH BH CH DH

8 7 AL BL CL DL

Figura 2.5 Registre de date

Arhitectura IA-32 pune la dispozi#ie patru registre de date de 32 de bi#i fiecare destinate opera#iilor aritmetice "i logice, dar nu numai. Aceste patru registre pot fi folosite dup! cum urmeaz!: 4 registre de 32 de bi#i: EAX, EBX, ECX, EDX; sau 4 registre de 16 bi#i: AX, BX, CX, DX; sau 8 registre de 8 bi#i: AH, AL, BH, BL, CH, CL, DH, DL (H = High, L = Low). Registrele de date pot fi folosite f!r! constrngere n majoritatea instruc#iunilor aritmetice "i logice. Totu"i, cnd sunt executate anumite instruc#iuni, unele registre din acest grup au func#ii speciale. De exemplu, registrele EAX (AX), denumit acumulator, "i EDX (DX), au rol prestabilit n instruc#iunile de nmul#ire, mp!r#ire "i de transfer I/O. ECX (CX) este utilizat drept num!r!tor pentru opera#iile de deplasare, rota#ie, bucle, repeti#ii de instruc#iuni. Registre index %i indicator
31 ESI EDI 16 15 SI DI 0 Source Index Destination Index

Figura 2.6 Registre index


31 ESP EBP 16 15 SP BP 0 Stack Pointer Base Pointer

Figura 2.7 Registre indicator

Arhitectura IA-32 nglobeaz! dou! registre index "i dou! registre indicator. Acestea pot fi folosite ca registre de 16 sau 32 de bi#i. Registrele index au rol principal n prelucrarea instruc#iunilor, dar pot fi folosite "i ca registre de date. Registrele indicator sunt folosite n special pentru lucrul cu stiva.

Stiva este o zon! din memoria principal! organizat! dup! principiul LIFO (Last In First Out), folosit! ca mijloc de depozitare a datelor temporare. Stivele sunt strict necesare n lucrul cu subprograme (proceduri %i func$ii), cnd registrele interne trebuie eliberate n vederea execu$iei unei func$ii care va suprascrie registrele cu propriile sale date. Eliberarea registrelor se face prin salvarea lor n stiv!, ntr-o anumit! ordine, %i refacerea lor din stiv! la revenirea n programul apelant. Registre de control
31 EIP 16 15 IP 0 Instruction Pointer

Figura 2.8 Indicatorul de instruc$iune

Acest grup de registre const! din dou! registre de 32 de bi#i: registrul indicator de instruc#iune "i registrul indicatorilor de stare. Procesorul folose"te registrul indicator de instruc#iune ca s! memoreze adresa urm!toarei instruc#iuni ce va intra n ciclul de execu#ie. Cteodat!, acest registru este denumit registru contor de program. Registrul indicator de instruc#iune poate fi folosit ca registru de 16 (IP) sau 32 de bi#i (EIP), n func#ie de m!rimea adreselor. Cnd o instruc#iune este extras! din memorie, registrul indicator de instruc#iune este reini#ializat automat cu adresa urm!toarei instruc#iuni. Registrul poate fi modificat "i de o instruc#iune care transfer! controlul execu#iei la alt! loca#ie n program.

31
Valorile de de 0 !i 1 n gri sunte rezervate Intel.

16 15

0 0 0 0 0 0 0 0 0 0 ID VIP VIF AC VM RF 0 NT IOPL OF DF IF TF SF ZF 0 AF 0 PF 1 CF

Indicatori de stare CF = Carry Flag PF = Parity Flag AF = Auxiliary Carry Flag ZF = Zero Flag SF = Sign Flag OF = Overflow Flag

Indicatori de control DF = Direction Flag

Indicatori de sistem TF = Trap Flag IF = Interrupt Flag IOPL = I/O Privilege Level NT = Nested Task RF = Resume Flag VM = Virtual 8086 Mode AC = Alignment Check VIF = Virtual Interrupt Flag VIP = Virtual Interrrupt Pending ID = ID flag

Registrul indicatorilor de stare poate fi considerat ca fiind de 16 (FLAGS) sau 32 de bi!i (EFLAGS). Registrul FLAGS este folosit atunci cnd se execut" cod compatibil 8086. Registrul EFLAGS con!ine 6 indicatori de stare, 1 indicator de control #i 10 indicatori de sistem. Bi!ii acestui registru pot fi seta!i (1 logic) sau nu (0 logic). Setul de instruc!iuni IA-32 con!ine instruc!iuni capabile s" seteze sau s" #tearg" valoarea unora dintre indicatori. De exemplu, instruc!iunea clc #terge valoarea indicatorului de transport (Carry Flag), iar instruc!iunea stc o seteaz". Cei 6 indicatori de stare semnalizeaz" un eveniment specific ap"rut n urma execu!iei ultimei instruc!iuni aritmetice sau logice. De exemplu, dac" o instruc!iune de sc"dere produce rezultat zero, procesorul seteaz" automat indicatorul de zero, ZF (Zero Flag ia valoarea 1). Vom discuta n detaliu indicatorii de stare atunci cnd vom prezenta instruc!iunile aritmetice #i logice. Aici mai amintim faptul c" indicatorul de direc!ie (DF) se diferen!iaz" de ceilal!i indicatori prezen!i n registrul EFLAGS. Prin intermediul lui, programatorul poate specifica procesorului cum trebuie s" judece anumite instruc!iuni; a#adar, programatorul semnalizeaz" ceva procesorului #i nu invers. Rolul acestui indicator va fi discutat n detaliu n sec!iunea dedicat" instruc!iunilor de operare pe #iruri. Cei zece indicatori de sistem controleaz" modul n care opereaz" procesorul. De exemplu, setarea indicatorului de mod virtual, VM, for!eaz" procesorul s" emuleze un 8086, iar posibilitatea set"rii #i #tergerii indicatorului ID indic" faptul c" procesorul poate furniza programelor informa!ie cu privire la produc"torul procesorului, familia din care face parte, modelul, etc., prin intermediul instruc!iunii CPUID.

2.2.5. ntreruperile
Dispozitivele de intrare/ie#ire pun la dispozi!ia sistemelor de calcul mijloacele prin care acestea pot interac!iona cu exteriorul. Un dispozitiv poate fi un dispozitiv de intrare (de ex., tastatura, mouse-ul), un dispozitv de ie#ire (de ex., imprimanta, monitorul), sau un dispozitiv de intrare #i ie#ire (de ex., discul). Calculatoarele folosesc dispozitive de intrare/ie#ire, numite #i periferice, din dou" motive principale: s" comunice cu exteriorul #i s" stocheze date. Dispozitive ca imprimanta, tastatura, modemurile, pl"cile de re!ea sunt folosite n comunica!ia cu exteriorul, iar discul la stocarea informa!iei. De#i scopurile sunt diferite, sistemul comunic" cu aceste dispozitive prin intermediul aceleia#i magistrale de sistem. Dispozitivele de intrare/ie#ire nu sunt conectate direct la magistrala de sistem; comunica!ia dintre sistem #i periferic este gestionat" de un controler de intrare/ie#ire. Procesoarele acceseaz" registrele interne ale controlerului de intrare/ie#ire prin porturile de intrare/ie#ire. Un port I/O reprezint" adresa unui registru din

controlerul I/O. Procesoarele pot mapa porturile I/O la adrese de memorie, mecanism numit memory-mapped I/O, sau pot folosi un spa!iu de adrese I/O separat de spa!iul adreselor de memorie, tehnic" numit" isolated I/O.n primul caz, scrierea la un port I/O este similar" cu scrierea ntr-o loca!ie de memorie. n al doilea caz, spa!iul de adrese I/O este accesat cu ajutorul unor instruc!iuni speciale, numite instruc!iuni de intrare/ie#ire. Setul de instruc!iuni IA-32 furnizeaz" dou" astfel de instruc!iuni: IN #i OUT. Instruc!iunea IN este folosit" pentru citirea portului I/O, iar instruc!iunea OUT pentru scrierea portului I/O. Procesoarele pot folosi simultan ambele strategii. De exemplu, imprimanta #i tastatura sunt mapate n spa!iul de adrese I/O folosind strategia isolated I/O, iar monitorul este mapat la un set de adrese de memorie folosind strategia memorymapped I/O. Arhitectura IA-32 pune la dispozi!ie un spa!iu de adrese I/O de 64 kB. Acest spa!iu de adrese poate fi folosit pentru porturi I/O de 8, 16 #i 32 de bi!i. Totu#i, combina!ia nu poate dep"#i 64 kB. Sistemele de operare pun la dispozi!ia aplica!iilor #i utilizatorilor rutine (secven!e de instruc!iuni) de acces la dispozitivele I/O. Sistemele Linux #i Windows implementeaz" un set astfel de rutine. Pe lng" acestea, se pot folosi #i rutine prezente n BIOS. BIOS-ul este un soft rezident ntro memorie ROM aflat" pe placa de baz" #i const" dintr-o colec!ie de rutine care controleaz" dispozitivele I/O.

2.3. Exerci!ii
2.1. Care este diferen!a ntre microarhitectura #i arhitectura procesorului? 2.2. Descrie!i ciclul de execu!ie. 2.3. Ce rol are memoria principal n structura de ansamblu a unui calculator? 2.4. Ce nseamn" arhitectur" von Neumann? Care este problema principal" a acesteia? 2.5. Care processor este ultimul reprezentant al arhitecturii IA-32? 2.6. Dac" un procesor poate folosi o magistral" de adrese de 64 de linii, care este m"rimea spa!iului de memorie adresabil? Exprima!i adresa ultimei loca!ii de memorie n hexazecimal. 2.7. Care sunt registrele de uz general la procesoarele Intel de 32 de bi!i?

3. LIMBAJUL DE ASAMBLARE

Acest capitol prezint! nivelurile la care utilizatorul poate interac"iona cu sistemul de calcul #i define$te limbajul de asamblare n contextul acestei interac"iuni. Totodat! se explic! pe ce nivel se reg!se#te limbajul de asamblare n ierarhia limbajelor de programare. Deoarece reiese c! limbajul de asamblare reprezint! o etap! parcurs! de orice compilator n procesul de generare a codului obiect, prezent!m procesul de compilare a unui program scris n C. Capitolul se ncheie cu o descriere succint! a avantajelor #i dezavantajelor asociate cu programarea n diferite limbaje de programare. Aceast! sec"iune are rolul s! ofere motiva"ia necesar! studierii limbajului de asamblare #i s! demonstreze avantajele acestuia.
Nivel 5

Aplica!ie Cre"te nivelul de abstractizare


Nivel 4

Limbaj de nivel nalt (C, C++, Java)


Nivel 3

Indepentent de sistem

Limbaj de asamblare
Nivel 2

Dependent de sistem Limbaj ma"in#

Nivel 1

Apeluri de sistem
Nivel 0

Hardware

Figura 3.1 Nivelurile de interac"iune cu sistemul de calcul

Figura 3.1 prezint! nivelurile la care utilizatorul poate interac"iona cu un sistem de calcul. La nivelul programelor de aplica"ie utilizatorul interac"ioneaz! cu sistemul de calcul prin interfa"a pus! la dispozi"ie de o anumit! aplica"ie, fie aceasta un editor de text, un joc, etc.. Utilizatorul nu trebuie s! cunoasc! n detaliu cum func"ioneaz! sistemul, problema se reduce numai la #tiin"a de a folosi aplica"ia. Presupunnd c! este vorba de un editor de text, tot ce trebuie s! st!pneasc! utilizatorul, din punct de vedere tehnic, sunt combina"iile de taste care introduc, #terg, copiaz! text, etc.. Nivelul urm!tor presupune cunoa#terea unui limbaj de programare de nivel nalt, precum C sau Java. Un utilizator care interac"ioneaz! cu sistemul de calcul la acest nivel trebuie s! de"in! cuno#tin"e detaliate cu privire la dezvoltarea software. Ace#ti utilizatori sunt programatori de aplica"ii, care cunosc limbajul de programare folosit la elaborarea aplica"iei #i modul n care este ea realizat!. n schimb, nu este necesar s! cunoasc! n detaliu cum func"ioneaz! sistemul (doar dac! nu cumva sunt implica"i n dezvoltarea de drivere pentru dispozitive hardware sau de compilatoare, asambloare, etc.). Ambele niveluri, 4 #i 5, sunt independente de sistem, adic! de tipul particular de procesor folosit. O aplica"ie scris! n limbaj de nivel nalt poate fi rulat! de sisteme cu arhitecturi diferite f!r! modific!ri suplimentare aduse codul surs!. Aceast! caracteristic! a aplica"iei se nume#te portabilitate, #i tot ce trebuie f!cut este ca programul s! fie recompilat cu un compilator nativ sistemului respectiv. n fapt, de aici provine #i denumirea de limbaj de nivel nalt - denot! capacitatea limbajului de programare de a oferi o abstractizare a arhitecturii sistemului de calcul. Unele limbaje pot ascunde complet detaliile specifice unei anumite arhitecturi: modul de adresare a memoriei, alocarea/dealocarea memoriei, lucrul cu dispozitivele externe, etc.. n contrast, dezvoltarea de programe sub nivelul 4 este dependent! de sistem. Limbajul de asamblare se nume#te #i limbaj de programare de nivel sc!zut deoarece necesit! cuno#tin"e detaliate cu privire la organizarea intern! a sistemului: arhitectura procesorului, organizarea memoriei, #.a.m.d. Instruc"iunile limbajului de asamblare sunt native procesorului. Un program scris n limbaj de asamblare pentru procesoare Intel nu poate fi executat de un procesor ARM sau SPARC. Limbajul ma#in! este o rud! apropiat! a limbajului de asamblare. Tipic, este o coresponden"! de unu la unu ntre instruc"iunile limbajului de asamblare #i instruc"iunile ma#in!. Procesorul n"elege numai limbajul ma#in!, ale c!rui instruc"iuni consist! din #iruri de 0 #i 1. Vom vedea c!, de#i limbajul de asamblare este considerat de nivel sc!zut, programarea n asamblare nu expune toate m!runtaiele sistemului. Unele detalii sunt ascunse de sistemul de operare. De exemplu, citirea datelor de la tastatur! sau afi#area lor la monitor se face prin intermediul unor func"ii puse la dispozi"ie de sistemul de operare.

Nivelul hardware execut! instruc"iunile limbajului ma#in!.

3.1. Tipuri de limbaje de programare


3.1.1. Limbajul ma!in"
Fiecare familie de procesoare (x86, SPARC, Power, MIPS) are propriul s!u limbaj, denumit cod ma#in!, exprimat n idiom binar. Acest limbaj este definit n etapa de proiectare #i cuprinde totalitatea instruc"iunilor pe care le poate executa un procesor. Instruc"iunea binar! definit! de produc!tor n procesul de realizare a procesorului se nume#te intruc!iune n cod ma"in# sau instruc!iune ma"in#. Tipuri diferite de procesor con"in tipuri diferite de instruc"iuni ma#in!. Procesoarele sunt clasificate frecvent pe baza num!rului #i tipului de instruc"iuni ma#in! cunoscute. Un program n cod ma#in! este denumit #i cod obiect. Figura 3.2 arat! un fragment de cod ma#in! scris pentru un procesor cu arhitectur! IA-32. S! presupunem c! n memoria principal!, reprezentat! ca #ir liniar de octe"i, avem secven"a de bi"i prezentat! n Figura 3.2.
10110000 10001001 11000010 10001001 11010001 10001001 11001000 7 0

Figura 3.2 Instruc!iuni ma"in# n memoria principal#

n timpul rul!rii, procesorul cite#te instruc"iuni ma#in! din memorie. Fiecare instruc"iune ma#in! poate con"ine unul sau mai mul"i octe"i de informa"ie. Ace#tia instruiesc procesorul s! efectueze un proces specific: opera"ii aritmetice #i logice, transferul datelor ntre memorie #i procesor, etc.. Datele prelucrate de instruc"iunile ma#in! sunt de asemenea stocate n memorie, iar octe"ii instruc"iunilor ma#in! nu sunt diferi"i de octe"ii datelor utilizate de instruc"iune. Bi"ii de date ilustra"i n Figura 3.3 sunt aceea#i cu bi"ii de cod prezenta"i n Figura 3.2, numai semnifica"ia lor este diferit!. Pentru a diferen"ia datele de instruc"iuni sunt utiliza"i indicatori (pointeri) speciali care ajut! procesorul s! diferen"ieze zona de memorie care stocheaz! date de zona de memorie care stocheaz! instruc"iuni.

10110000 10001001 11000010 10001001 11010001 10001001 11001000 7 0

Figura 3.3 Secven!" de date n memoria principal"

Indicatorul de instruc!iune ajut! procesorul s! diferen"ieze instruc"iunile deja executate de cele care urmeaz! s! fie procesate. Evident, exist! instruc"iuni (de ex., instruc"iunea de salt la o anumit! adres! din program) capabile s! schimbe loca"ia memorat! n indicatorul de instruc"iune. n mod similar, exist! un indicator de date, care adreseaz! zona de memorie n care sunt stocate datele, #i un indicator de stiv", care adreseaz! zona de memorie destinat! stivei. Fiecare instruc"iune ma#in! trebuie s! con"in! cel pu"in un octet denumit opcode (operation code ), #i unul sau mai mul"i octe"i de informa"ie. Opcode-ul, sau codul de opera#ie, define#te opera"ia ce trebuie realizat! de procesor. Fiecare familie de procesoare are predefinit propriul set de coduri de opera!ie care define#te toate func"iile disponibile. S! traducem ce reprezint! pentru un procesor 80386 codul din zona de memorie din exemplul nostru: primii doi octe"i, 1 0 0 0 1 0 0 1 1 1 0 0 1 0 0 0 (citi"i normal, de la stnga la dreapta), for"eaz! procesorul s! copieze n registrul EAX valoarea din registrul ECX. urm!torii doi octe"i, 1 0 0 0 1 0 0 1 1 1 0 1 0 0 0 1, for"eaz! procesorul s! copieze valoarea lui EDX n ECX. urm!torii doi octe"i copiaz! valoarea din EAX n EDX. Toate aceste opera"ii sunt deduse dac! #tim c! opcode-ul pentru opera"iunea de copiere dintr-un registru n altul este 1 0 0 0 1 0 0 1 1 1, iar codul pentru registrele EAX, ECX, EDX, este 0 0 0, 0 0 1, respectiv 0 1 0. Reprezentarea hexazecimal! a codurilor instruc"iune Programul scris n limbaj ma#in! devine mai u#or de n"eles dac! se recurge la reprezentarea codurilor binare n hexazecimal. Se ob"ine un a#a numit hexdump (reprezentare hexazecimal!) al programului.
B0 89

C2 89 D1 89 C8 7 0

Figura 3.4 Reprezentarea instruc!iunilor ma"in# n hexazecimal

3.1.2. Limbajul de asamblare


Codul ma!in" este limbajul n#eles de procesor. Limbajul de asamblare poate fi definit ca fiind limbajul ce permite programatorului s" aib" control asupra codului ma!in". Limbajul de asamblare specific# cod ma!in". Instruc#iunile sale sunt de fapt reprezent"ri simbolice ale instruc#iunilor ma!in". Aceste coduri simbolice sunt denumite mnemonici. 1 0 0 0 1 0 0 1 1 1 este definit simbolic prin cuvntul MOV, care prime!te ca argumente dou" registre. Mnemonica MOV nseamn" efectuarea unei copieri. Deoarece sintaxa complet" este 1 0 0 0 1 0 0 1 1 1 S S S D D D, unde S S S este codul pentru registrul surs", iar D D D este codul pentru registrul destina#ie, 1 0 0 0 1 0 0 1 1 1 0 0 0 0 0 1 nseamn" MOV ECX,EAX. Secven#a din exemplul nostru scris" n limbaj de asamblare arat" astfel: mov eax,ecx mov ecx,edx mov edx,eax Procesul prin care se coverte!te un program din limbaj de asamblare n cod ma!in" se nume!te asamblare, iar unealta software care converte!te un program scris n limbaj de asamblare n limbaj ma!in" se nume!te asamblor. Alternativ, procesul de conversie a codului ma!in" n limbaj de asamblare se nume!te dezasamblare, iar programul care realizeaz" acest proces se nume!te dezasamblor. Limbajul de asamblare este proiectat pentru o anumit" familie de procesoare. Limbajul de asamblare destinat unui procesor Intel x86 are alt" mnemonic" fa#" de limbajul de asamblare destinat unui procesor SPARC, de exemplu.

3.1.3. Limbaje de nivel nalt


Putem programa n limbaj ma!in", dar este foarte dificil. Chiar !i cel mai simplu program oblig" programatorul s" specifice o mul#ime de coduri de opera!ie

!i octe"i de date. n plus, programul ar fi rulat numai de tipul de procesor c#ruia i-a fost dedicat programul respectiv. Limbajele de nivel nalt, de ex. C, au fost concepute pentru a nu "ine cont de caracteristicile tehnice specifice unui procesor. Instruc"iunile limbajului de nivel nalt pot fi convertite n cod obiect pentru fiecare familie de procesoare n parte. Totu!i, codul scris n limbaj de nivel nalt trebuie tradus printr-un mecanism sau altul n formatul limbajului ma!in#. Din acest punct de vedere, programele scrise n limbaj de nivel nalt pot fi clasificate n trei mari categorii: compilate interpretate hibride Programe compilate Majoritatea aplica"iilor sunt create n limbaje compilate. Programatorul scrie programul folosind sintaxa specific# unui limbaj de nivel nalt. Fi!ierul care con"ine programul n format text se nume!te fi!ier surs" sau cod surs". Acest text este convertit n cod ma!in# specific unui tip de procesor. De obicei, ceea ce se nume!te comun compilare este un proces n doi pa!i: conversia codului surs" n cod obiect. Programul care realizeaz# acest pas se nume!te compilator. editarea leg#turilor ntre diferite module obiect n vederea ob"inerii executabilului. Programul care efectueaz# acest pas se nume!te editor de leg"turi, sau linker.
Compilator Fi"ier surs! Fi"ier obiect Editor de leg!turi !"#$%&'&()$*+&(,# /&'&()$(0(,1#2+&"

-&+"&*#(,&$.($%&'&()($*+&(,#

Figura 3.5 Procesul de compilare

Pa!ii procesului de compilare convertesc instruc"iunile limbajului de nivel nalt n instruc"iuni ma!in#. Fiec#rei linii de cod scrise n limbaj de nivel nalt i corespunde una sau mai multe instruc"iuni ma!in# specifice tipului de procesor pe care va rula aplica"ia. De exemplu, codul

int main() { int i=1; exit (0); } este compilat n urm!toarele instruc"iuni ma#in!: 55 89 83 C7 83 6A E8 E5 EC 45 EC 00 D1

08 FC 01 00 00 00 0C FE FF FF

Acest pas produce un fi#ier intermediar, numit fi!ier obiect. Fi#ierul obiect con"ine cod obiect ntr-un anumit format n"eles de sistemul de operare, de#i nc! nu poate fi rulat de acesta. Codul obiect con"ine numai datele #i instruc"iunile ma#in! ale func"iilor definite n program. Programul poate avea ns! nevoie de componente aflate n alte fi#iere obiect (de ex., func"ia exit). Pentru ad!ugarea acestor componente este necesar nc! un pas. Dup! transformarea codului surs! n cod obiect, un editor de leg!turi leag! fi#ierul obiect al programului de alte fi#iere obiect necesare acestuia #i creaz! fi!ierul executabil. Rezultatul editorului de leg!turi este un executabil ce poate fi rulat numai de tipul de sistem de operare pe care a fost compilat programul. Din nefericire, fiecare sistem de operare folose#te un format de fi#ier executabil (sau obiect) diferit. O aplica"ie compilat! pe un sistem de operare tip Windows nu va rula pe Linux, sau viceversa. Fi#ierele obiect care con"in func"ii foarte uzuale pot fi combinate ntr-un singur fi#ier, numit bibliotec". Bibliotecile pot fi legate de aplica"ii n timpul compil!rii (biblioteci statice) sau n timpul rul!rii aplica"iei (biblioteci partajate). Bibliotecile statice sunt acele biblioteci ale c!ror module obiect (componente) sunt incluse n fi#ierul executabil n momentul edit!rii de leg!turi. n cazul bibliotecilor partajate, modulele obiect sunt adresate n momentul lans!rii n execu"ie sau n momentul rul!rii. Programe interpretate Spre deosebire de programul compilat, care ruleaz! prin for"e proprii, programul interpretat este citit #i rulat de un program separat, numit interpretor. De-a lungul prelucr!rii aplica"iei, interpretorul cite#te #i decodific! (interpreteaz!) fiecare instruc"iune n parte. Conversia programului n instruc"iuni ma#in! specifice

procesorului este realizat! de interpretor n timpul rul!rii programului. Evident, punctul sensibil al acestor tipuri de programe este viteza. n loc ca aplica"ia s! fie compilat! direct n cod ma#in!, un program intermediar cite#te fiecare linie de cod surs! #i proceseaz! opera"iile respective. La timpul de execu"ie se adaug! timpul de care are nevoie interpretorul s! citeasc! #i s! decodifice instruc"iunile aplica"iei. Avantajul este convenien"a. Pentru programele compilate, la fiecare modificare a programului, fi#ierul surs! trebuie recompilat. La programele interpretate, fi#ierul surs! poate fi modificat rapid #i u#or chiar n timp ce programul ruleaz!. n plus, programul interpretor determin! automat func"iile adi"ionale necesare codului principal (codul obiect al sursei ini"iale). Programe hibride Programele hibride combin! caracteristicile programelor compilate cu versatilitatea programelor interpretate. Un exemplu perfect este limbajul Java. Java este compilat n a#a numitul cod octet (byte code). Codul octet este similar codului ma#in! rulat de procesor, dar el nsu#i nu este compatibil cu nicio familie de procesoare. n schimb, codul octet Java trebuie interpretat de o ma#in! virtual! (JVM - Java Virtual Machine) care ruleaz! separat. Codul octet Java este portabil, n sensul c! poate fi rulat de c!tre orice JVM, pe orice tip de sistem de operare sau procesor. Implement!rile ma#inilor virtuale Java pot diferi de la platform! la platform!, dar toate pot interpreta acela#i cod octet Java f!r! a fi necesar! recompilarea sursei originare.

3.2. Procesul de compilare


n concluzie, un program este compus din una sau mai multe instruc"iuni ce descriu un proces, sau un set de procese, realizat de calculator, iar codul surs! este o secven"! de instruc"iuni #i/sau declara"ii scrise ntr-un limbaj de programare lizibil. Codul surs! poate fi convertit n cod executabil de c!tre un compilator sau poate fi executat n timpul rul!rii cu ajutorul unui interpretor. Executabilul este un fi#ier al c!rui con"inut este interpretat drept program de c!tre sistemul de operare. De#i un fi#ier sub form! de cod surs! poate fi un executabil (acest tip de fi#ier se nume#te script), majoritatea fi#ierelor executabile con"in reprezentarea binar! a instruc"iunilor ma#in! (de aceea se mai nume#te #i binar) specifice unui tip de procesor. Compilatorul este un program (sau un set de programe) care translateaz! textul scris n limbaj de programare de nivel nalt n limbaj ma#in!. Programul originar este numit cod surs!, iar programul ob"inut este numit cod obiect. Portabilitatea sistemului de operare Unix a fost n parte consecin"a faptului

c! n 1973 a fost rescris ntr-un limbaj de nivel nalt, "i anume, C. GCC (GNU C Compiler), prima versiune nonproprietar! de compilator C, a fost scris de Richard Stallman n 1989 pentru proiectul GNU. Numele s!u, GNU, care provine de la GNU's Not Unix, proclam! independen#a de restric#iile impuse de drepturile de copiere. Compilatorul GNU C este foarte folosit, nu numai deoarece este gratuit, dar "i pentru c! a impus un standard n ceea ce prive"te utilitatea. GCC translateaz! un program scris n C n cod ma"in!. Realizeaz! n acela"i timp cei doi pa"i ai procesului de compilare, adic! compilarea propriu zis! "i editarea de leg!turi. Rezultatul este un executabil ce poate fi stocat n memoria calculatorului "i rulat de procesor. Compilatorul GNU C lucreaz! n etape, a"a cum se poate observa din Figura 3.6.
Cod surs!
prog.c Preprocesare

Unitate de translatare
prog.i

Cod n asamblare
prog.s

Cod obiect
prog.o

Fi"ier executabil
a.out

Compilare

Asamblare

Editarea de leg!turi

gcc -E gcc -S gcc -c gcc

Figura 3.6 Etapele procesului de compilare

Comanda gcc prog.c parcurge toate etapele necesare translat!rii codului surs! "i genereaz! un executabil, numit a.out, capabil s! ruleze exclusiv pe sisteme Linux. Pentru a stopa execu#ia procesului la un anumit moment, putem folosi op#iunile din reprezentarea de mai sus. Pentru exemplificare, consider!m programul C de mai jos. Nu este necesar s! cunoa"te#i limbajul C. Ne intereseaz! numai s! n#elegem efectul etapelor parcurse de compilator. /* prog.c */ #include <stdio.h> int main() { int var1 = 40; int var2 = 50; int var3; var3 = var1; var1 = var2; var2 = var3;

return 0; }

3.2.1. Preprocesarea
Etapa de preprocesare presupune nlocuirea/expandarea directivelor de preprocesare din fi!ierul surs". Preprocesorul utilizat de GCC n aceast" etap" este un program de sine st"t"tor numit CPP. Preprocesorul CPP analizeaz" macrourile (cuvintele din surs" care ncep cu caracterul #) !i le expandeaz". n cazul nostru, directiva #include copiaz" con#inutul fi!ierului stdio.h n fi!ierul surs" prog.c. Astfel, rezultatul preproces"rii este tot un program surs", dar care nu mai include directivele preprocesor, ci rezultatul acestora. gcc -E prog.c -o prog.i sau cpp prog.c prog.i

Din aceste dou" variante, prima permite rularea preprocesorului cu toate op#iunile implicite (dezirabil"). Fi!ierul rezultat .i este generat rar, dar poate fi interesant de v"zut cum sunt expandate macrourile complexe. Op#iunea -o specific" numele fi!ierul de ie!ire.

3.2.2. Compilarea
Compilarea este etapa n care din fi!ierul preprocesat se ob#ine un fi!ier n limbaj de asamblare. Rezultatul compil"rii este un fi!ier lizibil, cu sufixul .s, con#innd programul scris n limbaj de asamblare. Compilatorul propriu-zis folosit de GCC este CC. CC este un program complex, deoarece nu exist" o coresponden#" unu la unu ntre instruc#iunile C !i instruc#iunile n asamblare. n plus, poate optimiza codul n func#ie de cerin#e precum genereaz" varianta mai rapid" sau genereaz" varianta mai compact", rezultnd secven#e diferite de instruc#iuni n asamblare. Totu!i, niciun compilator nu este infailibil, optimiz"ri complexe nu pot fi realizate dect de un programator n asamblare. gcc O0 -S prog.c -o prog.s m32 sau cc -S prog.c -o prog.s

Red!m integral rezultatul acestei comenzi: .file "prog.c" .text .globl main .type main, @function main: pushl %ebp movl %esp, %ebp subl $16, %esp movl $40, -4(%ebp) movl $50, -8(%ebp) movl -4(%ebp), %eax movl %eax, -12(%ebp) movl -8(%ebp), %eax movl %eax, -4(%ebp) movl -12(%ebp), %eax movl %eax, -8(%ebp) movl $0, %eax leave ret .size main, .-main .ident "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2" .section .note.GNU-stack,"",@progbits A"a arat! n asamblare programul C din exemplul nostru. Totu"i, el nu se reg!se"te n forma studiat! de noi n aceast! carte. De"i am fi putut genera cu u"urin#! varianta dorit! (gcc O0 -S prog.c -o prog.s m32 mintel)am preferat s! folosim setarea implicit!. Acest lucru ne permite s! demonstr!m faptul c! limbajul de asamblare nu este un limbaj de sine st!t!tor, ci mai degrab! o familie de limbaje. Limbajul de asamblare pentru arhitecturi Intel nu are o singur! sintax!. n fapt, sunt dou! mari familii: sintaxa Intel "i sintaxa AT&T. Toate sistemele de operare derivate din Unix sau nrudite folosesc nativ sintaxa AT&T. Toate sistemele cu origini n DOS "i Windows folosesc sintaxa Intel. Sintaxa Intel este forma limbajului de asamblare specificat! n documenta#ia Intel. Cele dou! sintaxe nu sunt foarte diferite, folosirea uneia sau alteia fiind mai degrab! o problem! de gust. Pe un sistem de operare Linux sintaxa implicit! este AT&T, dar putem folosi oricare din cele dou!. Dispunem "i de un utilitar capabil s! transforme un program dintr-o sintax! n alta sau dintr-un idiom specific unui asamblor n altul (deoarece

asambloarele ns!"i introduc modific!ri de sintax!). intel2gas -g prog.s -o intel.asm Rezultat: ;FILE "prog.c" SECTION .text GLOBAL main GLOBAL main:function main: push ebp mov ebp,esp sub esp,16 mov dword [ebp-4],40 mov dword [ebp-8],50 mov eax, [ebp-4] mov [ebp-12],eax mov eax, [ebp-8] mov [ebp-4],eax mov eax, [ebp-12] mov [ebp-8],eax mov eax,0 leave ret GLOBAL main:function (.-main) ;IDENT "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2"

3.2.3. Asamblarea
Etapa de asamblare translateaz! codul scris n limbaj de asamblare n cod binar. Asamblorul utilizat de GCC se nume"te AS. AS este un asamblor care cunoa"te sintaxa AT&T. Rezultatul asambl!rii este un fi"ier obiect. Fi"ierul obiect reprezint! un amestec de cod ma"in! "i alte informa#ii necesare n faza de editare de leg!turi; con#ine o list! de simboluri (de ex., nume de variabile declarate, dar nedefinite), locurile n care acestea apar n program, informa#ii de relocare (specific! adresele de memorie la care vor fi plasate datele "i instruc#iunile programului n etapa de editare de leg!turi). Nu n ultimul rnd, fi"ierele obiect pot con#ine informa#ie de depanare, inclus! n corpul lor cu op#iunea -g. Aceast! op#iune este necesar! dac! se inten#ioneaz! depanarea programului.

gcc -g -c prog.s -o prog.o sau as -g prog.s -o prog.o Fi!ierul obiect prog.o este generat ntr-un format binar specific platformelor Linux, numit ELF (Executable and Linkable Format). Acesta descrie modul n care trebuie structurat binarul unui program astfel nct s" poat" fi executat de un sistem de operare Linux. Sistemele de operare Windows folosesc un format diferit (PE Portable Executable). De aceea, o aplica#ie compilat" pentru Linux nu ruleaz" pe Windows, sau invers. n Linux putem dezasambla con#inutul unui fi!ier binar (obiect sau executabil) cu ajutorul unui utilitar ca objdump. Dezasamblarea nseamn" recuperarea mnemonicilor limbajului de asamblare pornind de la codul ma!in"; este opera#ia invers" asambl"rii. objdump -d -M intel prog prog.o: file format elf32-i386

Disassembly of section .text: 08048394 <main>: 8048394: 55 8048395: 89 e5 8048397: 83 ec 10 804839a: c7 45 fc 28 00 00 00 80483a1: c7 45 f8 32 00 00 00 80483a8: 8b 45 fc 80483ab: 89 45 f4 80483ae: 8b 45 f8 80483b1: 89 45 fc 80483b4: 8b 45 f4 80483b7: 89 45 f8 80483ba: b8 00 00 00 00 80483bf: c9 push ebp mov ebp,esp sub esp,0x10 mov DWORD PTR [ebp-0x4],0x28 mov DWORD PTR [ebp-0x8],0x32 mov eax,DWORD PTR [ebp-0x4] mov DWORD PTR [ebp-0xc],eax mov eax,DWORD PTR [ebp-0x8] mov DWORD PTR [ebp-0x4],eax mov eax,DWORD PTR [ebp-0xc] mov DWORD PTR [ebp-0x8],eax mov eax,0x0 leave

Se observ" clar diferen#a dintre limbajul de asamblare !i limbajul ma!in". Limbajul ma!in", n format hexazecimal, este reprezentat cu bold, iar n dreapta este programul n limbaj de asamblare (n format Intel). Observa#i mnemonica instruc#iunilor n limbaj de asamblare - abrevieri apropiate limbajului uman (NOP no operation, MOV move, INT interrupt). Din listing reiese echivalentul n cod

ma!in" al instruc#iunii NOP este 90H, !irul binar 1001 0000. n concluzie, limbajul de asamblare este un limbaj mnemonic - un cod format din una sau mai multe litere ce reprezint" un num"r, abrevieri, cuvinte care u!ureaz" memorarea instruc#iunilor complexe !i fac programarea mai u!oar". Programarea n cod ma!in" este posibil", dar predispus" la erori !i mare consumatoare de timp. Mnemonica u!ureaz" sarcina programatorului, n schimb, un program scris n limbaj de asamblare trebuie convertit n cod ma!in". Acest lucru este realizat de asamblor. Asamblorul genereaz" translat"ri unu la unu ntre cuvinte mnemonice !i instruc#iuni ma!in". A nu se confunda asamblorul cu compilatorul. Acesta din urm" este folosit la conversia n cod ma!in" a unui program de nivel nalt, conversia efectundu-se n bloc. De asemenea, convertoarele ce translateaz" linie cu linie se numesc interpretoare.

3.2.4. Editarea leg!turilor


Un fi!ier obiect este asociat unui singur fi!ier surs". Fi!ierul obiect con#ine datele !i codul func#iilor proprii unui program. Datele !i func#iile poart" numele generic de simboluri. Simbolurile externe modulului (adic" func#iile sau datele nedefinite local, prezente n alte fi!iere obiect) sunt marcate ca nedefinite. Aceast" etap" este folosit" la rezolvarea simbolurilor nedefinite (opera#ie denumit" !i rezolvarea simbolurilor) !i la unificarea ntr-un singur fi!ier a mai multor fi!iere obiect sau biblioteci. Rezultatul este un fi!ier binar cu un format apropiat de fi!ierul obiect. n Linux este chiar acela!i format, ELF. Editarea de leg"turi se face cu ajutorul programului LD, dar care, n cazul programelor C, e preferabil s" nu fie apelat separat (programul poate include numeroase biblioteci !i lista fi!ierelor obiect poate fi foarte mare). n cazul programelor scrise n asamblare va fi folosit de fiecare dat".

3.2.5. Formatul fi"ierelor executabile


Un fi!ier executabil este un fi!ier binar ob#inut dintr-un set de fi!iere obiect !i biblioteci n urma opera#iei de editare de leg"turi. Un fi!ier executabil con#ine codul ma!in" necesar ndeplinirii opera#iilor, dar !i antete !i sec#iuni de formatare auxiliare care specific" organizarea executabilului n memorie, modul n care se folose!te codul, zonele de memorie alocate pentru acesta !i date, etc.. Un fi!ier executabil are, a!adar, un format bine definit !i totodat" strns legat de sistemul de operare. Sistemul de operare este responsabil cu interpretarea fi!ierului executabil !i generarea unui proces pe baza acestuia.

obiect sunt:

Re!inem c" formatul de fi#ier executabil este acela#i #i pentru fi#ierele sau bibliotecile partajate. Exemple de formate de fi#iere obiect/executabile a.out primul format folosit de sistemele Unix; ELF folosit n sistemele Unix; PE formatul implicit pe sistemele Windows; Mach-O formatul implicit pe Mac OS X.

3.3. Avantajele limbajului de asamblare


Avantajele limbajelor de nivel nalt: Permit dezvoltarea rapid" a programelor. Limbajele de nivel nalt ofer" func!ii, proceduri, structuri de date predefinite care faciliteaz" dezvoltarea rapid" a programelor. n compara!ie cu echivalentele lor n limbaj de asamblare, programele n limbaj de nivel nalt au num"r relativ mic de linii de cod #i sunt u#or de scris. Programele sunt u#or de revizuit. Programele scrise n limbaj de nivel nalt sunt mai u#or de n!eles #i, dac" respect" anumite metode de programare, u#or de revizuit. Putem ad"uga cod sau corecta erori de programare foarte rapid. Programe portabile. Programele n limbaj de nivel nalt ascund nivelurile dependente de sistem. Ca rezultat, ele pot fi folosite pe diferite arhitecturi de sistem cu pu!ine, sau f"r", modific"ri. n contrast, programele n limbaj de asamblare sunt total dependente de procesor. Avantajele limbajului de asamblare: Eficien!a. Eficien!a se refer" la ct de bun este un program n ndeplinirea unui obiectiv. ntotdeauna cnd judec"m calitatea unui program trebuie s" !inem cont de cantitatea de memorie ocupat" #i de timpul necesar acestuia n ndeplinirea obiectivului pentru care a fost realizat. Programele scrise n limbaj de asamblare, din perspectiva spa!iului de memorie pe care l necesit" fa!" de echivalentele lor n limbaj de nivel nalt, sunt mult mai compacte. De asemenea, timpul necesar execu!iei programului n asamblare este mai mic dect echivalentul s"u de nivel nalt. Acces eficient la hardware-ul sistemului. Limbajele de nivel nalt, prin natura lor, furnizeaz" o imagine abstract" a hardware-ului pe care l utilizeaz". Din aceast" cauz" este aproape imposibil ca programele s" poat" executa sarcini care necesit" acces direct la hardware-ul sistemului. De

exemplu, scrierea unui driver pentru un scaner aproape sigur necesit! cuno"tinte de programare n limbaj de asamblare.

3.4. Exerci!ii
3.1. Ce rela#ie exist! ntre limbajul de asamblare "i limbajul ma"in!? 3.2. De ce este considerat limbajul de asamblare limbaj de nivel sc!zut iar C limbaj de nivel nalt? 3.3. De ce este important! portabilitatea? Dac! dore"ti ca un program s! fie portabil, scrii programul n C sau n limbaj de asamblare? 3.4. Care este diferen#a ntre compilator "i asamblor? 3.5. Ce rol are editorul de leg!turi? 3.7. Ce nseamn! dezasamblare? 3.8. Ce con#ine un fi"ier obiect? 3.9. Care sunt avantajele programelor interpretate?

4. DEZVOLTAREA PROGRAMELOR N LIMBAJ DE ASAMBLARE

Acest capitol prezint! procesul de dezvoltare a programelor n limbaj de asamblare. Prima sec"iune a capitolului descrie elementele constitutive ale programelor n asamblare #i modul n care acestea definesc un cadru de baz! (un arhetip). Se continu! cu definirea no$iunii de proces %i prezentarea structurii acestuia n memoria principal!. Urmeaz! o sec$iune esen$ial! program!rii n limbaj de asamblare, %i anume declararea datelor n memorie. Pe baza tuturor acestor no"iuni sunt prezentate uneltele de dezvoltare necesare cre!rii programelor n limbaj de asamblare.

4.1. Sintaxa limbajului de asamblare


Programele scrise n limbaj de asamblare sunt formate din trei categorii diferite de declara!ii. Prima categorie spune procesorului ce s" fac". Aceste declara!ii sunt numite instruc!iuni executabile sau simplu, instruc$iuni. Fiecare instruc!iune con!ine un cod de opera!ie ce comand" asamblorului generarea unei instruc!iuni n cod ma#in". De obicei, fiecare instruc!iune executabil" genereaz" o instruc!iune n cod ma#in". A doua categorie furnizeaz" asamblorului informa!ii cu privire la diferite aspecte legate de procesul de asamblare. Aceste instruc!iuni se numesc directive de asamblare sau pseudoinstruc$iuni. Pseudoinstruc!iunile nu genereaz" instruc!iuni n cod ma#in". Ultima clas" de declara!ii pune la dispozi!ia programatorului un mecanism de substitu!ie a textului, numit macrodefini$ie (macro). Toate declara!iile limbajului de asamblare sunt scrise linie cu linie n fi#ierul surs" #i toate au acela#i format: [etichet!] opera"ie [operanzi] [;comentariu] n unele declara!ii, cmpurile scrise ntre parantezele p"trate sunt op!ionale. Cmpul etichet! reprezint" un nume (litere, cifre sau caractere

speciale), primul caracter fiind liter! sau caracter special. Fiecare etichet! are asociat! o valoare - adresa relativ! a liniei respective n cadrul segmentului. Cmpul opera!ie reprezint! mnemonica instruc"iunii. Cmpul operanzi define#te operandul sau operanzii asocia"i instruc"iunii, conform sintaxei cerute de codul de opera"ie. Pot fi constante, simboluri sau expresii de simboluri. Cmpul comentariu reprezint! un text oarecare precedat de caracterul punct #i virgul!. Cmpurile unei declara"ii trebuie separate printr-un spa"iu sau un caracter TAB. Num!rul acestor caractere desp!r"itoare r!mne la discre"ia programatorului. De#i asamblorul ignor! tot ce dep!#e#te un singur caracter TAB, utilizarea mai multor caractere de acest fel permite eviden"ierea structurii programului #i d! claritate textului.

4.2. Structura programului


Un program, indiferent de limbajul folosit la scrierea sa, este alc!tuit din dou! p!r"i importante: cod #i date. Codul, tradus n limbaj ma#in!, este plasat ntr-o zon! de memorie numit! segment de cod, iar datele, n func"ie de tipul lor, n zone de memorie numite segmente de date. mp!r"irea programelor scrise n limbaj de nivel nalt n segmente are loc n procesul de compilare. n cazul programelor scrise n limbaj de asamblare segmentele sunt vizibile nc! din fi#ierul surs!. Programatorul n asamblare este obligat s! specifice prin directive speciale nceputul fiec!rui segment folosit de programul s!u #i s! l populeze n consecin"!. Denumirile exacte depind de asamblor. NASM (Netwide Assembler), MASM (Microsoft Assembler), TASM (Borland Turbo Assembler) sunt cteva din cele mai populare asambloare pentru procesoarele Intel. Asamblorul folosit de noi delimiteaz! segmentele prin directivele segment sau section. Pn! n acest capitol am tot repetat faptul c! instruc"iunile #i datele unui program sunt introduse n segmente de memorie separate, a#adar, poate c! nu v! a#tepta"i s! existe mai multe segmente de date. Urm!torul listing prezint! structura tipic! a unui program scris n asamblare: section .rodata ;declar! datele protejate la scriere section .data ;declar! segmentul de date ini"ializate ... section .bss ;declar! segmentul de date neini"ializate

... section .text global _start _start: nop ... ;declar! segmentul de cod ;instruc"iunea No Operation ;instruc"iunile programului

;instruc"iuni care ntrerup rularea programului mov eax,1 mov ebx,0 int 80h
section .rodata date read-only section .data date ini!ializate

section .bss date neini!ializate

section .text cod

Figura 4.1 Structura programului n limbaj de asamblare

Datele programelor sunt de dou! tipuri: ini"ializate #i neini"ializate. Section .data declar! elemente de date ce dispun de valoare ini"ial!; adic! elementele de date c!rora la momentul rezerv!rii spa"iului de memorie li se

specific! "i valoarea ini#ial! (valoarea introdus! n loca#ia de memorie respectiv!). Aceste elemente de date sunt folosite n programele de nivel nalt ca variabile globale sau statice, ini#ializate. //variabil! global! ini"ializat! (n C) int i = 56; void main() { } Variabilele sunt loca#ii de memorie din care se pot scrie "i citi valori. Declararea variabilei presupune rezervarea unui spa#iu de memorie corespunz!tor p!str!rii unei valori. Adresa la care a fost nc!rcat! n memorie variabila este reprezentat! chiar de numele variabilei. Dac! folosim analogia memoriei ca dulap cu sertare, declararea unei variabile ini#ializate nseamn! introducerea unei valori n sertar "i etichetarea acestuia cu numele variabilei. Unele date ini#ializate sunt protejate, n sensul c! nu pot fi rescrise n timpul rul!rii programului. Acestea se g!sesc n sec#iunea declarat! cu section .rodata. Din aceast! categorie fac parte literalii din C. De exemplu, n cazul instruc#iunii printf (Hello World!\n), "irul Hello World\n este stocat n sec#iunea .rodata. n segmentul de date neini#ializate, declarat cu section .bss, rezerv!m un anumit num!r de loca#ii de memorie c!rora le asociem o denumire. Etichet!m sertarul dar nu specific!m nicio valoare. Valoarea este instan#iat! automat cu valori de zero (caracterul NULL). Variabilele neini#ializate se folosesc frecvent la alocarea unor zone de memorie tampon (buffer). //variabil! global! neini"ializat! (n C) int i; void main() { } A"adar, dac! pn! n prezent "tiam c!, n memorie, datele sunt separate de instruc#iuni, acum afl!m c! zona de memorie care con#ine date ini#ializate este separat! de zona de memorie care con#ine date neini#ializate. Listingul dinainte de Figura 4.1 arat! modul tipic de dispunere a segmentelor n program. Segmentul .bss trebuie plasat ntotdeauna nainte de segmentul .text, n timp ce segmentul .data poate fi plasat "i dup!. ns! trebuie s! #inem cont c!, pe lng! func#ionalitate, programul trebuie s! fie "i lizibil. Gruparea tuturor defini#iilor de date la nceputul fi"ierului surs! faciliteaz! n#elegerea programului de c!tre al#i programatori. Section .text declar! zona de memorie ce con#ine instruc#iunile

programului. Ca fapt divers, termenul de program care !i modific" propriul cod (self modifying code) denot" faptul c" programul !i poate modifica singur aceast" sec#iune n timpul rul"rii. Pe de alt" parte, mult mai important de re#inut este faptul c" atunci cnd editorul de leg"turi converte!te fi!ierul surs" n fi!ier executabil, acesta trebuie s" recunoasc" instruc#iunea din segmentul de text de la care sistemul de operare trebuie s" nceap" rularea programului. Programatorul specific" punctul de intrare n program (entry point), declarnd o etichet"11, un identificator. Eticheta _start indic" instruc#iunea de la care trebuie s" nceap" rularea programului. Dac" editorul de leg"turi nu g"se!te aceast" etichet", va produce un mesaj de aten#ionare (warning: cannot find entry symbol _start;) !i va ncerca s" ghiceasc" singur punctul de intrare n program. ns" nu avem nicio garan#ie c" va ghici corect. Nu este obligatoriu ca numele etichetei de intrare n program s! fie _start. n acest caz, n etapa edit!rii de leg!turi trebuie s! preciz!m numele punctului de intrare n program printr-un parametru specific editorului de leg!turi. Programatorul poate s" anun#e punctul de intrare n program al aplica#iei curente !i altor programe. Acest lucru se face cu directiva global. Directiva global indic" etichetele din programul curent accesibile altor programe externe. Segmentul de cod se ncheie cu trei instruc#iuni. Recunoa!tem instruc#iunea MOV, ntlnit" n paragrafele anterioare, !i deducem u!or efectul: registrul EAX ia valoarea 1 iar registrul EBX valoarea 0. Instruc#iunea INT 080H solicit" sistemului de operare s" studieze con#inutul registrelor !i s" execute opera#ia codificat" prin valorile acestora. Codul asociat valorii 1 n registrul EAX cere sistemului de operare Linux s" ntrerup" execu#ia programului. A!a este apelat" func#ia de sistem (func#ii implementate la nivelul sistemului de operare) sys_exit ie!ire din program, n Linux. Vom vorbi pe larg la timpul potrivit, momentan re#inem c" aceste linii permit ntreruperea normal" a procesului. Un program aflat n execu"ie se nume#te proces.

4.3. Structura procesului


Sistemul de operare, n momentul lans"rii programului n execu#ie !i cre"rii procesului, aloc" memorie pentru segmentele de mai sus. Pe lng" aceste zone definite n executabil, n cadrul unui proces se aloc" !i dou" zone de memorie
11

Denumiri introduse de programator n program cu scopul de a nlesni accesul la zonele de memorie specificate de acestea.

foarte importante. Acestea sunt zonele de stiv! "i heap. Pentru a n#elege mai bine structura procesului trebuie s! vorbim pe scurt de modul n care sistemul de operare Linux organizeaz! memoria principal! n modul protejat de adresare.

4.3.1. Memoria virtual! n Linux


n modul protejat, procesoarele Intel x86 sunt procesoare de memorie virtual!. Instruc#iunile nu specific! loca#iile de memorie prin adresele lor fizice, ci prin adrese virtuale (re#inem a"adar c! adresa prezent! n corpul unei instruc#iuni este o adres! virtual!). Adresa virtual! este un num!r alternativ dat unei loca#ii fizice de memorie. Sistemul de operare mapeaz! adresele virtuale la adrese fizice. Prin acest mecanism sistemul de operare poate executa n acela"i timp12 mai multe procese independent unul de altul, astfel nct rularea defectuoas! a unuia s! nu afecteze rularea celorlalte. Niciun proces nu este con"tient de faptul c! ruleaz! al!turi de altele "i nici nu poate interfera cu ele. Mecanismul memoriei virtuale permite sistemului de operare s! aloce o zon! din spa#iul de adrese fizice "i s! o prezinte procesului ca ncepnd de la adresa virtual! 08048000H. Sistemul de operare face acest lucru pentru toate procesele. Toate procesele consider! c! blocul de memorie alocat lor de c!tre sistemul de operare ncepe de la adresa 08048000H "i sfr"e"te aproape de 0BFFFFFFFH (adresa de sfr"it nu e ntotdeauna aceea"i). Fiecare proces crede c! ruleaz! n propria zon! de memorie "i totu"i toate zonele de memorie ale proceselor ncep "i sfr"esc la acelea"i adrese. Sistemul de operare realizeaz! acest lucru mapnd aceea"i adres! virtual! la o adres! fizic! diferit!. Adresa 0BFFFFFFFH nseamn! pu#in peste 3 GB. Chiar dac! majoritatea calculatoarelor au mai pu#in! memorie fizic!, sistemul de operare poate promite programului 3 GB de memorie prin faptul c! nu mapeaz! toate adresele virtuale la adrese fizice. De fapt, spa#iul de memorie virtual! pus la dispozi#ia procesului este mp!r#it n dou! blocuri: Blocul inferior - ncepe de la adresa 08048000H "i con#ine sec#iunile de cod, date ini#ializate "i neini#ializate. Acestuia i este alocat numai spa#iul necesar, n func#ie de m!rimea codului "i a datelor definite. Blocul superior - ncepe din partea opus!, dinspre cap!tul superior al memoriei, "i se ntinde nspre blocul inferior. Adresa de nceput pentru al doilea bloc nu este ntotdeauna aceea"i, dar nu poate fi mai mare de 0BFFFFFFFH. Acest bloc reprezint! stiva programului. Stiva reprezint! o zon! de memorie n care sunt stocate variabilele locale "i
12

Proprietatea sistemului de operare de a executa mai mult de un program simultan se nume"te multitasking. Se bazeaz! pe capacitatea procesorului de a comuta rapid ntre procese, crend iluzia de simultaneitate.

parametrii func!iilor. La apelul unei func!ii, informa!iile men!ionate formeaz" un cadru de stiv" (stack frame). Atunci cnd se revine din func!ie, cadrul de stiv" asociat este eliberat. n stiv", datele sunt stocate utiliznd metoda ultimul intrat, primul ie#it (Last In First Out). Acest lucru nseamn" c" spa!iul este alocat #i dealocat la un singur cap"t al memoriei, numit vrful stivei. Stiva este o sec!iune din memoria principal" utilizat" pentru stocarea temporar" a informa!iilor, n care cel mai recent element introdus este primul extras.
4 GB KERNEL SPACE 3 GB stiv! 0BFFFFFFFH Bloc superior 0FFFFFFFFH

USER SPACE

Acest spa"iu de memorie virtual! este alocat numai la cerere. Nu e gol, ci NU EXIST# (HEAP)

segment .bss segment .data segment .text

Bloc inferior

08048000H 00000000H 0

Figura 4.2 Aspectul memoriei pentru un proces n linux

Spa!iul aparent neutilizat dintre cele dou" blocuri nu exist". Dac" programul are nevoie de memorie adi!ional" din acea zon", trebuie numai s" ncerce s" o acceseze #i sistemul de operare va mapa rapid adresa virtual" la o adres" fizic". Aceast" zon" se nume#te heap. Heap denot" o zon" de memorie folosit" pentru crearea #i distrugerea structurilor de date care au timp de via!" limitat. n acest caz, blocurile de memorie sunt alocate #i eliberate dinamic. Modelul de alocare #i dimensiunea blocului de

memorie nu sunt cunoscute dect la momentul rul!rii (runtime). Zona heap este partajat! de toate bibliotecile "i modulele nc!rcate dinamic de proces. ncepe la sfr"itul segmentului de date neini#ializate "i cre"te c!tre adrese mai mari. A"adar, n Linux, codul "i datele programului ncep de jos, aproape de 08048000H, iar stiva ncepe de sus, aproape de 0BFFFFFFFH.

4.4. Tipuri de date


Segmentele .data "i .bss con#in directive de date care declar! alocarea unor zone de memorie. Sunt dou! tipuri de directive de date: directive D<x>, pentru date ini#ializate (D=define) directive RES<x>, pentru date neini#ializate (RES=reserve) x se refer! la dimensiunea datelor "i se nlocuie"te cu indicatorii din Tabelul 4.1.
Tabelul 4.1 Dimensiunea tipurilor de date

Unitate Byte (octet) word (cuvnt) double word quad word ten bytes

Indicator (x) B W D Q T

Dimensiune (octe!i) 1 2 4 8 10

4.4.1. Date ini!ializate


Declararea unei zone de memorie cu date ini#ializate presupune definirea a trei elemente. etichet!: numele acelei zone de memorie. D<x>, unde x este litera corespunz!toare dimensiunii datelor declarate. DB DW DD DQ DT Define Define Define Define Define Byte Word Doubleword Quadword Ten Bytes ;aloc! 1 octet ;aloc! 2 octe#i ;aloc! 4 octe#i ;aloc! 8 octe#i ;aloc! 10 octe#i

valoare ini"ial!.

Este important s! n"elegem c!, spre deosebire de limbajele de nivel nalt, eticheta din limbajul de asamblare nu face altceva dect s! indice loca"ia datelor n memorie. Este un indicator, o adres!. Nu o valoare, nu un tip de date. Eticheta nu specific! o dimensiune. De#i este tentant s! o gndim ca variabil!, eticheta este mult mai limitat!: reprezint! numai adresa virtual! a unui octet aflat undeva n memorie. Variabilele limbajelor de nivel nalt sunt nume simbolice asociate cu un spa"iu de stocare de m!rime definit! #i cu o valoare cunoscut! sau necunoscut!. Pe parcursul programului, att loca"ia, ct #i valoarea, se pot modifica. Dac! la momentul declar!rii se atribuie o valoare de nceput (se define#te variabila), atunci vorbim de o variabil! ini"ializat!. Dac! se aloc! spa"iu f!r! atribuirea unei valori ini"iale, vorbim de variabil! neini"ializat!. Constanta reprezint! un tip special de variabil! a c!rei valoare nu poate fi alterat! n timpul execu"iei programului. Valoarea r!mne fix!. Valoarea unei constante este specificat! o singur! dat!. ; ;date ini!ializate ; section .data var db 55h ;octet cu numele var #i valoarea 0x55 vector db 55h ;o succesiune de trei octe"i db 56h db 57h _char db 'a' ;caracterul a cars db 'hello',12,10,'$' ;#ir sir db "hello" _short dw 1234h character dw 'a' chars dw 'abc' ;caracterele 61h, 62h, 63h _int dd 12345678h opt dq 0123456789ABCDEFh zece dt 0FFAAFFAAFFAAFFAAFFAAh Fiecare element de date este plasat n memorie n ordinea n care este definit. Elementele cu mai multe valori sunt plasate n memorie exact a#a cum apar n corpul directivei de date. Deoarece pentru multe asambloare, inclusiv pentru cel folosit de noi, short #i int sunt cuvinte rezervate (instruc"iuni), pentru a le folosi ca etichete am ad!ugat prefixul underscore. Am reprezentat harta memoriei n Figura 4.3. Cnd utiliz!m defini"ii multiple de date, asamblorul aloc! un spa"iu contiguu de memorie. De aceea, secven"a de directive vector poate fi abreviat!:

vector

db

55h,56h,57h

Din acest punct de vedere, secven!a, cars este abrevierea de la cars db db db db db db db db 'h' 'e' 'l' 'l' 'o' 12 10 '$' db 'hello',12,10,'$'

Valorile de ini!ializare pot fi definite "i ca expresii. De exemplu, _init este echivalent cu _init dw 250 dw 10*25

Asamblorul evalueaz# expresia "i atribuie etichetei valoarea rezultat#. De"i utilizarea unor astfel de expresii nu este indicat#, exist# situa!ii n care o expresie eviden!iaz# mai bine semnifica!ia datei respective. Ordinea octe!ilor Un octet poate reprezenta o valoare cuprins# ntre 0 "i 255. Numerele mai mari de 255 folosesc mai mult de un octet. O secven!# de doi octe!i al#tura!i poate reprezenta orice num#r ntre 0 "i 65535. Totu"i, o dat# ce ai o valoare numeric# care nu poate fi reprezentat# pe un singur octet, ordinea octe!ilor devine crucial". Lu#m ca exemplu num#rul zecimal 681. Limbile europene evalueaz# numerele de la dreapta la stnga. Num#rul 681 const# n 6 sute, 8 de zece "i 1 de unu, nu din 1 sute, 8 de zece "i 6 de unu. Prin conven!ie, cea mai pu!in semnificativ# coloan# este cea din dreapta "i valorile cresc de la dreapta la stnga. Dac# transform#m 681 n hexazecimal ob!inem o secven!# de doi octe!i: 02A9H. Cel mai semnificativ octet (MSB Most Significant Byte) este cel din stnga

(02H), iar cel mai pu!in semnificativ (LSB Least Significant Byte) este cel din dreapta (A9H). Dac" am inversa ordinea lor am ob!ine un num"r zecimal diferit (A902H = 43266). De aceea, trebuie s" fim aten!i cum scriem valorile zecimale reprezentate n hexazecimal #i, mai ales, s" #tim cum judec" sistemul de calcul numerele hexazecimale. Din acest ultim punct de vedere, sistemul de calcul are dou" posibilit"!i: octetul mai pu!in semnificativ este introdus la adres" de memorie mai mic", iar octetul mai semnificativ la adres" de memorie mai mare; octetul mai pu!in semnificativ este introdus la adres" de memorie mai mare, iar octetul mai semnificativ la adres" de memorie mai mic". Posibilit"!ile se exclud reciproc. Despre procesorul care stocheaz" octetul cel mai pu!in semnificativ la adres" mai mic" #i octetul cel mai semnificativ la adres" mai mare spunem c" respect" conven!ia little-endian. Procesorul care stocheaz" octetul cel mai semnificativ la adres" mai mic", lucreaz" conform conven!iei big-endian. Am spus procesorul, nu sistemul de operare. I always regret that I didn't fix up some idiosyncrasies of the 8080 when I had a chance. For example, the 8080 stores the low-order byte of a 16-bit value before the high-order byte. The reason for that goes back to the 8008, which did it that way to mimic the behavior of a bit-serial processor designed by Datapoint (a bitserial processor needs to see the least significant bits first so that it can correctly handle carries when doing additions). Now there was no reason for me to continue this idiocy, except for some obsessive desire to maintain strict 8080 compatibility. But if I had made the break with the past and stored the bytes more logically, nobody would have objected. And today we wouldn't be dealing with issues involving big-endian and little-endian - the concepts just wouldn't exist. Stephen Morse Sistemul de operare Linux utilizeaz" ambele tipuri de ordine, n func!ie de arhitectura hardware pe care este instalat. ntreaga arhitectur" x86, de la 8086 pn" la Haswell, este little-endian. Alte arhitecturi hardware, ca ARM sau POWER, sunt big-endian. Unele arhitecturile hardware, MIPS #i Intel Itanium, sunt bi-endian, n sensul c" pot fi configurate s" interpreteze valorile numerice ori ntr-un fel, ori n cel"lalt. Dar asta nu e tot. Limbile europene evalueaz" numerele de la dreapta la stnga, dar #irurile de caractere sunt evaluate invers, de la stnga la dreapta. Din aceast" perspectiv", dac" un #ir arbitrar de digi!i hexazecimali, ABCD, este considerat !ir de cifre hexazecimale (num"r), de exemplu 0ABCDH, atunci MSB este ABH #i LSB este CDH. n memorie, va ap"rea n ordinea CD AB. Dac" un #ir arbitrar de digi!i hexazecimali, ABCD, este considerat !ir de caractere (cuvnt, text), de exemplu 'ABCD', atunci MSB este caracterul D, iar LSB caracterul A. n

memoria unui sistem little-endian !irul de caractere va fi ordonat A B C D.


0xFF 0xAA 0xFF 0xAA 0xFF 0xAA 0xFF 0xAA 0x01 0x23 0x45 0x67 0x89 0xAB 0xCD 0xEF 0x12 0x34 0x56 0x78 0x00 0x63 0x62 0x61 0x00 0x61 0x12 0x34 0x6F 0x6C 0x6C 0x65 0x68 0x24 0x0A 0x0C 0x6F 0x6C 0x6C 0x65 0x68 0x61 0x57 0x56 0x55 0x55 7 0 Etichet! Adres! 0x80490bb 0x80490ba 0x80490b9 0x80490b8 0x80490b7 0x80490b6 0x80490b5 0x80490b4 0x80490b3 0x80490b2 0x80490b1 0x80490b0 0x80490af 0x80490ae 0x80490ad 0x80490ac 0x80490ab 0x80490aa 0x80490a9 0x80490a8 0x80490a7 0x80490a6 0x80490a5 0x80490a4 0x80490a3 0x80490a2 0x80490a1 0x80490a0 0x804909f 0x804909e 0x804909d 0x804909c 0x804909b 0x804909a 0x8049099 0x8049098 0x8049097 0x8049096 0x8049095 0x8049094 0x8049093 0x8049092 0x8049091 0x8049090

zece

opt

_int este num!r. Octetul mai pu"in semnificativ, 0x78, la adres! mai mic! (little-endian)

_int

chars character _short

Caracterul 'a' reprezentat pe un cuvnt. sir este #ir de caractere. Octetul mai pu"in semnificativ, 'h', la adres! mai mic! (little-endian).

sir

caracterul $ 10 12 'o' 'l' 'l' 'e' 'h' 'a'

cars char vector var

Figura 4.3 Harta memoriei

Harta memoriei din Figura 4.1 precizeaz! "i adresele corespunz!toare etichetelor. Numele simbolic var este adresa 0x8049090, ".a.m.d.. Pseudoinstruc#iunile DB, DW, DD, DQ, DT aloc! spa#iu de stocare "i asociaz! acestuia eticheta prin care poate fi accesat. La momentul asambl!rii, asamblorul atribuie fiec!rei etichete un deplasament. A"a cum am specificat anterior, asamblorul aloc! datelor un spa#iu contiguu. De asemenea, asamblorul p!streaz! ordinea datelor din fi"ierul surs!. Ca s! deduc! deplasamentul unui element de date, asamblorul nu trebuie dect s! numere octe#ii aloca#i datelor de dinainte. De exemplu, deplasamentul lui char este 4 deoarece var "i vector au aloca#i 1, respectiv 3 octe#i.
Tabelul 4.2 Tabela de simboluri

Nume var vector char cars sir _short character chars _int opt zece

Deplasament 0 1 4 5 13 18 20 22 26 30 38

Tabelul 4.2 prezint! tabela de simboluri corespunz!toare h!r#ii de memorie din Figura 4.3. Odat! aleas! adresa de nceput, celelalte sunt calculate prin adunarea deplasamentului. Acest lucru permite adresarea oric!rui element din segmentul de date prin intermediul etichetei var. Constante Constanta este o etichet! care are asociat! o valoarea fix!. O astfel de etichet! este tratat! asem!n!tor constantelor din limbajele de nivel nalt. De fiecare dat! cnd asamblorul ntlne"te o astfel de etichet!, va nlocui numele cu valoarea. Re#inem c! acest lucru se ntmpl! la asamblare. Constantele pot fi definite cu directivele EQU, %assign "i %define. Directiva EQU define"te constante numerice "i nu permite redefinirea ulterioar! n cadrul programului. EQU leag! un nume de un operand (de un singur operand). Valoarea r!mne aceea"i pe parcursul ntregului program. De exemplu, urm!toarea directiv! define"te o constant! numit! CR.

Valoarea ASCII pentru carriage-return este atribuit! acestei constante prin directiva EQU. CR NR_CARACTERE NR_DE_RAND NR_DE_COL MARIME_VECTOR equ equ equ equ equ 0Dh ;caracterul carriage-return 16 25 80 NUM_DE_RAND * NUM_DE_COL

Constantele CR, NR_CARACTERE,NR_DE_RAND, etc., nu pot fi redefinite mai trziu n cadrul programului. Totu"i, definirea unor constante aduce programului dou! avantaje: devine mai lizibil "i mai u"or de modificat. Prin asocierea valoare - nume descriptiv, instruc#iunea devine mai u"or de n#eles. Acum "tim c! valoarea 0DH din acea instruc#iune reprezint! caracterul carriagereturn. Pe de alt! parte, apari#ii multiple ale constantei pot fi modificate dintr-un singur loc. Pentru a modifica num!rul de caractere acceptat de la tastatur! de la 16 la 160 trebuie s! schimb!m numai valoarea din cadrul directivei NR_CARACTERE. Operandul unei directive EQU poate fi o expresie evaluat! la momentul asambl!rii. Ultimele trei propozi#ii definesc m!rimea vectorului la 2000. Foarte frecvent, constanta definit! cu EQU se folose"te la memorarea lungimii unui "ir. mesaj lungime db equ 'Hello world' $-mesaj

Constanta lungime va avea valoarea 11 "i nu va putea fi redefinit! pe tot parcursul programului. Caracterul $ reprezint! un simbol special al asamblorului, evaluat ca fiind adresa de nceput a liniei care con#ine expresia. Valoarea sa reprezint! deplasamentul curent n segment. A"adar, n cazul exemplului anterior, caracterul $ indic! primul octet dup! "irul 'Hello world'. Cum mesaj este adresa de nceput a "irului Hello world (adresa lui 'H'), $-mesaj reprezint! num!rul de octe#i ocupa#i de "ir. n cazul de fa#!, num!rul de octe#i ocupa#i de "ir se confund! cu num!rul de elemente al "irului, adic! lungimea acestuia. Dac! consider!m "irul mesaj2, lungimea se afl! mp!r#ind num!rul de octe#i la 4, deoarece fiecare caracter este reprezentat pe 32 de bi#i, adic! 4 octe#i. mesaj2 octeti lungime2 dd equ equ 'Hello world' $-mesaj2 ($-mesaj2)/4

n cazul EQU, simbolurile c!rora le-au fost alocate o valoare nu pot lua alte

valori pe parcursul programului. Dac! sunt necesare redefiniri, trebuie s! folosim directiva %assign. Directiva %assign define"te tot o constant! numeric!, dar permite redefinirea ulterioar! n cadrul programului. De exemplu, definim i ca fiind j+1 astfel: %assign i j+1

"i mai trziu, n cadrul programului, putem redefini i la valoarea j+10: %assign i j+10

Directiva %assign este sensibil! la majuscule. Simbolurile I "i i sunt tratate distinct. Dac! este un efect nedorit se poate folosi %iassign. Directivele EQU "i %assign definesc constante numerice. Directiva %define poate defini att constante numerice ct "i constante tip "ir. La fel ca directiva precedent!, %define permite redefinirea "i are variant! insensibil! la majuscule, %idefine. %define i [EBX+2]

4.4.2. Date neini!ializate


n segmentul datelor neini#ializate nu declar!m valori, ci rezerv!m un anumit num!r de loca#ii de memorie. Fiecare directiv! de rezervare prime"te ca argument un singur operand - num!rul de unit!#i de memorie care trebuie rezervat (octe#i, cuvinte, dublu cuvinte, etc.). Directiva de rezervare RES<x> ia urm!toarele forme: RESB RESW RESD RESQ REST (REServe a Byte) (REServe a Word) (REServe a Doubleword) (REServe a Quadword) (REServe Ten Bytes) ;rezerv! un octet ;rezerv! un cuvnt ;rezerv! un dublu cuvnt ;rezerv! un cuvnt cvintuplu ;rezerv! 10 octe#i

A!adar, RES<x> specific" ntotdeauna num"rul de elemente de memorie. Cteva exemple: tampon: cuvnt: resb 64 resw 1 ;rezerv! 64 de octe#i ;rezerv! un cuvnt (2 octe#i)

vector:

resq 10

;rezerv! un "ir de 10 numere reale (80 octe#i)

Am putea presupune c! declara#iile precedente, introduse n sec#iunea de date neini#ializate a unui program, cresc m!rimea executabilului cu 148 de octe#i. Dar un beneficiu al declar!rii elementelor n sec#iunea datelor neini#ializate este c! acestea nu sunt incluse n programul executabil. Datele ini#ializate sunt incluse n corpul programului executabil deoarece trebuie ini#ializate cu o valoare specific!. Zonele de date declarate n segmentul BSS nu sunt ini#ializate cu valori la creare (sunt ini#ializate la momentul rul!rii), a"adar nu sunt incluse n fi"ierul surs!. n capitolul urm!tor, cnd vom prezenta operatorul TIMES, vom demonstra acest lucru prin testarea m!rimii unui program ce aloc! succesiv 100 de elemente de date ini#ializate "i 100 de elemente de date neini#ializate.

4.5. Procesul de dezvoltare al programelor


Privit n mare, procesul de dezvoltare al programelor n asamblare poate fi rezumat astfel: 1. Editarea fi"ierului surs!; 2. Asamblarea fi"ierului surs! "i ob#inerea fi"ierului obiect; 3. Coversia fi"ierului obiect ("i a altor module obiect asamblate anterior) ntrun singur fi"ier executabil cu ajutorul editorului de leg!turi; 4. Testarea programului prin execu#ia sa direct! sau prin intermediul unui depanator; 5. Dac! algoritmul trebuie mbun!t!#it se revine la pasul 1 "i se modific! fi"ierul surs!; 6. Se repet! pa"ii anteriori pn! la ob#inerea rezultatului dorit.

4.5.1. Editarea textului


Programele n asamblare (de fapt, orice programe, indiferent de limbajul de programare utilizat) sunt scrise cu un editor de text. Nu are importan#! care, dar e bine ca n alegerea acestuia s! #inem cont de cteva lucruri. Procesoarele de text gen Microsoft Word "i LibreOffice Writer, pe lng! textul propriu zis, includ n fi"iere date suplimentare (de ex., formatarea paginii, tipul de font, m!rimea sa, antete de pagin!) de care asamblorul nu are nevoie "i pe care nu le n#elege. E posibil ca, n timpul asambl!rii, aceast! informa#ie suplimentar! s! genereze erori. Pe de alt! parte, este dezirabil ca editorul de text s! poat! eviden#ia sintaxa

limbajului n care scriem - n cazul nostru, limbajului de asamblare. Nu toate editoarele de text au aceast! proprietate. De aici nainte se presupune c! lucra"i cu editorul de text vim. Vim Vi este un editor de text prezent n majoritatea sistemelor Unix. Prima versiune a fost dezvoltat! la Universitatea Berkeley n anul 1980. Vim este acronimul lui Vi Improved, o variant! extins! a lui vi, creat! de Bram Moolenaar n 1991. Vim include toate caracteristicile vi, plus multe altele noi, destinate s! ajute utilizatorul n procesul de editare al codului surs!. n vim, comenzile sunt introduse numai prin intermediul tastaturii, ceea ce nseamn! c! putem "ine minile pe tastatur! #i ochii pe ecran. Pentru utilizarea acestuia avem nevoie de un terminal, a#adar introduce"i combina"ia de taste CTRL+ALT+T. Cei care nu consider! introducerea comenzilor de la tastatur! un avantaj, pot instala gvim, o versiune grafic! a lui vim. Gvim asigur! integrarea cu mouse-ul, prezint! meniuri #i bar! de derulare. Vim este o unealt! plin! de func"ionalit!"i #i dispune de un manual pe m!sur!. Manualul poate fi activat din interiorul editorului prin comanda :help (man nu con"ine foarte multe informa"ii). n continuare vom prezenta numai comenzile principale. Deschiderea unui fi#ier se realizeaz! prin comanda vim fisier.txt. Dac! fi#ierul nu exista nc!, va fi creat. Aten"ie, creat nseamn! c! a fost selectat! o zon! temporar! de memorie (buffer) care va re"ine textul introdus de noi pn! la salvarea lui pe disc. Dac! nchidem fi#ierul f!r! s! salv!m datele pe disc, am pierdut tot ce am introdus n fi#ier, inclusiv denumirea. Numai salvarea datelor duce la crearea fisier.txt pe disc. Din perspectiva interfe"ei, bufferul este fereastra n care apare textul n curs de editare. Ecranul vim con"ine un buffer #i o linie de comand! aflat! n partea de jos a acestuia. n linia de comand! sunt afi#ate informa"ii de stare #i pot fi introduse comenzi. Vim opereaz! n mai multe moduri de lucru, ceea ce nseamn! c! editorul se comport! diferit, n func"ie de acestea. n aceast! prezentare vom lucra n dou! moduri: comand! #i editare. n mod comand!, tot ce tast!m este interpretat de editor ca o comand!. Exemple de astfel de comenzi sunt: salveaz! fi#ierul, p!r!se#te editorul, mut! cursorul, #terge, caut!, nlocuie#te, selecteaz! por"iuni de text, trece editorul n modul inserare. Modul editare (inserare) ne permite s! introducem text. Acest! dualitate de operare nseamn! c! orice tast! poate reprezenta o comand! sau un caracter. De exemplu, tasta i (insert), introdus! n mod comand!, comut! editorul n modul editare, n modul editare este pur #i simplu caracterul i. Modul editare este indicat prin cuvntul INSERT afi#at pe linia de jos a

terminalului. n zona bufferului, liniile libere sunt indicate prin caracterul ~ (tilda). n acest moment putem introduce text. Salvarea fi!ierului nseamn" o comand", a!adar, comut"m n mod comand" ap"snd tasta ESC. Putem ie!i din editor cu urm"toarele comenzi: ZZ salveaz" bufferul pe disc !i ie!i :x - salveaz" bufferul pe disc !i ie!i (la fel ca ZZ) :wq salveaz" bufferul pe disc !i ie!i (la fel ca ZZ) :q ie!i din editor (func#ioneaz" numai dac" modific"rile sunt salvate) :q! - ie!i din editor f"r" s" salvezi bufferul pe disc Cu urm"toarele comenzi putem scrie bufferul pe disc. :w - salveaz" bufferul n fi!ierul curent (fisier.txt) :w output.txt - salveaz" bufferul n fi!ierul output.txt; nu rescrie fi!ierul n caz c" acesta exist" :w! output.txt - salveaz" bufferul n fi!ierul output.txt; rescrie fi!ierul dac" exist". Prima comand" salveaz" modific"rile n fi!ierul dat ca argument. A doua !i a treia comand" ne permite s" salv"m bufferul ntr-un fi!ier nou. Pentru a afla informa#ii suplimentare despre comanda :w, putem folosi :help w. Implicit, ecranul va fi mp"r#it n jum"tate, cu partea superioar" afi!nd informa#ii de ajutor. nchiderea noii ferestre de face cu :q. Navigarea prin text se face de regul" cu tastele s"ge#i. Dar pentru c" este incomod s" mut"m mna frecvent n col#ul din dreapta jos al tastaturii se pot folosi tastele h, l, k, j (un caracter la stnga, dreapta, sus, jos). n plus, Space deplaseaz" cursorul cu un caracter la dreapta !i Enter pozi#ioneaz" cursorul la nceputul liniei urm"toare. Alte comenzi care pot deplasa cursorul sunt: G gg ^ $ w b fx Fx % - pozi#ioneaz" cursorul la ultima linie a documentului - pozi#ionaz" cursorul la prima linie a documentului - pozi#ioneaz" cursorul la nceputul liniei curente - pozi#ioneaz" cursorul la sfr!itul liniei curente - pozi#ioneaz" cursorul un cuvnt nainte - pozi#ioneaz" cursorul un cuvnt napoi - s"ri la urm"toarea apari#ie a caracterului x pe linia curent" - s"ri la precedenta apari#ie a caracterului x pe linia curent" - s"ri la paranteza care corespunde celei de sub cursor.

De asemenea, n mod comand! putem modifica textul: x - "terge caracterul sub care este pozi#ionat cursorul X - "terge caracterul dinaintea cursorului dG - "terge de la linia curent! pn! la sfr"itul fi"ierului dfx - "terge tot textul ncepnd cu pozi#ia curent! pn! la urm!toarea apari#ei a caracterului x dd - "terge linia curent! dw - "terge urm!torul cuvnt D - "terge restul liniei curente u - anuleaz! ultima comand! U - anuleaz! toate modific!rile f!cute pe ultima linie editat! r - nlocuie"te caracterul curent cu cel introdus Cnd "tergem ceva cu x, d (delete), sau alt! comand!, textul este salvat ntr-o memorie temporar!. l putem realipi cu p (paste, de"i termenul tehnic n vi este put). Comanda p are semnifica#ii diferite, n func#ie de elementele de text "terse. Folosit! dup! dw (delete word): p P - plaseaz! textul dup! cursor - plaseaz! textul nainte de cursor

Folosit dup! dd: p P - plaseaz! textul sub linia curent! - plaseaz! textul deasupra liniei curente

Modificarea unui cuvnt sau a unei p!r#i de cuvnt (de la cursor pn! la sfr"itul cuvntului) se face prin pozi#ionarea cursorului n locul de nceput "i tastarea comenzii cw (change word). Editorul trece automat n mod editare. Comanda cw este o comand! compus! din alte dou! comenzi; n acest caz, din al!turarea comenzilor c (change) "i w (word). Alte exemple: c$ c^ 4cw 5dd 3x 3X 2G - schimb! ncepnd cu pozi#ia curent! pn! la sfr"itul liniei - schimb! ncepnd cu pozi#ia curent! pn! la nceputul liniei - schimb! urm!toarele 4 cuvinte - "terge urm!toarele 5 linii - "terge urm!toarele 3 caractere - "terge 3 caractere din fa#a cursorului - pozi#ioneaz! cursorul la a doua linie a documentului

Copierea f!r! "tergere se face cu y (yank). Nu afecteaz! textul, dar poate fi folosit n conjunc#ie cu p. n acest caz, p se comport! la fel ca n cazul lui d. yw yy 3yy - copiaz! urm!torul cuvnt - copiaz! linia curent! - copiaz! urm!toarele trei linii

Comanda de nlocuire r (replace) plaseaz! vim n mod editare. Caracterul tastat va nlocui caracterul curent, dup! care editorul revine automat n mod comand!. Pe lng! comanda r, vim trece n mod editare "i cu i (insert), a (append) sau o (open). n aceste cazuri, textul va fi introdus ncepnd cu prima pozi#ie nainte de cursor, prima pozi#ie dup! cursor, sau la nceputul unei linii noi, creat! imediat sub linia curent!. Pentru a c!uta nainte ntr-un text, se folose"te comanda /. De exemplu, /text caut! "irul text de la pozi#ia curent! a cursorului c!tre sfr"itul fi"ierului. C!utarea napoi se face cu ? n loc de / . De exemplu, ?text caut! de la pozi#ia curent! a cursorului c!tre nceputul fi"ierului. Ultima comand! discutat! este cea de substitu#ie, s (substitute). Permite nlocuirea unor p!r#i de text. :[linii] s/text_vechi/text_nou/op!iune Vechiul text este nlocuit cu cel nou n limita liniilor specificate de domeniul op#ional [linii]. Domeniul este specificat n format de la, pn! la. Dac! nu este dat un domeniu, schimb!rile apar numai pe linia curent!, considerat! implicit. Cmpul op!iune modific! comanda. De obicei se folose"te caracterul g, care nseamn! substitu#ie global!. Comanda :s/test/text nlocuie"te cu text prima apari#ie a cuvntului test n linia curent!. Dac! dore"ti s! nlocuie"ti toate apari#iile din linia curent!, folose"ti op#iunea g :s/test/text/g Comanda :1,10s/test/text nlocuie"te prima apari#ie a lui test n fiecare din cele 10 linii specificate. Ca s!

schimbi toate apari!iile lui text n aceste linii, adaugi op!iunea g la sfr"it. Am acoperit numai comenzile de baz#. Vim permite cteva comenzi foarte sofisticate.13 Un lucru foarte important, toate uneltele folosite de noi n procesul de asamblare (editorul de text, asamblorul) recunosc fi"ierele text ca fi"iere scrise n limbaj de asamblare dup# extensia .asm. Cu alte cuvinte, fi"ierele surs# scrise n limbaj de asamblare trebuie ntotdeauna salvate pe disc cu extensia .asm (de ex., program.asm). n continuare, scrie!i programul care urmeaz# ntr-un fi"ier intitulat prog.asm. section .data a db 0fh b db 89 c dw 045E3h d dw 65535 e dd 001234567h f dd 1047000 g db 0ffh section .text global _start _start: nop ;ncarc# imediatul 8H n registrul de 8 bi!i AL mov al, 8h ;ncarc# imediatul 1239054 n registrul de 32 de bi!i EAX mov eax, 1239054 ;copiaz# valoarea 89 (aflat# n loca!ia de memorie cu adresa b) n registrul de 8 bi!i BL mov bl,[b] ;copiaz# valoarea 45E3H (aflat# n loca!ia de memorie cu adresa c) n registrul de 16 bi!i CX mov cx,[c] ;copiaz# valoarea 01234567H n registrul de 32 de bi!i EDX mov edx,[e] ;ncarc# registrul de 32 de bi!i EAX cu adresa etichetat# a mov eax,a ;ncarc# registrul de 32 de bi!i EBX cu adresa etichetat# b mov ebx,b
13

ftp://ftp.vim.org/pub/vim/doc/book/vimbook-OPL.pdf

;copiaz! n loca"ia de memorie etichetat! a valoarea aflat! n registrul de 8 bi"i AH. n segmentul de date, a este declarat! ca fiind etichet! la o loca"ie de 8 bi"i. mov [a],ah ;copiaz! n loca"ia f de 32 de bi"i valoarea aflat! n registrul de 32 de bi"i ECX. Evident, vechea valoare adresat! de f se pierde. mov [f],ecx ;copiaz! n registrul de 8 bi"i AH valoarea 0ffh. Observ!m parantezele p!trate. F!r! ele, asamblorul ar fi ncercat s! scrie n AH adresa g, #i cum registrul de 8 bi"i AH este prea mic pentru o adres! de 32 de bi"i, asamblorul returneaz! o eroare (relocation truncated to fit: R_386_16 against `.data'). mov ah, [g] ;ntrerupe rularea programului mov eax,1 mov ebx,0 int 80h Programul realizeaz! una din cele mai frecvente activit!"i ntlnite n practic!, transfer! date dintr-un loc n altul cu ajutorul instruc"iunii MOV.

4.5.2. Asamblarea
Dup! editarea #i salvarea programului putem verifica prezen"a fi#ierului surs! cu ajutorul comenzii ls. n urma acestei comenzi ar trebui s! vede"i fi#ierul prog.asm. Dac! nu, verifica"i s! nu fi omis ceva. Presupunnd c! fi#ierul surs! este prezent, trebuie s! l transform!m n fi#ier obiect cu ajutorul unui asamblor. n paragrafele urm!toarea prezent!m dou! din cele mai cunoscute asambloare. NASM (Netwide Assembler) este un asamblor pentru arhitecturi Intel x86, de la 16 pn! la 64 de bi"i, care suport! toate extensiile acestora pn! n prezent. Ruleaz! pe o mare varietate de sisteme de operare (Linux, BSD, Windows). Folose#te o sintax! similar! cu cea Intel, dar mai pu"in complex!, #i vine cu un pachet serios de macroinstruc"iuni. YASM este o rescriere complet! a asamblorului NASM, sub o licen"! diferit!14. Suport! mai multe sintaxe de asamblare (de ex. NASM, GAS, TASM, etc.) #i la fel de multe formate de fi#iere obiect. n general, YASM poate fi folosit alternativ cu NASM. Avantaje: a fost primul care a implementat suport pentru arhitecturi x86_64. Acesta a fost #i marele s!u avantaj pn! la NASM 0.99.00.
14

Licen"! BSD, spre deosebire de NASM licen"iat LGPL.

fiind un proiect mai dinamic, YASM r!spunde mai rapid cererilor venite de la utilizatori (de informa"ii sau noi op"iuni). poate asambla fi#iere scrise att n sintaxa Intel ct #i AT&T (gas). implementeaz! o interfa"! ce poate fi folosit! de c!tre compilatoare. Dezavantaje: NASM a fost utilizat #i depanat intensiv. YASM este un proiect activ, e posibil s! nu fie att de bine testat ca NASM. Datorit! resurselor superioare implicate de-a lungul timpului n dezvoltarea NASM, documenta"ia este mai complet!.

NASM #i YASM sunt utilitare n linie de comand!. Deoarece n testele noastre YASM s-a dovedit a suporta mai bine arhitecturi de 64 de bi$i, n aceast! carte recomand!m utilizarea acestuia. n schimb, pentru informa"ii cu privire la sintaxa, instruc"iunile, declara"iile suportate de asamblor, consulta"i manualul NASM.15 Asambla"i fi#ierul surs! introducnd urm!toarea comand!: yasm -f elf -g stabs prog.asm -l prog.lst Comanda de asamblare ncepe chiar cu numele asamblorului. Dup! nume urmeaz! diverse op"iuni ce guverneaz! procesul de asamblare. Acestea pot fi g!site n documenta"ia YASM. Cele prezente sunt specifice platformei Linux: cuvntul YASM invoc! asamblorul; -f elf specific! asamblorului faptul c! fi#ierul obiect trebuie generat n format ELF, propriu sistemelor Linux de 32 de bi"i; -g specific! asamblorului s! includ! n fi#ierul obiect informa"ie de depanare #i indic! formatul acesteia (n acest caz STABS); prog.asm, numele fi#ierului surs! pe care dorim s! l asambl!m; -l specific! asamblorului s! creeze un listing al procesului de asamblare. Fi#ierul listing include textul programului #i eventualele erori ap!rute la asamblare. Dac! YASM nu g!se#te gre#eli de sintax!, procesul se finalizeaz! cu succes #i ob"inem doar un nou prompt. Dac! a"i scris programul cu gre#eli, asamblorul semnaleaz! aten"ion!ri sau erori. Despre acestea vorbim mai trziu, deocamdat! asigura"i-v! c! fi#ierul prog.lst corespunde celui de mai jos. Tasta"i
15

http://www.nasm.us/doc/. Totu#i, nu neglija"i resursele YASM: http://www.tortall.net/ projects/yasm/manual/manual.pdf

comanda cat prog.lst. 1 2 3 00000000 4 00000001 5 00000002 6 00000004 7 00000006 8 0000000A 9 0000000E 10 11 12 13 00000000 15 00000001 17 00000003 19 00000008 21 0000000E 23 00000015 25 0000001B 27 00000020 29 00000025 31 0000002B 33 00000031 35 00000037 36 0000003C 37 00000041 %line 1+1 prog.asm [section .data] 0F a db 0f 59 b db 89 E345 c dw 045E3 FFFF d dw 65535 67452301 e dd 001234567 D8F90F00 f dd 1047000 FF g db 0ff [section .text] [global _start] _start: 90 nop B008 mov al, 8 B80EE81200 mov eax, 1239054 8A1D[00000000] mov bl,[b] 668B0D[00000000] mov cx,[c] 8B15[00000000] mov edx,[e] B8[00000000] mov eax,a BB[00000000] mov ebx,b 8825[00000000] mov [a],ah 890D[00000000] mov [f],ecx 8A25[00000000] mov ah, [g] B801000000 mov eax,1 BB00000000 mov ebx,0 CD80 int 80

Acesta este rezultatul op!iunii -l din comanda de asamblare. Chiar dac" procesul de asamblare nu a ntmpinat probleme, informa!ia din fi#ierul prog.lst nu este lipsit" de importan!". Cele mai interesante informa!ii se desprind din coloana a doua #i a treia. Coloana a doua specific" distan!a liniei curente fa!" de nceputul fi#ierului surs" (dat" n octe!i). Din aceste informa!ii putem calcula num"rul de octe!i ai instruc!iunilor. A treia coloan" prezint" codul ma#in" pentru fiecare instruc!iune n limbaj de asamblare. Codul ma#in" al instruc!iunilor care lucreaz" cu memoria sunt incomplete (vezi parantezele p"trate), deoarece n momentul asambl"rii nc" nu sunt cunoscute adresele la care se vor afla datele n memorie. Acesta este rolul editorului de leg"turi. Formatul fi#ierelor obiect variaz" n func!ie de platforma pe care dorim s" rul"m programul. YASM este capabil s" genereze toate formatele ntlnite pe

platformele suportate. Parametrul -f specific! asamblorului formatul fi"ierului obiect. Pentru arhitecturi IA-32 "i sistem de operare Linux i386, formatul este ELF32, sau simplu, ELF. Pentru arhitecturi x86-64 "i sistem Linux amd64, formatul este ELF64. n timpul dezvolt!rii unui program este dezirabil s! include#i n fi"ierul obiect informa#ie de depanare. n acest mod se poate verifica execu#ia programului "i depista eventualele erori de programare. Parametrul -g specific! asamblorului s! introduc! informa#ie de depanare n fi"ierul obiect. La fel ca n cazul formatului obiect, YASM poate genera diferite formate de informa#ie de depanare. Pentru un sistem Linux "i o platform! de 32 de bi#i se poate folosi formatul STABS sau DWARF. Formatul STABS este mai simplu "i e tot ce ne trebuie n acest stadiu. Re#ine#i c! sistemul de operare Linux diferen#iaz! literele mici de cele mari n corpul comenzilor (case sensitive). Parametrul -f este diferit de parametrul -F. La fel "i numele fi"ierului surs!: prog.asm este diferit de Prog.asm, sau orice alt! varia#ie de caractere. Acela"i lucru este valabil "i n cazul etichetelor din program. Asamblorul diferen#iaz! eticheta b de B. n schimb, numele registrelor pot ap!rea n orice variant!: eax, EAX, eAx, Al, aL, toate sunt corecte att timp ct succesiunea de litere denot! un registru existent. S! intr!m pu#in n detalii. Mesaje de eroare Un fi"ier surs! scris corect este complet comprehensibil asamblorului "i poate fi translatat n instruc#iuni ma"in! f!r! probleme. Dac! asamblorul g!se"te ceva ininteligibil n linia de program pe care o proceseaz!, textul respectiv se nume"te eroare, "i asamblorul afi"eaz! un mesaj de eroare. Erorile pot consta din scrierea gre"it! a numelui unui registru sau din asocierea eronat! a opcode-ului cu operanzii. n cazul primei erori, mesajul de eroare afi"at este de forma: prog.asm:5: symbol 'etx' undefined n acest caz mesajul este destul de clar, asamblorul nu cunoa"te cine este etx. Pentru noi este un registru scris gre"it. Pentru asamblor poate fi orice simbol al programului, nu conteaz! ce anume (putea fi numele unei variabile), problema este c! nu l n#elege. Observa#i c! num!rul liniei care con#ine eroarea este plasat imediat dup! numele fi"ierului (:5). Al!turarea eronat! a opcode-ului cu operanzii este semnalizat! prin mesajul: prog.asm:10: invalid combination of opcode and operands E"ti avertizat c! ai ncercat o asociere invalid! ntre opcode "i operanzi. Dar, ca s! po#i n#elege ce este valid "i ce este invalid trebuie s! "tii ce ai gre"it. A"adar, mesajele de eroare ale asamblorului nu absolv! programatorul de la

cunoa!terea procesorului sau regulilor de asamblare. Atunci cnd asamblorul afi!eaz" concomitent mai multe erori, este indicat s" ncepe#i cu rezolvarea primeia. Celelalte erori pot ap"rea din cauza acesteia. Mesaje de eroare pot ap"rea !i n etapa de editare de leg"turi, atunci cnd editorul de leg"turi ntmpin" probleme n procesul de asociere a mai multor fi!iere obiect. Din fericire, aceste erori sunt mai pu#in ntlnite. Mesaje de aten!ionare Mesajele de eroare fac imposibil" generarea fi!ierului executabil; cnd asamblorul sau editorul de leg"turi ntlne!te o eroare, nu va furniza ca ie!ire niciun fi!ier.16 Mesajele de aten#ionare apar cnd asamblorul ntlne!te ceva care violeaz" logica sa intern", dar nu att de grav nct s" opreasc" procesul de asamblare. De exemplu, YASM va afi!a o aten#ionare dac" n program este definit" o etichet" c"reia nu i urmeaz" nicio instruc#iune. n cazul aten#ion"rilor, asamblorul se comport" ca un consultant care indic" ceva ciudat n codul surs". De!i executabilul va fi generat, este bine s" #inem cont de mesajele de aten#ionare !i s" investig"m problemele ap"rute. Ignora#i un mesaj de aten#ionare numai dac" !ti#i exact ce nseamn".

4.5.3. Editarea leg"turilor


n acest moment, YASM a generat un fi!ier obiect cu numele fi!ierului surs" !i extensia .o (object). Nu este neap"rat necesar ca fi!ierul obiect s" poarte numele fi!ierului surs". Numele fi!ierului obiect rezultat poate fi specificat prin parametrul -o. nainte s" edit"m leg"turile, verific"m existen#a fi!ierului obiect cu ls. Editorul de leg"turi are rolul s" uneasc" fi!ierul obiect de altele !i s" aloce efectiv adrese !i resurse de sistem viitorului fi!ier executabil. Editorul de leg"turi utilizat este ld (GNU Linker). Dup" ce ne-am asigurat de prezen#a fi!ierului obiect prog.o scriem n terminal urm"toarea comand": ld -o prog prog.o Dac" procesul se finalizeaz" f"r" erori, n directorul curent apare un fi!ier executabil. La fel ca la asamblare, parametrul -o specific" numele fi!ierului de ie!ire. Dac" nu am fi specificat numele dorit pentru executabil, editorul de leg"turi ar fi generat un fi!ier cu numele a.out. n Windows, fi!ierele executabile se identific" prin extensia .exe. n Linux, executabilele nu folosesc extensie, dar pot fi
16

Aceste erori sunt fatale. De aici !i termenul fatal error.

identificate dup! drepturile de execu"ie pe care le de"in sau dup! culoare verde din listingul ls. Aten"ie! Dac! editorul de leg!turi refuz! s! proceseze comanda anterioar! #i afi#eaz! mesajul ld: i386 architecture of input file `prog.o' is incompatible with i386:x86-64 output, nseamn! c! sistemul de operare este de tip x86-64 #i editorul de leg!turi nu poate lega un fi#ier obiect generat n format ELF de biblioteci de 64 de bi"i. O solu"ie este s! asambla"i iar!#i programul folosind formatul ELF64. Dar, pentru c! subiectul acestei c!r"i este studiul limbajului de programare pe arhitecturi IA-32, este mai indicat s! genera"i un executabil compatibil cu astfel de arhitecturi folosind n procesul edit!rii de leg!turi parametrul -m, astfel: ld -o prog prog.o -m elf_i386

4.5.4. Automatizarea sarcinilor cu GNU Make


Probabil deja v! gndi"i cu groaz! la faptul c! de acum nainte, pentru fiecare program n parte, trebuie s! scrie"i o linie complex! de asamblare, plus una, la fel de complex!, de editare de leg!turi. Dar v! aten"ionez c! acest lucru se ntmpl! nu dup! fiecare instan"! de program, ci dup! fiecare modificare a programului. Se poate ntmpla s! scrie"i o virgul! unde nu trebuie. Procesul de generare a executabilului trebuie luat de la nceput: editare, asamblare, editare de leg!turi. Atunci cnd aplica"ia dispune de mai multe fi#iere surs!, situa"ia devine critic!. Asamblarea #i legarea acestora devine un proces foarte anevoios. Utilitarul Make serve#te n Linux la automatizarea compil!rii programelor. Cele mai multe programe distribuite n format surs! folosesc acest utilitar. Prima implementare a GNU Make a fost realizat! de Richard Stallman #i Roland McGrath Mecanismul Make permite crearea fi#ierelor executabile din p!r"ile lor componente. Utilitarul Make execut! alte programe n conformitate cu un plan descris de un fi#ier text numit makefile. Fi#ierul makefile seam!n! pu"in cu un program de calculator n care se specific! cum trebuie s! se fac! ceva. Dar, spre deosebire de un program, nu precizeaz! succesiunea exact! a opera"iilor ci specific! ce componente din program sunt necesare la crearea altor componente din program. n cele din urm!, prin aceast! modalitate de ac"iune, sunt definite toate regulile necesare ob"inerii executabilului final. Aceste reguli sunt numite dependin"e. n practic!, codul surs! al aplica"iilor con"ine sute, mii sau chiar milioane de linii. Problema principal! a dezvoltatorilor de aplica"ii const! din cantitatea imens! de linii de cod care trebuie gestionat!. R!spunsul la aceast! problem! const! n scrierea programelor ntr-o manier! modular!. Programul este mp!r"it n componente mai mici #i fiecare component! este dezvoltat! separat. Desigur, acest

lucru nseamn! o provocare suplimentar!, trebuie s! "tii cum sunt create componentele "i modul n care acestea se potrivesc mpreun!. Pentru asta este nevoie de un plan. Noi deja am urmat un astfel de plan. Ca s! ob#inem fi"ierul executabil a trebuit s! transform!m mai nti fi"ierul surs! n fi"ier obiect (cu ajutorul unui asamblor). Existen#a fi"ierului obiect depinde a"adar de cea a fi"ierului surs!. n continuare, fi"ierul executabil depinde de existen#a fi"ierului obiect, precum "i de existen#a altor fi"iere bibliotec!. Pentru legarea acestor fi"iere obiect mpreun! am fost obliga#i s! folosim un editor de leg!turi. Ei bine, fi"ierul makefile trebuie s! descrie chiar acest plan. Crearea fi"ierului makefile ncepe cu determinarea dependin#elor (fi"ierele necesare pentru ob#inerea fi"ierului executabil). Fi"ierul executabil este creat n etapa de editare de leg!turi, a"adar, prima dependin#! care trebuie definit! const! din numele fi"ierelor necesare editorului de leg!turi ca s! creeze fi"ierul executabil. Prima linie a fi"ierului makefile este: prog: prog.o Acest lucru nseamn! c! pentru generarea fi"ierului executabil prog este nevoie de fi"ierul obiect prog.o. Aceast! linie se nume"te linie de dependin#e. Probabil este cea mai simpl! linie de dependin#e posibil!: un fi"ier executabil depinde de un singur fi"ier obiect. Dac! sunt necesare fi"iere obiect adi#ionale, ele trebuie aranjate unul dup! altul, separate prin spa#ii. Aceast! organizare se nume"te list! de dependin#e. exec: main.o swap.o com.o Aceast! linie ne spune c! executabilul depinde de trei fi"iere obiect (main.o, swap.o "i com.o). Toate trei trebuie s! existe nainte de a putea genera fi"ierul executabil exec, numit #int!. Liniile de dependin#e descriu fi"ierele, nu "i ac#iunea necesar! ob#inerii lor. Aceasta este o parte esen#ial! a procesului, "i este o linie cunoscut! nou!. Aceste dou! linii lucreaz! mpreun!: prog: prog.o ld -o prog prog.o A doua linie trebuie identat! fa"! de nceputul liniei cu un singur caracter TAB. Din motive de tradi#ie, comenzile dintr-un fi"ier makefile trebuie precedate de caracterul TAB. O gre"eal! frecvent! const! n introducerea unor spa#ii nainte de comenzi. Apari#ia unui mesaj de forma celui de mai jos nseamn!, destul de probabil, omiterea folosirii caracterului TAB:

makefile:2: *** missing separator.

Stop.

A!adar, mecanismul Make presupune s" specifici numele fi!ierelor necesare !i ce trebuie f"cut cu aceste fi!iere. n plus, pentru a optimiza execu#ia ac#iunilor, o dat" fi!ierul compilat sau legat, Make nu va repeta procesul dect atunci cnd este modificat unul din fi!ierele surs" sau obiect de care depinde. De asemenea, Make !tie cnd au fost modificate ultima oar" executabilul !i dependin#ele, astfel nct, dac" fi!ierul executabil este mai recent dect vreo dependin#", deduce c" schimb"rile ap"rute n codul obiect deja sunt reflectate n executabil (poate fi absolut sigur de acest lucru, deoarece singura modalitate de a genera executabilul se face prin prolucrarea fi!ierului obiect). Make determin" data !i ora modific"rilor printr-o facilitate a sistemului de fi!iere (aminti#i-v" de rezultatul comenzii ls l). nc" nu am terminat de editat fi!ierul makefile. Mecanismul Make !i dovedeasc" importan#a cnd fi!ierul de configurare con#ine lan#uri de dependin#e. Chiar !i cel mai simplu fi!ier makefile va con#ine dependin#e care depind de alte dependin#e. Pn" !i programul nostru banal are nevoie de dou" propozi#ii de dependin#e n fi!ierul s"u makefile: prog: prog.o ld -o prog prog.o prog.o: prog.asm yasm -f elf -g stabs prog.asm Aceste dou" propozi#ii de dependin#e definesc cei doi pa!i necesari gener"rii fi!ierului executabil prog. La apelarea comenzii make, aceasta caut" n directorul curent fi!ierul makefile (dac" nu l g"se!te, caut" Makefile) !i execut" secven#a de opera#ii specificat" n el. make -k Op#iunea -k instruie!te Make s" opreasc" generarea oric"rui fi!ier n care apare o eroare !i s" p"streze neschimbat" copia anterioar" a fi!ierului #int" (continu" ns" generarea oric"rui alt fi!ier care trebuie creat/recreat). n absen#a op#iunii -k, Make ar putea suprascrie codul obiect !i executabilul existent cu variante incomplete. Reamintim c" oricnd aduce#i fi!ierului surs" o modificare, indiferent de mic", trebuie s" rula#i make pentru a reface executabilul. Lucru care nu este att de groaznic cum pare. Editoarele de text prezentate includ combina#ii de taste sau comenzi care v" permit s" rula#i Make din cadrul lor.

Integrarea cu Vim Comanda :make ruleaz! programul Make n directorul curent. Implicit, Vim recunoa"te mesajele de eroare "i le listeaz!, facilitnd deplasarea prin surse. Deplasarea ntre mesajele de eroare se face utiliznd comenzile :cnext "i :cprev. Aceste comenzi func#ioneaz! "i dac! eroarea nu se afl! n fi"ierul curent (deschide automat fi"ierele care con#in eroarea). Comanda :copen mparte ecranul pe orizontal! "i deschide o fereastr! nou!, dedicat! afi"!rii erorilor. Pozi#ionarea cursorului pe o anumit! eroare, urmat! de un Enter sare n programul surs! la linia respectiv!. Navigarea ntre ferestre se face cu comenzile de deplasare cunoscute (h,j,k,l) precedate de Ctrl-w. nchiderea ferestrelor se face normal,:q. Fereastra cu erori poate fi creat! la momentul execu#iei Make dac! se folose"te comanda compus! :make | copen. Dac! se prefer! mp!r#irea ecranului pe vertical! se folose"te :make | vert copen. A"a cum am spus mai devreme, dac! fi"ierul executabil este mai nou dect toate fi"ierele de care depinde, Make va refuza s! l regenereze. Cu toate acestea, exist! situa#ii cnd acest lucru este dezirabil. n special cnd modifica#i fi"ierul makefile "i dori#i s! l testa#i. Linux pune la dispozi#ie o comand!, numit! touch, care are un singur rol: actualizeaz! informa#iile de timp ale fi"ierelor. Dac! executa#i comanda touch asupra fi"ierului surs! sau obiect, de exemplu touch prog.asm, fi"ierul va deveni mai nou dect fi"ierul executabil "i Make va repeta procesul de generare. Editorul Vim permite rularea comenzilor din linia sa de comand!. De exemplu, comanda anterioar! poate fi executat! din interiorul editorului tastnd :!touch prog.asm.

4.5.5. Execu!ia programului


Odat! fi"ierul binar ob#inut, l putem executa prin apelarea sa din linie de comand!: ./firstProg Probabil v! a"tepta#i s! nu se ntmple nimic. Instruc#iunile programului nu cer date de la tastatur! "i nici nu afi"eaz! ceva pe ecran. Programul nu face altceva dect s! introduc! date n cteva loca#ii de memorie "i s! transfere valori ntre registre "i memorie. Singurul mod n care putem verifica execu#ia programului este s! arunc!m o privire n interiorul calculatorului. Nu deschide#i carcasa, din fericire dispunem chiar de unealta de care avem nevoie: depanatorul GDB. Dar, pn! atunci, s! vorbim despre problemele care pot fi ntmpinate chiar dac! procesul de asamblare s-a desf!"urat f!r! eroare.

Gre!eli de programare Dac! n urma procesului de asamblare se ob"ine fi#ierul executabil, nseamn! c! din punct de vedere al sintaxei programul este corect. Aceasta nu nseamn! ns! c! programul va face ceea ce inten"iona programatorul s! fac!. Se spune c! programul care nu lucreaz! conform planului con"ine una sau mai multe gre#eli de programare (bug). O gre#eal! de programare este acel ceva din program care nu lucreaz! a#a cum a gndit programatorul s! lucreze. O eroare denot! prezen"a n fi#ierul surs! a ceva inacceptabil pentru asamblor sau editor de leg!turi. O eroare previne finalizarea cu succes a procesului de generare a fi#ierului executabil. n contrast, o gre!eal" de programare este o problem! descoperit! n timpul execu#iei unui program. Gre#elile de programare, sau de algoritm, nu sunt detectate de asamblor sau de editorul de leg!turi. Pot fi beningne, de exemplu cuvinte scrise gre#it ntr-un mesaj destinat afi#!rii pe ecran, sau pot cauza ntreruperea prematur! a programului. n unele cazuri, gre#elile de programare pot ntrerupe execu"ia programului f!r! mesaje de avertizare. n situa"iile n care opera"iile programului afecteaz! sistemul de operare (ncearc! s! acceseze zone de memorie protejate, etc.), acesta va ntrerupe programul #i va afi#a o eroare: Segmentation Fault Acest tip de eroare se nume#te eroare la rulare (runtime error). De cele mai multe ori ns!, programul nu va deranja sistemul de operare, va rula complet, dar rezultatul nu va fi cel a#teptat.

4.5.6. Depanarea fi!ierului executabil


Testarea programelor #i eliminarea erorilor de programare se face n cadrul unui proces numit depanare (debugging). Depanarea se refer! la procesul sistematic prin care sunt localizate #i corectate gre#elile de programare. Depanatorul este un program creat special n scopul localiz!rii #i identific!rii gre#elilor de programare. Permite nc!rcarea programului n memorie, execu"ia sa pas cu pas17 #i vizualizarea memoriei #i a registrelor procesorului. n Linux, depanatorul standard este GDB (GNU Debugger). Autorul este Richard Stallman, care a nceput dezvoltarea acestuia n anul 1988. Ruleaz! n linie de comand! #i a fost creat pentru a depana programe scrise n C/C++. Pentru a putea fi executat prin intermediul unui depanator, fi#ierul executabil trebuie s! fie asamblat cu op"iunea -g (include informa"ia de depanare).
17

Execu"ia programului se opre#te dup! efectuarea fiec!rei instruc"iuni ma#in!.

Nu orice executabil include aceast! informa"ie. n general, trebuie s! folosim informa"ii de depanare numai dac! vrem s! verific!m aplica"ia respectiv!. Chiar dac! executabilul creat cu op"iunea -g ruleaz! #i se comport! ca orice alt program asamblat f!r!, deoarece introduce n fi#ierul executabil informa"ie adi"ional!, executabilul devine mai mare #i mai lent. Presupunnd c! executabilul con"ine informa"ia de depanare necesar!, putem rula programul prin intermediul GDB astfel: gdb executabil GDB are o interfa"! de tip interpretor de comenzi ce permite execu"ia comenzilor de depanare. Prompt-ul (gdb) arat! c! se a#teapt! din partea programatorului introducerea unei comenzi de depanare. Ie#irea din GDB se face prin comanda quit. Putem lansa n execu"ie GDB f!r! s! furniz!m ca argument numele fi#ierului executabil. n acest caz, specificarea acestuia se face prin comanda file. stefan@laptop:~$ gdb GNU gdb (Ubuntu/Linaro 7.2-1ubuntu11) 7.2 Copyright (C) 2010 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. (gdb) GDB poate fi lansat n execu"ie cu op"iunea -q (quiet). n acest caz textul de prezentare nu mai este afi#at. stefan@laptop:~$ gdb -q (gdb) file prog Reading symbols from /home/stefan/prog...done. Comanda help arat! clasele de comenzi pe care le poate primi depanatorul. Afi#area comenzilor con"inute ntr-o clas! se face prin specificarea numelui acesteia imediat dup! comanda help. Descrierea unei comenzi se face prin acela#i procedeu, numai c! de aceast! dat!, dup! help specific!m numele comenzii. (gdb) help info variables

All global and static variable names, or those matching REGEXP. (gdb) help info registers List of integer registers and their contents, for selected stack frame. Register name as argument means describe only that register. Comanda list afi!eaz" codul surs" al programului, linia sau func#ia specificat". F"r" argument, afi!eaz" zece (num"rul implicit) sau mai multe linii aflate dup" sau n jurul liniei la care s-a ajuns n urma afi!"rii anterioare. (gdb) list 1 section .data 2 r db 3 a db 4 b db 5 c dw 6 d dw 7 e dd 8 f dd 9 g db 10 section .text

67 0fh 89 045E3h 65535 001234567h 1047000 0ffh

n cazul n care argumentul specific" o linie, sunt afi!ate zece linii n jurul acelei linii. (gdb) info source Current source file is prog.asm Located in /home/stefan/prog.asm Contains 29 lines. Source language is unknown. Compiled with stabs debugging format. Does not include preprocessor macro info. (gdb) list 19 14 mov al, 8h 15 mov bl,[r] 16 mov [r],al 17 mov eax, 1239054 18 mov bl,[b] 19 mov cx,[c] 20 mov edx,[e] 21 mov eax,a 22 mov ebx,b

23

mov [a],ah

mpreun! cu argumentul (liniu"!) afi#eaz! zece linii dinaintea pozi"iei la care s-a ajuns prin listarea anterioar!. (gdb) list 4 5 6 7 8 9 10 11 12 _start: 13 b db c dw d dw e dd f dd g db section .text global _start nop 89 045E3h 65535 001234567h 1047000 0ffh

Num!rul implicit de linii de afi#are poate fi schimbat cu ajutorul comenzii set. (gdb) set listsize 5 (gdb) show listsize Number of source lines gdb will list by default is 5. (gdb) list 14 mov al, 8h 15 mov bl,[r] 16 mov [r],al 17 mov eax, 1239054 18 mov bl,[b] Avem posibilitatea s! preciz!m exact regiunea dorit!. Urm!toarea comand! afi#eaz! tot programul. Num!rul total de linii al programului a fost deja aflat cu comanda info source. Comanda list a fost abreviat! cu l. (gdb) l 1,29 1 section .data 2 r 3 a 4 b ... 7 e 8 f 9 g

db db db dd dd db

67 0fh 89 001234567h 1047000 0ffh

10 11 12 13 ... 27 28 29

section .text global _start _start: nop mov eax,1 mov ebx,0 int 80h

Pentru a executa programul pas cu pas trebuie s! specific!m un punct de oprire. Punctul de oprire (breakpoint) stopeaz! execu"ia programului la acel punct din codul surs!. De acolo putem rula programul pas cu pas sau putem continua execu"ia obi#nuit!. Punctul de ntrerupere ne permite s! inspect!m starea programului la momentul respectiv. Punctele de ntrerupere pot fi specificate folosind num!rul de linie al codului surs!, numele unei func"ii sau o adres!. Comanda este break (se poate abrevia cu b). Putem ob"ine informa"ii cu privire la punctele de ntrerupere cu info breakpoints. (gdb) b 15 Breakpoint 1 at 0x8048083: file prog.asm, line 15. (gdb) b *_start+1 Breakpoint 2 at 0x8048081: file prog.asm, line 14. Observa!ie: b *_start+1 este comanda utilizat! de noi pentru toate exemplele din aceast! carte #i trebuie s! indice c!tre o instruc"iune NOP, altfel punctul de ntrerupere setat nu va fi luat n considerare (un bug al depanatorului GDB). (gdb) info b Num Type 1 breakpoint 2 breakpoint Disp Enb Address What keep y 0x08048083 in _start at prog.asm:15 keep y 0x08048081 in _start at prog.asm:14

Observa"i c! fiec!rui punct de ntrerupere i este atribuit un num!r (indice) care ne permite s! l adres!m. Coloana Disp (Disposition) descrie decizia care trebuie ndeplinit! de depanator cnd ajunge n punctul respectiv. Implicit, toate punctele de ntrerupere sunt executate (keep). Punctul de ntrerupere mai poate fi marcat cu dezactiveaz! (disable) sau #terge (delete). Coloana Enb (Enabled) specific! dac! punctul de ntrerupere este ini"ializat sau nu. Un y indic! faptul c! este ini"ializat. Adresa de memorie la care se afl! punctul de ntrerupere este dat! n coloana

Address, iar adresa din fi!ierul surs", afi!at" ca o combina#ie de nume de fi!ier !i num"r de linie, este dat" de ultima coaloan". Comanda tbreak (temporary break) seteaz" un punct de ntrerupere temporar. Un punct de ntrerupere temporar ntrerupe execu#ia programului o singur" dat", apoi este !ters. (gdb) tbreak 13 Temporary breakpoint 4 at 0x8048080: file prog.asm, line 13. (gdb) info b Num Type Disp Enb Address What 1 breakpoint keep y 0x08048083 in _start at prog.asm:15 2 breakpoint keep y 0x08048081 in _start at prog.asm:14 4 breakpoint del y 0x08048080 in _start at prog.asm:13 Comanda disable dezactiveaz" punctul de ntrerupere. Prime!te ca argument num"rul punctului de ntrerupere. F"r" argumente dezactiveaz" toate punctele de ntrerupere. Activarea unui punct de ntrerupere se face cu enable. (gdb) disable 2 (gdb) info b Num Type Disp Enb Address What 1 breakpoint keep y 0x08048083 in _start at prog.asm:15 2 breakpoint keep n 0x08048081 in _start at prog.asm:14 4 breakpoint del y 0x08048080 in _start at prog.asm:13 Ignorarea punctului de ntrerupere pentru un anumit num"r de ori se realizeaz" cu comanda ignore. Comanda ignore prime!te dou" argumente: num"rul punctului de ntrerupere ce trebuie ignorat !i num"rul de ori pentru care acesta este s"rit. $tergerea unui punct de ntrerupere se face cu comanda delete. Argumentul specific" num"rul punctului de ntrerupere !ters. Dac" nu sunt specificate argumente, !terge toate punctele de ntrerupere. (gdb) delete Delete all breakpoints? (y or n) y (gdb) info b No breakpoints or watchpoints. Lansarea n execu#ie a programului se face prin comanda run. Programul se opre!te la punctul de ntrerupere. De acolo putem continua execu#ia pas cu pas prin comanda next (abreviat" n) sau step (abreviat" s). De!i n cazul

programului actual next !i step se comport" la fel, ele sunt comenzi diferite. Pentru o linie de cod care apeleaz" o func#ie, next va s"ri peste func#ie, la urm"toarea linie de cod, n timp ce step va intra n func#ie. Execu#ia programului depanat poate fi oprit" oricnd cu comanda kill. Starea programului poate fi consultat" cu info program. (gdb) b *_start+1 Breakpoint 1 at 0x8048081: file prog.asm, line 14. (gdb) r Starting program: /home/stefan/prog Breakpoint 1, _start () at prog.asm:14 warning: Source file is more recent than executable. 14 mov al, 8h (gdb) n 15 mov bl,[r] (gdb) s 16 mov [r],al (gdb) info program Using the running image of child process 4717. Program stopped at 0x8048089. It stopped after being stepped. Continuare execu#iei se face cu ajutorul comenzii continue. Ie!irea din GDB se face prin comanda quit. Con#inutul registrelor este afi!at cu info registers, info registers $registru, info all-registers. Versiunile recente primesc ca parametru !i numele simplu al registrului, f"r" simbolul $. O abreviere util" este de genul i r ax. Tot de la versiunile mai noi se poate afi!a con#inutul registrelor mai mici dect cuvntul standard al arhitecturii (32 de bi#i). Eu am observat aceast" posibilitate de la versiunea 7.2. (gdb) info registers eax 0x8 8 ecx 0x0 0 edx 0x0 0 ebx 0x4367 esp 0xffffd400 0xffffd400 ebp 0x0 0x0 esi 0x0 0

edi 0x0 0 eip 0x8048089 0x8048089 <_start+9> eflags 0x202 [ IF ] cs 0x23 35 ss 0x2b 43 ds 0x2b 43 es 0x2b 43 fs 0x0 0 gs 0x0 0 (gdb) info registers $eax eax 0x8 8 (gdb) info registers $eax $ebx $ecx eax 0x8 8 ebx 0x4367 ecx 0x0 0 (gdb) i r al Comanda care afi!eaz" valorile loca#iilor de memorie este x (examine). Este o comand" complex", care poate primi mai mul#i parametrii op#ionali. Apare n urm"toarea form": x /nyz &etichet! unde: n n reprezint" num"rul de linii de afi!at, y descrie formatul n care se dore!te afi!area, z descrie m"rimea unit"#ii n care se dore!te afi!area.
Tabel 4.3: Detalii cu privire la parametrii op!ionali

Num"r de repeti#ie (ntreg zecimal) Specific" num"rul de unit"#i de memorie (n z) care trebuie afi!at. Valoarea implicit" este 1. Formatul afi!"rii x hexazecimal d zecimal (decimal) u zecimal f"r" semn (unsigned decimal) o octal t binar (two) afi!eaz" adresa att n zecimal ct !i ca deplasament fa#" de cel a mai apropiat simbol precedent. c afi!eaz" sub form" de caractere (character)

s afi!eaz" ca !ir terminat n caracterul 0 t afi!eaz" ca num"r n virgul" mobil" i afi!eaz" ca instruc#iune n cod ma!in" Valoarea implicit" este x. Valoarea implicit" se schimb" de fiecare dat" cnd este folosit" comanda x. M"rimea unit"#ii b octe#i (byte) h 2 octe#i sau jum"t"#i de cuvnt (half-word) w 4 octe#i sau cuvnt de 32 de bi#i (word) g 8 octe#i sau cuvnt gigant (giant word) Valoarea implicit" este w. Valoarea implicit" se modific" automat la fiecare unitate care este specificat" cu comanda x.

(gdb) x /1db &r 0x80490d0 <r>: (gdb) x /1xb &r 0x80490d0 <r>: (gdb) x /1dt &r 0x80490d0 <r>: (gdb) x /1c &r 0x80490d0 <r>: (gdb) x /4db &r 0x80490d0 <r>: (gdb) x /4xb &e 0x80490d7 <e>:

67 0x43 01000011 67 'C' 67 0x67 15 0x45 89 0x23 -29 0x01

Comanda care poate afi!a att valoarea unui registru ct !i a unei loca#ii de memorie este print. Comanda print poate folosi parametrii op#ionali de formatare a afi!"rii. Registrele primite ca argument trebuie precedate de caracterul $ (dollar). (gdb) print /x $eax $4 = 0x12e80e (gdb) print /d $ebx $5 = 89 (gdb) print /t $ecx $6 = 100010111100011 n cazul loca#iilor de memorie, o etichet" simpl" dat" ca argument duce la afi!area valorii, o etichet" precedat" de caracterul & (ampersand) arat" adresa loca#iei de memorie respective.

(gdb) print /x &e $11 = 0x80490d7 (gdb) print /x e $12 = 0x1234567 Dac! sunte"i obi#nui"i cu limbajul de programare C, comanda printf v! este deja cunoscut!. Comanda poate executa o expresie de afi#are complex!, utiliznd un format #ir cu specificatori de conversie exact ca la func"ia ANSI C, printf(). (gdb) printf "%d\n",r 3 (gdb) printf "%d\n", $eax 8 (gdb) printf "%x\n", &r 80490d0 Comanda backtrace (abreviat! bt) afi#eaz! lista func"iilor invocate din programul principal pn! n momentul respectiv. Lista con"ine cte o linie pentru fiecare cadru de stiv! (stack frame). Comenzile frame #i info frame ne permit s! examin!m con"inutul cadrelor de stiv!. Selectarea unui cadru se face prin specificarea num!rului s!u ca argument pentru comanda frame. Odat! selectat, putem observa ce con"ine cu ajutorul comenzii info frame. Depanatorul poate dezasambla o sec"iune de memorie specificat!. Poate primi ca argument o adres!, de exemplu _start. n mod implicit, zona de memorie este afi#at! n sintaxa AT&T. Prima comand! din urm!toarea secven"! schimb! modalitatea de reprezentare. (gdb) set disassembly-flavor intel (gdb) disassemble _start Dump of assembler code for function _start: 0x08048080 <+0>: nop 0x08048081 <+1>: mov eax,0x80490c8 0x08048086 <+6>: mov ebx,DWORD PTR ds:0x80490c8 End of assembler dump. Ca s! nu fim nevoi"i s! specific!m sintaxa dorit! la fiecare deschidere a depanatorului, scrie"i ntr-un terminal urm!toarea comand!: echo "set disassembly-flavor intel" > ~/.gdbinit

4.6. ntreb!ri "i exerci#ii


4.1. Care este structura unui program n limbaj de asamblare? 4.2. Care este diferen!a dintre program "i proces? 4.3. Care este diferen!a ntre datele ini!ializate "i neini!ializate? 4.4. Conform c#rui criteriu aranjeaz# un procesor Intel x86 octe!ii de date n memorie? 4.5. Pentru fiecare din urm#toarele declara!ii, reprezenta!i harta memoriei. msg dw Introduceti primul numar: d dd 123 w dw AB sir db ABCD 4.6. Ce nseamn# ELF "i STABS n linia de asamblare? 4.7. Ce este un mesaj de eroare? Prin ce se diferen!iaz# acesta de mesajele de aten!ionare? 4.8. Ce rol are op!iunea m elf_i386 din linia editorului de leg#turi? 4.9. Ce rol are un depanator? Cu ce op!iune trebuie s# asambl#m un program astfel nct s# l putem depana? 4.10. Ce este un punct de ntrerupere? 4.11. Ce rol are utilitarul Make? 4.12. Cum se execut# un program din linie de comand# n Linux?

5. MEMORIA

Acest capitol demonstreaz! modul de declarare a datelor n program "i importan#a alinierii acestora n memorie. Discut! n detaliu diferite metode de adresare disponibile la procesoarele Intel de 32 de bi#i "i descrie modul de implementare $i manipulare n limbaj de asamblare a vectorilor. Din perspectiva unui programator n asamblare, acest capitol, deoarece prezint! metodele de adresare a memoriei, este unul din cele mai importante, dac! nu cel mai important.

5.1. Declararea datelor n bloc


Prefixul TIMES permite repetarea unei instruc!iuni sau pseudoinstruc!iuni de un num"r specificat de ori. n exemplul de mai jos, TIMES repet" de 100 de ori pseudoinstruc!iunea db 0, rezultnd un buffer de 100 de octe!i de 0. Pentru ob!inerea aceluia#i rezultat, dar f"r" prefixul TIMES, ar fi trebuit s" scriem dup" directiva DB o sut" de cifre de zero separate prin virgul". N-ar fi fost foarte pl"cut. buffer: times 100 db 0

Dar TIMES este mai versatil dect att. Argumentul lui TIMES (n exemplul precedent argumentul a fost 100) nu este o constant" numeric", ci o expresie numeric". n consecin!", se pot construi propozi!ii mult mai complexe. buffer: times db 'Rezervat:' 19-$+buffer db '-'

Expresia 19-$+buffer se evalueaz" la 10, a#adar se repet" de 10 ori db '-'(caracterul liniu!"). n final, n memorie vom avea secven!a: Rezervat:----------. Sunt #i situa!ii n care nu este indicat" folosirea prefixului TIMES. De exemplu, propozi!iile times 100 resb 1 #i resb 100 au acela#i rezultat, numai c" ultima, din cauza structurii interne a asamblorului, este asamblat" de 100 de ori mai rapid. Totu#i, ca s" nu fim acuza!i de partizanat, programul care demonstreaz"

faptul c! datele neini"ializate sunt alocate la momentul rul!rii, #i nu asambl!rii, folose#te la rezervarea ambelor tipuri de date prefixul TIMES. n primul rnd, s! verific!m m!rimea programului ini"ial. ; ;testMarime.asm ; section .text global _start _start: nop mov eax,1 mov ebx,0 int 80h Asambla"i cu make #i observa"i m!rimea acestuia. ls -l testMarime -rwxr-xr-x 1 ubuntu users 992 2011-02-19 21:59 testMarime Dimensiunea fi#ierului executabil este de 992 de octe"i. Ad!ug!m programului 8 MB de octe"i neini"ializa"i #i ob"inem executabilul. ; ;testMarime.asm ;+8192 octe!i neini!ializa!i section .bss buffer: times 8192 resb 1 ;se poate folosi buffer: resb 8192 section .text global _start _start: nop mov eax,1 mov ebx,0
int 80h

ls -l testMarime -rwxr-xr-x 1 ubuntu users 1075 2011-02-19 22:05 testMarime A#adar, am ad!ugat un buffer de 8192 de octe"i, dar m!rimea programului a crescut cu numai 83 de octe"i. S! test!m m!rimea programului la care au fost ad!uga"i 8192 de octe"i ini"ializa"i cu 0. ; ;testMarime.asm

;+8192 octe!i ini!ializa!i cu caracterul 0 section .data buffer: times 8192 db '0' section .text global _start _start: nop mov eax,1 mov ebx,0
int 80h

n urma procesului de asamblare !i editare de leg"turi observ"m c" buffer-ul de 8192 de octe#i este ad"ugat fi!ierului executabil. ls -l testMarime -rwxr-xr-x 1 ubuntu users 9271 2011-02-19 22:05 testMarime

5.2. Adresarea memoriei n modul protejat


Principala instruc#iune de care ne-am folosit pn" acum a fost instruc#iunea MOV. MOV necesit" doi operanzi !i are urm"toarea sintax": mov destina!ie,surs" n sintaxa Intel, operandul aflat lng" numele instruc#iunii este operandul destina#ie. Datele sunt copiate de la surs" la destina!ie, iar operandul surs" r"mne neschimbat. Observa#i c" am eviden#iat cuvntul copiate. Din nefericire, numele instruc#iunii, prin faptul c" pronun#ia, !i chiar aspectul, seam"n" cu cel al cuvntului englezesc move, care nseamn" a muta, n!eal" pe mul#i. Datele nu sunt mutate, ci copiate de la surs" la destina#ie. La final, vom avea aceea!i valoare n dou" locuri, n surs" !i n destina!ie. Instruc#iunea MOV poate copia date cu capacitatea de un octet, un cuvnt sau dublu cuvnt, ntre registrele procesorului sau ntre registre !i memorie. Aten#ie, MOV nu poate copia date ntre dou" loca#ii de memorie. Pentru aceasta este nevoie de un registru intermediar !i de dou" instruc#iuni MOV una copiaz" valoarea din memorie n registru, !i alta parcurge traseul invers. MOV nu e singura instruc#iune care respect" regulile de mai sus. Aproape fiecare instruc#iune din setul de instruc#iuni poate opera pe octet, cuvnt sau dublu cuvnt, iar atunci cnd prime!te doi operanzi, ace!tia nu pot fi n acela!i timp

loca!ii de memorie. Opera!iile cu ambii operanzi n memorie sunt excluse, cu excep!ia opera!iilor pe "iruri "i a opera!iilor cu stiva.

5.2.1. Adresare imediat! "i adresare la registre


Pn# acum am ntlnit dou# forme ale instruc!iunii MOV: transfer de date ntre registre: mov eax,ebx ;copiaz# valoarea din registrul EBX n registrul EAX

introducere operand imediat n registru: ;introducem imediatul 1 n registrul EAX ;introducem imediatul 0 n registrul EBX

mov eax,1 mov ebx,0

Un imediat este o valoare specificat# direct n corpul instruc!iunii. Acest fenomen poart# numele de adresare imediat!. Modul de adresare specific! criteriul folosit la calculul adresei unui operand (modul n care sunt specifica"i operanzii unei instruc"iuni). Numele de adresare imediat! provine de la faptul c# operandul este prezent chiar n corpul instruc!iunii ma"in#. Procesorul nu trebuie s# extrag# valoarea operandului separat, dintr-un registru sau dintr-o loca!ie de memorie, imediatul este inclus n instruc!iunea extras# "i executat#. MOV EAX,EBX semnific# faptul c# adresa operandului surs# este adresa unui registru de uz general, adic# operandul se g#se"te ntr-un registru. Acest mod de adresare se nume"te adresare la registre. n completarea regulilor deja enun!ate, ad#ug#m "i faptul c# dimensiunea operanzilor surs! #i destina"ie trebuie s! corespund!. De exemplu, un imediat de 16 bi!i nu poate fi introdus ntr-un registru de 8 bi!i. Instruc!iunea MOV AL,0FA95H este ilegal#. De asemenea, numai operandul surs# poate fi un imediat. Asamblorul sanc!ioneaz# toate gre"elile de acest fel. Din acest punct de vedere asamblorul este un pedagog foarte exigent. Transferul datelor ntre registre este un proces simplu. Nu se poate spune acela"i lucru despre transferul datelor ntre registre "i memorie. Primul lucru de care trebuie s# !inem cont este modul de reprezentare al adresei de memorie n corpul instruc!iunii. Ne amintim c# eticheta directivei de date reprezint# adresa loca!iei de memorie la care este stocat# valoarea. A"adar, o instruc!iune de forma mov ebx, d ;introduce n registrul EBX adresa d stocheaz# n registrul EAX adresa d, nu valoarea adresat# de aceasta. De"i

este util, de cele mai multe ori dorim s! transfer!m valoarea, nu adresa. Pentru a ob"ine valoarea, numele etichetei trebuie introdus ntre paranteze p!trate. mov eax,[d] ;introduce n registrul EAX valoarea adresat! de d mov ecx,[ebx] ;introduce n registrul ECX valoarea adresat! de registrul EBX Al doilea lucru care trebuie luat n considerare la transferul de date ntre memorie #i registre este dimensiunea datelor transferate. Instruc"iunea de mai sus extrage de la o adres! de memorie un num!r de bi"i de date. Num!rul de bi"i de date transferat de la adresa d n registrul EAX nu este specificat direct n corpul instruc"iunii. Con"inutul loca"iei de memorie adresate de eticheta d poate avea dimensiunea de un octet, un cuvnt, un dublu cuvnt, un quad, etc.. Programatorul a presupus c! valoarea adresat! prin eticheta d este reprezentat! pe 4 octe"i #i a folosit registrul EAX. Dac! programatorul dorea s! extrag! din memorie 8 bi"i de date folosea ca destina"ie un registru de 8 bi"i, precum AL. Dimensiunea registrului specific! num!rul de bi"i extra#i din memorie, sau, altfel spus, dimensiunea datelor este dedus! pe baza registrului destina"ie. ; ;MemReg.asm ; section .data b db 55h w dw 0ABCDh d dd 12345678h section .text global _start _start: nop ;ncarc! n eax adresa variabilei b mov eax, b ;ncarc! n ebx adresa variabilei w mov ebx, w ;ncarc! n ecx adresa variabilei d mov ecx, d ;ncarc! n SI valoarea 0CD55H (16 bi"i de date ncepnd cu adresa b) mov si, [b] ;ncarc! n DI valoarea 0ABCDH mov di, [w] ;ncarc! n EDX valoarea 12345678H mov edx, [d]

;ncarc! n EBP valoarea 5678abcdh (32 de bi"i de date ncepnd cu adresa w) mov ebp, [w] mov eax, 1 mov ebx, 0 int 80h Transferul datelor din registre n memorie folose#te o abordare similar!. mov [d],ecx ;ncarc! la adresa d octe"ii afla"i n ecx Instruc"iunea copiaz! 4 octe"i de date din registrul ECX n loca"ia de memorie specificat! de eticheta d. La fel ca nainte, instruc"iunea introduce n memorie con"inutul unui registru de 4 octe"i, a#adar va folosi 4 octe"i de memorie. Completa"i programul anterior cu urm!toarele instruc"iuni #i rula"i pas cu pas. Observa"i efectele. Desena"i noua hart! a memoriei. mov al, 13 mov [b], al mov bx, 65535 mov [w], bx mov ecx, 0aabbccddh mov [d], ecx ;mov ebp, 0 ;mov [b], ebp Activa"i ultimele dou! instruc"iuni #i vizualiza"i efectele. O directiv! de date poate introduce n memorie mai mult de o singur! valoare. De exemplu, directiva valori: dw 10,20,30,40,50,60 introduce n memorie o secven"! de valori, fiecare valoare ocup! o unitate de memorie egal! cu 2 octe"i. Reprezentarea memoriei, conform conven"iei littleendian, este dat! mai jos. Presupunem c! adresa de nceput, etichetat! valori, este 0x8049094.

Valoare 0 60 0 50 0 40 0 30 0 20 0 10
7 0

Adres! 0x804909e 0x804909c 0x804909a 0x8049098 0x8049096 valori

Prima valoare se acceseaz! simplu: adresa este precizat! direct n instruc"iune, prin intermediul etichetei valori. n schimb, extragerea altor valori din vector, de exemplu, elementul 40, necesit! un mod de adresare mai special, n sensul c! adresa fiec!rei loca"ii de memorie se determin! pe baza urm!toarelor elemente: adresa de nceput a vectorului, numit! adres! de baz! (baz!); un deplasament (n vector), care se adun! la adresa de baz! (deplasament); m!rimea elementului de date num!rul de octe"i pe care este reprezentat elementul (scal!); un index, care determin! elementul selectat (index). Indexul reprezint! pozi"ia elementului n #ir, num!rnd de la zero. Formatul complet al expresiei este: [baz! + index " scal! + deplasament] EAX EBX ECX EDX ESI EDI EBP ESP EAX EBX ECX EDX ESI EDI EBP 1 2 4 8 f!r! deplasament deplasament pe 8 bi#i deplasament pe 32 de bi#i

A#adar, adresa loca"iei de memorie corespunz!toare valorii dorite se ob"ine

adunnd baz! + deplasament + index " scal!. Sunt valabile urm!toarele reguli: baza "i indexul pot fi reprezentate de oricare din registrele de uz general de 32 de bi#i; deplasamentul poate fi reprezentat de orice constant! de 32 de bi#i (evident, valoarea 0, de"i legal!, este inutil!); scala trebuie s! fie una din valorile 1, 2, 4, sau 8 (valoarea 1 este legal!, dar nu aduce niciun beneficiu, a"adar nu este precizat! niciodat!); toate elementele expresiei sunt op#ionale "i pot fi utilizate n aproape orice combina#ie; nu pot fi utilizate registre de 16 sau 8 bi#i. Tabelul 5.1 rezum! metodele prin care poate fi specificat! o adres! de memorie n modul protejat. Cu excep#ia primelor dou!, pe care deja le-am ntlnit, toate celelalte implic! un mic calcul aritmetic ntre doi sau mai mul#i termeni, proces numit calculul adresei efective. Procesul de calcul se finalizeaz! cu ob#inerea adresei efective. Termenul adres! efectiv! ilustreaz! faptul c!, n cele din urm!, aceasta este adresa care va fi folosit! la citirea sau scrierea memoriei, indiferent de modul n care este exprimat! (format!). Calculul adresei efective se face la momentul execu#iei instruc#iunii ce con#ine expresia.
Tabelul 5.1 Moduri de adresare a memoriei

Schem! [baz!] [deplasament] [baz! + deplasament] [baz! + index] [index $ scal!] [index $ scal! + deplasament] [baz! + index $ scal!] [baz! + index $ scal! + deplasament] Adresarea indirect!

Exemplu [edx] [etichet!] sau [0x8049094] [ebx + 0FH] [eax + ebx] [ecx $ 2] [eax $ 4 + 32]

Descriere Numai baz! Deplasament, adres! simbolic! sau explicit! Baz! plus constant! Baz! plus index Index nmul#it cu scal! Index nmul#it cu scal! plus deplasament [ebp + edi $ 2] Baz! plus index nmul#it cu scal! [esi + ebp $ 4 + 1] Baz! plus index mnul#it cu scal!, plus deplasament

Primul caz presupune c! adresa efectiv! este reprezentat! de valoarea unui registru de uz general aflat ntre paranteze p!trate. Am v!zut deja c!, pe lng! date, registrele pot con#ine adrese de memorie. Registrul care con#ine o adres! de

memorie se nume!te indicator (pointer). Accesarea datelor stocate n loca"ia de memorie indicat# de adresa din registru se nume!te adresare indirect!. Poate fi folosit oricare din registrele EAX, EBX, ECX, EDX, EBP, EDI sau ESI. Modul n care stoc#m o adres# ntr-un registru a fost ntlnit n programul memReg.asm. A!adar, instruc"iunea mov ecx,valori va avea ca rezultat stocarea adresei 0x8049094 n registrul ECX. Cum adresele IA-32 sunt reprezentate pe 32 de bi"i, registrul trebuie s# fie unul de 32 de bi"i. Programul care urmeaz# stocheaz# n registrul AL primul octet din vectorul valori. ; ;indirecta.asm ; section .data valori: dw 10,20,30,40,50,60 section .text global _start _start: nop mov ecx, valori mov al, [ecx] ;AL = 0ah (adresare indirect#) ;mov bl, 255 ;BL = 0ffH ;mov [ecx], bl ;primul octet din vector devine 0ffH mov eax,1 mov ebx,0 int 080h Instruc"iunile comentate introduc n memorie, la adresa de nceput a vectorului, valoarea 255. n locul celor dou# ncerca"i s# folosi"i instruc"iunea mov [ecx], 255 Asamblorul va semnala o eroare: error: invalid size for operand 1 Ceea ce asamblorul ncearc# s# ne spun# este c# nu poate determina dimensiunea loca"iei de memorie la care trebuie s# introduc# valoarea 255. I s-a specificat

adresa, dar nu !i num"rul de octe#i. Acesta este rolul operatorilor de dimensiune. YASM pune la dispozi#ie 5 operatori de dimensiune: BYTE, WORD, DWORD, QWORD, TWORD. Ace!tia sunt folosi#i atunci cnd exist" ambiguit"#i cu privire la num"rul de octe#i pe care trebuie reprezentat n memorie un imediat. n cazul nostru, nu reiese clar dac" introducem n memorie un octet, un cuvnt, etc.. Operator de dimensiune BYTE WORD DWORD QWORD TWORD Pentru o valoare de 255, un octet este suficient: mov [ecx], byte 255 A!a cum reiese din intruc#iuni, chiar dac" adresarea indirect" nu necesit" vreun calcul al adresei efective, adresa nu apare n clar !i nici codificat" simbolic. De fapt, singura form" sub care este posibil ca adresa efectiv" s" apar" n clar este aceea de adres" explicit" scris" ntre paranteze p"trate: mov eax, [0x8049094] Acest mod de adresare direct! este aproape imposibil, deoarece n momentul asambl"rii este extrem de improbabil s" cuno!ti adresa exact". Aproape ntotdeauna vei cunoa!te codificarea simbolic" a adresei (eticheta). Sistemul de operare mapeaz" eticheta la adres" n momentul nc"rc"rii programului n memorie. Adresarea direct! prin deplasament Acesta a fost primul mod de adresare al memoriei ntlnit n aceast" carte. Adresa efectiv" a operandului se ob#ine din cmpul deplasament. S" ne amintim: mov [b], al mov [w], bx n acela!i mod, mov bx, [valori] Octe!i adresa!i 1 2 4 8 10

introduce n registrul BX valoarea 10. Principala caracteristic! a termenului deplasament este c! nu se afl! ntr-un registru. Un caz particular al acestui mod de adresare se ntlne"te atunci cnd adun!m la deplasament un num!r ntreg. mov ax, [valori + 2] Pare c! adresa efectiv! se formeaz! prin adunarea a dou! deplasamente. ns! YASM, la momentul asambl!rii, combin! cele dou! valori, sau mai multe, ntr-un singur deplasament. n cazul prezentat, pur "i simplu adaug! 2 la adresa simbolic! valori. Adresa ob#inut! va fi 0x8049094 + 2 = 0x8049096, adic! adresa primului octet al celui de al doilea element din vector. n registrul AL vom avea valoarea 20. Am precizat ntr-un capitol precedent c! putem accesa toate valorile unui "ir, sau vector, numai prin cunoa"terea adresei de nceput. Trebuie numai s! #inem cont de m!rimea elementelor. Cum fiecare element din "irul dat ca exemplu are 2 octe#i, elementul 6 din vector poate fi extras cu instruc#iunea mov ax, [valori + 10] Elementul 6 este num!rul 60. ; ;directa.asm ; section .data valori: dw 10,20,30,40,50,60 section .text global _start _start: nop mov di, [valori] mov ax, [valori+2] ;copiaz! n ax elementul 2 (20) mov bx, [valori+4] ;copiaz! n bx elementul 3 (30) mov cx, [valori+6] ;copiaz! n cx elementul 4 (40) mov dx, [valori+8] ;copiaz! n dx elementul 5 (50) mov si, [valori+10] ;copiaz! n si elementul 6 (60) mov eax,1 mov ebx,0 int 080h S! consider!m instruc#iunea:

mov [d], 1 ;valid!, adresare direct! prin deplasament n momentul asambl!rii, YASM va afi"a o eroare: operation size not specified Asamblorul nu "tie dac! 1 nseamn! 01H, 0001H sau 00000001H. Altfel spus, nu cunoa"te dimensiunea lui 1. d este o etichet!, o adres! de memorie. O etichet! nu are tip, nu denot! o dimensiune. De aceea, trebuie s! specific!m dimensiunea operanzilor imedia#i. mov dword [d], 1 ;1 este reprezentat pe 4 octe#i mov byte [b], 1 ;1 este reprezentat pe 1 octet mov [w], dword 'G' ;caracterul G este reprezentat pe doi octe#i "i introdus n loca#ia de memorie etichetat! cu w. Adresarea bazat! (baz! + deplasament) O alt! modalitate simpl! de calcul a adresei efective este s! adun!m o constant! la con#inutul unui registru. ; ;bazata.asm ; section .data valori: dw 10,20,30,40,50,60 section .text global _start _start: nop mov ebx, valori mov ax, [ebx+4] ;copiaz! n AX elementul 3 (30) mov cx, [ebx+6] ;copiaz! n CX elementul 4 (40) mov edx,2 mov bx,[valori+edx] ;copiaz! n BX elementul 2 (20) mov ax,[valori+edx+8] ;copiaz! n AX elementul 5 (50) mov eax,1 mov ebx,0 int 080h

Descrierea acestei metode de calcul, baz! + deplasament, este confuz!. n majoritatea cazurilor, cuvntul deplasament denot! o adres! (gndi"i-v! la adresarea direct! prin deplasament), n schimb, aici are rolul pur #i simplu de o constant! (o deplasare fa"! de adresa de baz!). Aceast! constant! poate fi reprezentat! de un ntreg sau de numele vectorului. n programul bazata.asm, primul mod de acces la elementele vectorului se face prin nc!rcarea n EBX a adresei de baz! #i adunarea sa cu un indice explicit. Al doilea mod de acces necesit! o scurt! discu"ie. Din punct de vedere al mecanismului de adresare, n EDX se afl! o adres! de baz!, iar valori este o constant! de 32 de bi"i. La toat! aceast! construc"ie se poate ad!uga u#or o alt! constant! explicit! (8). A#adar, din perspectiva mecanismului de adresare, exist! un termen baz! (EDX) #i un termen de deplasare (valori). ns!, din perspectiva programului care acceseaz! elementele vectorului, semnifica"ia este invers!: valori este adresa de baz!, iar EDX un indice (deplasament). Adresarea indexat! Adresa efectiv! se ob"ine prin adunarea a dou! registre de uz general, unul baz! #i unul index. ; ;indexata.asm ; section .data valori: db 10,20,30,40,50,60 section .text global _start _start: nop mov ebp, valori mov ecx, 4 mov ax, [ebp+ecx] ;copiaz! n AX elementul cu index 4 (50) mov word [ebp+ecx], 70 ;ncarc! 70 n loca"ia cu index 4 mov eax,1 mov ebx,0 int 080h Acest mod de adresare este utilizat de obicei pentru parcurgerea unui vector octet cu octet. Registrul baz! marcheaz! nceputul vectorului, iar registrul index, incrementat ntr-o bucl!, selecteaz! elementul. Denumirea index trebuie n"eleas! ca pozi"ia elementului n vector, numrnd de la zero. Cuvntul vector

este un termen general pentru buffer sau tablou: o secven!" de elemente de date aflate n memorie, toate de acela#i tip #i m"rime. Dar dac" trebuie s" parcurgem un vector ale c"rui elemente nu sunt reprezentate pe un singur octet, ci pe cuvinte sau dublu cuvinte? Aici intr" n scen" conceptul de scal!. Urm"torul listing arat" modul n care depanatorul interpreteaz" adresarea indexat" n contextul formulei: [baz! + index " scal! + deplasament] (gdb) disassemble _start Dump of assembler code for function _start: 0x08048080 <+0>: nop => 0x08048081 <+1>: mov ebp,0x80490a4 0x08048086 <+6>: mov ecx,0x4 0x0804808b <+11>: mov ax,WORD PTR [ebp+ecx*1+0x0] 0x08048090 <+16>: mov WORD PTR [ebp+ecx*1+0x0],0x46 0x08048097 <+23>: mov eax,0x1 0x0804809c <+28>: mov ebx,0x0 0x080480a1 <+33>: int 0x80 End of assembler dump. Registrul index este nmul!it implicit cu un factor de scal!. Pentru c" nu am specificat n instruc!iune multiplicatorul dorit, asamblorul a presupus c" factorul de scal! este egal cu 1. A#adar, adresa efectiv" este suma dintre baz" #i produsul registrului index cu factorul de scal". n mod obi#nuit, factorul de scal" este egal cu m"rimea elementelor individuale din vector. Dac" vectorul const" din cuvinte de 2 octe!i, scala ar trebui s" fie 2. Dac" vectorul con!ine cuvinte de 4 octe!i, scala ar trebui s" fie 4. Pentru elementele de tip quad, scala este 8. S" presupunem c" avem un #ir de 100 de elemente, fiecare de 4 octe!i, #i c" dorim s" extragem elementele 73, 84 #i 98. Ct adun"m la baz"? n primul rnd, deoarece elementele sunt cuvinte de 32 de bi!i, nseamn" c" factorul de scal! este 4. Nu mai trebuie dect s" specific"m indexul elementelor dorite cu ajutorul unui registru de uz general (altul dect cel folosit pentru baz!). Aminti!i-v" c" indexul ncepe de la 0. A#adar, primul element din vector are index 0, al doilea element index 1, #.a.m.d.. Programul exemplific" #i alt" form" de adresare indexat", [index $ scal" + deplasament]. ; ;scala.asm ; section .data x equ 1

y equ 2 z equ 3 buff: times 80 dd x times 10 dd y times 10 dd z section .text global _start _start: nop

;80 de cuvinte de 32 de bi!i cu valoarea 1 ;10 cuvinte de 32 de bi!i cu valoarea 2 ;10 cuvinte de 32 de bi!i cu valoarea 3

;adresarea prin deplasament+index*scal" mov edi, 72 mov esi, [buff+edi*4] ;adresarea prin baz"+index*scal" mov eax, buff mov edi, 83 mov ebx, [eax+edi*4] mov edi, 97 mov ecx, [eax+edi*4] mov eax,1 mov ebx,0 int 080h Adresarea bazat! "i indexat! Adresa efectiv" se ob!ine prin adunarea unui registru de baz" cu un registru index, plus o constant" de 32 de bi!i. Acesta este #i ultimul mecanism de calcul al adresei efective amintit (din cele 11 prezente la procesoarele 80386). n definitiv, deocamdat" conteaz" s" n!elege!i cum se calculeaz" adresa efectiv", pute!i ignora numele metodelor. Re!ine!i c" toate metodele folosesc ca punct de plecare aceea#i formul". Instruc!iunea LEA (Load Effective Address) Adresa efectiv" poate fi nc"rcat" ntr-un registru #i prin instruc!iunea LEA. Sintaxa acestei instruc!iuni este lea registru,[expresie]

Instruc!iunea LEA calculeaz" adresa efectiv" prin evaluarea expresiei aflat" ntre parantezele p"trate (dat" ca operand surs") #i ncarc" aceast" adres" ntr-un registru de uz general, de 32 de bi!i, dat ca operand destina!ie. Astfel, n loc de instruc!iunea mov ebx, valori se poate folosi lea ebx, [valori] Diferen!a ntre cele dou" instruc!iuni este c" varianta cu LEA calculeaz" valoarea deplasamentului la rulare, n timp ce varianta cu MOV, la asamblare. Din acest motiv, varianta cu MOV se folose#te de fiecare dat" cnd este posibil. Totu#i, LEA este mai flexibil" n ceea ce prive#te tipul operanzilor surs!. De exemplu, pentru a introduce n EBX adresa elementului al c"rui index se afl" n registrul ESI, putem scrie lea ebx, [valori+ESI] Echivalentul mov ebx, valori+ESI este ilegal, deoarece con!inutul lui ESI este cunoscut de abia la rulare. Pe de alt" parte, ne amintim c", n memorie, intr"rile individuale nu au etichet". n consecin!", nu pot fi accesate direct. LEA poate ob!ine adresa efectiv" a oric"rui octet individual din memorie. Instruc!iunea LEA permite #i realizarea rapid" a unor opera!ii aritmetice, f"r" a fi nevoie de utilizarea instruc!iunilor de adunare sau nmul!ire. De exemplu, expresia aritmetic" x = x + y " 8, presupunnd c" valoarea lui x se g"se#te n registrul EAX #i valoarea lui y n registrul EBX, poate fi calculat" rapid prin lea eax, [eax + ebx * 8] Nu numai c" opera!ia este efectuat" mai rapid dect n cazul utiliz"rii instruc!iunilor aritmetice dedicate, dar este #i mai lizibil" opera!ia efectuat" se deduce imediat. Nu are importan!" c" rezultatul final nu reprezint" o adres". LEA nu ncearc! s! acceseze elementul stocat la adresa pe care o calculeaz!. Pur #i simplu, efectueaz" opera!ia matematic" cuprins" ntre paranteze #i stocheaz" rezultatul n operandul destina!ie (rezultatul poate reprezenta o adres" sau nu).

5.3. Optimizarea accesului la memorie


Accesul la memorie este unul din cele mai lente procese ndeplinite de procesor. Cnd programele au cerin!e ridicate de performa!" este bine s" p"str"m datele n registre #i s" evit"m accesul la memorie ct mai mult posibil. Cel mai rapid mod de tratare a datelor este s" le transfer"m ntre registre. Dac" p"strarea datelor n registre nu reprezint" o op!iune viabil" (nu dispunem de un num"r suficient de registre), trebuie s" ncerc"m s" optimiz"m procesul de extragere a acestora din memorie. Am nv"!at s" privim memoria ca #ir liniar de octe!i. Cndva, memoria chiar a#a era organizat" #i adresat", dar pentru procesoarele familiei 80386 aceast" imagine nu se mai reflect" n hardware. De fapt, dimensiunea unei loca!ii de memorie de un singur octet este o fic!iune ntre!inut" n beneficiul dezvoltatorilor de programe. De#i memoria este for!at" s" emuleze un cuvnt de 8 bi!i, cuvintele propriu zise sunt de 32 de bi!i (patru octe!i) - dimensiunea magistralei de adrese. Dar, #i n acest caz, primii doi bi!i ai magistralei de adrese nu sunt prezen!i. Liniile magistralei de adrese sunt de la A31 la A2. A1 #i A0 lipsesc. Din punct de vedere hardware, un procesor 80386 adreseaz" !!" cuvinte de 32 de bi!i. Memoria de !!" !! bi!i este o fic!iune. Din cauza acestui mod de organizare hardware, procesorul cite#te sau scrie eficient loca!iile de memorie organizate n anumite blocuri specifice, ncepnd cu prima adres" a segmentului de date. De exemplu, un procesor de 32 de bi!i acceseaz" cel mai repid datele pozi!ionate la adrese cu primii doi bi!i de 0 (cei inexisten!i, liniile A0 #i A1). Datele aliniate sunt datele aflate la adrese de memorie pe care procesorul le poate accesa ntr-un singur ciclu de citire sau scriere. Alinierea datelor nu depinde numai de adresa, ci #i de m"rimea lor: valorile de un octet sunt ntotdeauna aliniate; valorile de doi octe!i sunt aliniate numai atunci cnd sunt localizate la adrese pare (adrese multiple de 2) bitul cel mai pu!in semnificativ este 0. valorile de patru octe!i sunt aliniate atunci cnd sunt pozi!ionate la adrese perfect divizibile cu patru primii doi bi!i mai pu!in semnificativi sunt 0. valorile de 8 octe!i sunt aliniate atunci cnd sunt stocate la adrese multiplu de opt primii trei bi!i mai pu!in semnificativi sunt 0. Aceast" aliniere este important" pentru procesoarele cu magistrale de date de 64 de bi!i, precum Pentium. La procesoarele 80386, deoarece magistrala de date are 32 de bi!i, o valoare de 64 de bi!i va fi citit" ntotdeauna n dou" cicluri de citire #i alinierea la grani!e de 4 octe!i este suficient". De#i procesoarele IA-32 pot folosi att date aliniate ct #i date nealiniate, modul de organizare al datelor prezentat mai sus, numit aliniere natural!, permite unui program s" ruleze mai rapid. Mai mult, anumite caracteristici ale procesorului

pot fi ntrebuin!ate numai cu date aliniate. A"adar, unele instruc!iuni lucreaz# mai bine cu date aliniate, altele chiar necesit# aliniere. Unele sisteme de operare necesit# structuri de date aliniate. Pentru procesoarele care folosesc memoria cache efectele nealinierii sunt ntructva mai reduse. n general, accesul la datele nealinitate aflate ntr-o linie cache nu necesit! cicluri adi"ionale. Totu#i, accesul la datele nealiniate ntre liniile de cache includ penalizare de vitez!. n plus, accesarea memoriei n ordine secven"ial! ajut! la cre#terea probabilit!"ii de cache hit, deoarece mai multe blocuri de memorie vor fi citite n acela#i timp n cache. S# judec#m urm#torul caz: presupunem c# lucr#m cu date de 32 de bi!i aliniate (aflate la adrese perfect divizibile cu patru). Procesorul va extrage datele n grupuri de patru octe!i (deoarece sunt definite ca DD), de la adrese divizibile cu patru (tot deoarece sunt definite ca DD). Datele noastre sunt 1111 2222 3333 4444, aranjate n memorie astfel:
Tabelul 5.2 Date de 32 de bi"i aliniate

11 33

Valoare 11 22 33 44

22 44

Adres! ..00 ..00

Pentru a extrage cuvntul de 32 de bi$i 3333 4444, procesorul trebuie s# afle adresa divizibil# cu patru "i s# extrag# o singur# dat#. Dac# datele sunt aranjate n memorie conform Tabelului 5.3, ca s# extrag# acelea"i date, procesorul trebuie: s# extrag# primul cuvnt de 32 de bi!i "i s# preia trei octe!i din stnga (33 4444), s# extrag# al doilea cuvnt de 32 de bi!i "i s# preia ultimul octet din dreapta (33), s# pun# octe!ii cap la cap. A"adar, dou# extrageri.
Tabelul 5.3 Date pe 32 de bi"i nealiniate

11 33

Valoare 22 22 44 44

33 11

Adres! ..00 ..00

Pe lng# cele men$ionate, preciz#m "i urm#toarele reguli de aliniere: n segmentul de cod este indicat# alinierea etichetelor accesate frecvent (deoarece s-a observat o cre"tere a vitezei programului). n plus, unele instruc!iuni necesit# alinieri la 32 de octe!i.

n segmentul de date este necesar! cel pu"in alinierea datelor la adrese divizibile cu patru, altfel procesorul cite#te de dou! ori ca s! extrag! o singur! dat!, ceea ce penalizeaz! serios performan"a.

O regul! general! spune c! trebuie s! definim nti datele cu dimensiuni mai mari cuvintele de 32 de bi"i naintea celor de 16, cuvintele de 16 bi"i naintea octe"ilor, etc.. Elemente de date de acela#i tip trebuie plasate mpreun!, la nceputul sec"iunii de date. Acest lucru asigura alinierea corect!. Dac! se lucreaz! cu #iruri sau buffere, este indicat, ori ca acestea s! fie pozi"ionate la sfr#itul sec"iunii de date, astfel nct s! nu strice alinierea altor elemente, ori s! aliniem explicit datele declarate dup! ele. Alinierea datelor n YASM n YASM, alinierea datelor sau codului la cuvnt, la dublu cuvnt, la paragraf (16 octe"i), etc., se face prin directivele align #i alignb. Sintaxa este: align align align align align alignb 4 ;aliniaz! datele la frontiere de 4 octe"i 16 ;aliniaz! datele la frontiere de 16 octe"i 16,nop ;linie echivalent! celei precedente 8, db 0 ;vezi OBS. II de mai jos 4, resb 1 ;aliniaz! la frontiere de 4 octe"i n segmentul BSS 4 ;linie echivalent! celei precedente

Obs. I. Pentru ambele directive, argumentul trebuie s! fie putere a lui doi (2, 4, 8, 16, 32). Obs. II. Ini"ial, octe"ii liberi sunt completa"i cu valoarea 0x90 (codul ma#in! al instruc"iunii NOP). Prin op"iunea db 0, octe"ii liberi se completeaz! cu 0. Datele programului alignData.asm sunt nealiniate (directiva align 4 este comentat!). Dup! sir, urmeaz! imediat d1 #i d2: ; ;alignData.asm ; section .data sir db 10,20,30,40,50,60 ;align 4 d1 dd 0ffffffffh d2 dd 0aaaaaaaah section .text global _start _start:

nop mov eax,1 mov ebx,0 int 080h Dac! urm!rim ce se ntmpl! n segmentul de date, observ!m: Valoare 0xaa 0xaa 0xaa 0xaa 0xff 0xff 0xff 0xff 0x3c 0x32 0x28 0x1e 0x14 0x0a
7 0

Adres! 0x804909d 0x804909c 0x804909b 0x804909a 0x8049099 0x8049098 0x8049097 0x8049096 0x8049095 0x8049094 0x8049093 0x8049092 0x8049091 0x8049090

Ultimul digit ...1110 ...1100 ...1011 ...1010 ...1001 ...1000 ...0111 ...0110 ...0101 ...0100 ...0011 ...0010 ...0001 ...0000

Dac! aliniem datele prin directiva align 4 (urmeaz! date de tip DD), ob"inem: Valoare Adres! Ultimul digit 0xaa 0x804909d ...1110 0xaa 0x804909c ...1100 0xff 0x804909b ...1011 0xff 0x804909a ...1010 0xff 0x8049099 ...1001 0xff 0x8049098 ...1000 0x90 0x8049097 ...0111 0x90 0x8049096 ...0110 0x3c 0x8049095 ...0101 0x32 0x8049094 ...0100 0x28 0x8049093 ...0011 0x1e 0x8049092 ...0010 0x14 0x8049091 ...0001

0x0a
7 0

0x8049090

...0000

6. ARHITECTURA SETULUI DE INSTRUC!IUNI

Arhitectura setului de instruc!iuni (ISA Instruction Set Architecture) cuprinde setul de instruc!iuni la nivel ma"in# recunoscut de procesor, tipurile de date ce pot fi manipulate cu aceste instruc!iuni "i contextul n care aceste instruc!iuni opereaz#. Arhitectura setului de instruc!iuni este o component# a sistemului de calcul vizibil# programatorului n limbaj de asamblare, component# care reprezint# interfa!a ntre software "i hardware. n acest capitol studiem arhitectura setului de instruc!iuni specific# procesoarelor Intel de 32 de bi!i.

6.1. Simboluri cheie


Instruc!iunea MOV prime"te ca operanzi trei tipuri de date: date aflate n memorie (memory data), date aflate n registre (register data) "i date imediate (immediate data date specificate direct n corpul instruc!iunilor). De acum nainte indic#m natura operanzilor prin urm#toarele simboluri: r, registru. m, memorie. i, imediat. b, octet (byte). 2, 2 octe!i. v, 32 de bi!i sau 16 bi!i (variable). e, nseamn# E cnd se lucreaz# cu 32 de bi!i "i dispare n logica de 16 bi!i (extended). Aceste simboluri cheie au fost utilizate de Stephen Morse n cartea 80386/387 Architecture. De"i ele nu respect# formatul oficial, sunt de un real ajutor n explicarea codurilor ma"in#. A"adar, instruc!iunea MOV poate primi una din formele urm#toare:
mov r, r

mov r, m mov m, i

mov r, m
mov m, r

Instruc!iunea MOV nu transfer" date din memorie n memorie. Variantele de mai sus pot fi reduse la dou! reprezent!ri: mov r,rmi mov m,ri Cnd nu preciz!m capacitatea operanzilor nseamn! c! instruc"iunea poate lucra cu oricare din cele trei variante (octet, cuvnt, dublu cuvnt). n cazul transferului de date ntre operanzi trebuie s! "inem cont c! nu putem transfera date ntre operanzi de dimensiuni diferite. Mul"i sunt nclina"i s! copieze registre de dimensiuni mai mici n registre de dimensiuni mai mari n virtutea faptului c! ncape. Numai c! instruc"iuni de tipul mov bx,al vor produce o eroare de asamblare. Aceast! instruc"iune ncearc! s! copieze 8 bi"i din registrul AL n registrul BX. n schimb, trebuie copiat con"inutul registrului AX n registrul BX, ambele de aceea#i dimensiune. Evident, trebuie s! fi"i aten"i ca nu cumva valoarea lui AX s! difere de valoarea lui AL (cnd AH nu este zero). Simboliz!m acest lucru prin forme de genul: mov rv,rmv mov rb,rmb mov rmv,rv Dac! "inem cont #i de acest ultim aspect, variantele instruc"iunii MOV cresc considerabil. Setul de instruc"iuni poate fi interpretat la dou! niveluri: nivelul de asamblare #i nivelul ma#in!. Pentru programatorul n limbaj de asamblare, procesorul are aproximativ o sut! de instruc"iuni. Dar unei instruc"iuni n limbaj de asamblare (de ex., MOV) i corespunde, de fapt, mai multe formate de instruc"iuni ma#in!, n func"ie de tipul #i m!rimea operandului. La nivel ma#in! exist! aproximativ trei sute de instruc"iuni. Instruc"iunile nivelului de asamblare simplific! viziunea programatorului asupra setului de instruc"iuni: programatorul scrie instruc"iunea n limbaj de asamblare, asamblorul o examineaz! #i determin! instruc"iunea de nivel ma#in! ce trebuie generat!.

6.2. Codificarea instruc!iunilor


Mecanismul prin care asamblorul genereaz! instruc"iuni ma#in! este destul de complex. Totu#i, instruc"iunile folosite de-a lungul exemplelor noastre pn! n prezent nu sunt foarte complicate. Codificarea acestora este ilustrat! n Tabelul 6.1. Majoritatea codului ma#in! este dat n hexazecimal, dar unii octe"i sunt reprezenta"i n binar.
Tabelul 6.1 Cteva instruc!iuni ma"in# de 32 de bi!i

mov mov mov mov

rv,iv rb,ib rmv,rv rmb,rb

Primul octet 10111DDD 10110DDD 89 88

Al doilea octet 11SSSDDD 11SSSDDD

nc! 4

Instruc"iunile procesorului 80386 sunt codificate pe un num!r de octe"i cuprins ntre 1 #i 15 (Figura 6.1).
OPCODE cod opera!ie
7

ModR/M

Imediat r/m
nc! 4 octe"i

d w mod
1 0 76

reg
543

210

Figura 6.1 Formatul general al unei instruc!iuni

Primul octet con"ine codul opera"iei (pe 6 bi"i), adic! tipul prelucr!rilor ce vor fi efectuate la execu"ia instruc"iuni (opera"ie aritmetic!, logic!, etc.). n cazul nostru este vorba de transfer de date. Al doilea octet con"ine informa"ii cu privire la registrele care con"in operanzii, adresarea memoriei, etc.. Codul ma#in! pentru MOV r,r este format din doi octe"i - primul este reprezentat n hexazecimal, al doilea n binar. Octetul binar ncorporeaz! adresele registrelor. SSS reprezint! codul de trei bi"i pentru registrul surs!. DDD reprezint! codul de trei bi"i pentru registrul destina"ie. Dimensiunea registrelor depinde de bitul 0 al primului octet. Acesta este notat cu w (word) #i codific! lungimea operanzilor: w=0, operand de tip octet; w=1, operand de tip cuvnt; la 386, aceast! valoare nseamn! operand de dimensiune complet# (16/32 de bi"i n func"ie de modul de lucru). n aceste condi"ii, adresele registrelor sunt prezentate n Tabelul 6.2.

Tabelul 6.2 Adresele registrelor

Registru Adres! 000 001 010 011 100 101 110 111 Cuvnt w=1 EAX ECX EDX EBX ESP EBP ESI EDI Octet w=0 AL CL DL BL AH CH DH BH

Tot n primul octet se afl! bitul d (direction), care indic! direc"ia rezultatului opera"iei: d=0, cmpul REG indic! operandul surs!; d=1, cmpul REG indic! operandul destina"ie. REG se afl! n al doilea octet al instruc"iunii, numit ModR/M (dac! exist!). Octetul ModR/M poate lipsi. De exemplu, instruc"iunea MOV r,i nu prezint! octetul ModR/M. Nu este zero, ci lipse#te. Valoarea imediatului este memorat! n cei patru octe"i adi"ionali (de la 1 la 4; n func"ie de dimensiunea destina"iei, imediatul poate fi reprezentat pe un 1, 2 sau 4 octe"i). Consider!m urm!toarele exemple: 1 2 3 4 5 6 7 8 9 B801000000 B89B000000 B800010000 B8FEFF0000 BB00000000 B10F 89C8 89D3 88CD mov mov mov mov mov mov mov mov mov eax,1 eax,155 eax,256 eax,65534 ebx,0 cl,15 eax,ecx ebx,edx ch,cl

Primul octet al instruc"iunii MOV EAX,1, B8, este codificat folosind codul 10111DDD, conform formatului MOV rv,iv. Bi"ii DDD sunt completa"i cu adresa registrului EAX, rezultnd codul binar 1011 1000 (B8H). Valoarea imediatului, ntregul 1, este reprezentat! imediat dup! acest OPCODE, pe urm!torii 4 octe"i. Observa"i cum valoarea imediatului de 4 octe"i, 00000001H, este stocat!

ca 01 00 00 00, conform criteriului little-endian (de aceea valoarea sa n instruc!iunea ma"in# pare a fi ntoars#). De exemplu, valoarea 155 n hexazecimal este 9B; n consecin!#, a doua instruc!iune este codificat# B89B000000. Verifica!i faptul c# a!i n!eles mecanismul ncercnd s# deduce!i instruc!iunile ma"in# pentru urm#toarele trei linii. Linia 6 prezint# o instruc!iune de forma MOV rb,ib. Codificarea folosit# este 10110DDD. Deoarece adresa registrului CL este 001 "i imediatul 15 n hexazecimal este 0F, instruc!iunea ma"in# se formeaz# ca B10F. Linia 7 prezint# o instruc!iune de forma MOV rv,rv, cu registrul EAX ca destina!ie (bi!ii DDD = 000) "i registrul ECX ca surs# (bi!ii SSS = 001). Octetul OPCODE este 89H, iar forma binar# a octetului ModR/M este 11SSSDDD. Pentru octetul ModR/M, dac# plas#m adresele registrelor pe pozi!iile corespunz#toare, ob!inem 1100 1000 n binar (C8H). Rezult# instruc!iunea ma"in# 89C8.

6.2.1. Spa!iul codurilor opera!ionale


Codurile ma"in# utilizate n ultima sec!iune pot asambla o mare varietate de instruc!iuni n limbaj de asamblare. Pe de alt# parte, pe ansamblu, ele reprezint# numai o mic# parte din setul de instruc!iuni Intel x86. n aceast# sec!iune facem o descriere general# a setului de instruc!iuni ma"in#. Tabelul 6.3 prezint# informa!iile oferite de primul octet al codului ma"in#. Majoritatea intr#rilor din tabel con!in informa!ii cu privire la mnemonic# "i operanzi. n cteva cazuri aceast# informa!ie este specificat# complet. De exemplu, intrarea corespunz#toare octetului 90 (rndul 9, coloana 0) reprezint# instruc!iunea NOP. n alte cazuri se precizeaz# mnemonica "i o clas# de operanzi admi"i (descri"i prin simbolurile cunoscute). Informa!iile transmise de primul octet (OPCODE) pot fi mp#r!ite n urm#toarele clase: Octetul OPCODE exprim# complet instruc!iunea. De exemplu, NOP specific# instruc!iunea NOP (No Operation), care, a"a cum denot# "i numele ei, nu realizeaz# nicio prelucrare. NOP ocup# un singur octet "i dureaz# trei cicluri de ceas. Octetul OPCODE determin# tipul opera!iei, dar nu specific# operanzii. n aceste cazuri, de cele mai multe ori, aceast# informa!ie este furnizat# de cel de al doilea octet, ModR/M. De exemplu, dac# primul octet este 89H, intrarea corespunz#toare din tabel# este MOV rmv,rv. Pe lng# faptul c# specific# opera!ia MOV, simbolurile operand rmv,rv transmit informa!ie cu privire la modul n care trebuie interpretat octetul ModR/M. Acest caz a fost deja ntlnit.

Tabelul 6.3 Codurile setului de instruc!iuni IA-32 [13]

Octetul OPCODE nu specific! o opera"ie, ci o categorie de opera"ii, iar octetul ModR/M este folosit att s! completeze informa"ia de prelucrare ct #i s! furnizeze informa"ia cu privire la operanzi. De exemplu, dac! primul octet este C1, intrarea n tabel este Shift rmv,ib. n aceste cazuri este nevoie de interpretarea complet! a octetului ModR/M (Figura 6.2). Shift nu este un cuvnt mnemonic. El este un indicator c!tre Tabelul 6.4. n Tabelul 6.3, acest lucru este indicat prin faptul c! nu toate literele cuvntului sunt majuscule. Dac! primul octet este 0F, atunci se deschide o ntreag! pleiad! de posibilit!"i. Informa"ia transmis! de 0F este mergi la Tabelul 6.5. Dac! valoarea primului octet se afl! n gama D8-DF, atunci este vorba de o instruc"iune n virgul! mobil!. Octe"i prefix. Octe"ii prefix modific! comportamentul instruc"iunilor care i urmeaz! (de ex., LOCK).

6.2.2. Octetul ModR/M


Octetul ModR/M transmite informa!ii cu privire la operanzi n cazurile n care primul octet este insuficient.
Mod 7 6 5 REG 4 3 2
R/M 1

Figura 6.2 Octetul ModR/M

Bi!ii 7 "i 6 sunt bi!ii Mod. Cnd bi!ii Mod sunt 11, cmpul R/M specific# un registru. n celelalte cazuri, bi!ii R/M codific# adrese de memorie. Bi!ii 5, 4, 3, formeaz# cmpul REG, sau registru, "i de cele mai multe ori este desemnat prin nota!ia /r. Indic# registrul care con!ine unul din operanzi sau, mpreun# cu cei 6 bi!i din primul octet, specific# alte coduri opera!ionale (Tabelul 6.4). Acest lucru nseamn# c# REG este determinat de primul octet (OPCODE) al instruc!iunii. Bi!ii 2,1,0, formeaz# cmpul R/M, sau registru/memorie. Dac# Mod = 11, atunci R/M indic# registrul care con!ine al doilea operand. n toate celelalte cazuri, R/M indic# registrul implicat n aflarea loca!iei de memorie ce con!ine al doilea operand.
Tabelul 6.4 Instruc!iuni specificate de REG

/r /0 000 /1 001 /2 010 /3 011 ADD OR ADC SBB Immed ROL ROR RCL RCR Shift NOT NEG Unary TEST i INC DEC IncDec INC DEC CALL m CALL Indir FAR m

/4 100 AND SHL MUL JMP

/5 101 SUB SHR IMUL JMP FAR

/6 110 XOR SAR DIV PUSH

/7 111 CMP IDIV

Unul din cazurile n care cei 6 bi!i de cod opera!ional prezen!i n primul octet sunt insuficien!i pentru a defini complet opera!ia, "i este necesar# studierea cmpului REG din octetul ModR/M, este cel al instruc!iunii AND ECX,64. nregistrarea din Tabelul 6.3 pentru 83 este Immed rmv,ib Deoarece rndul intitulat Immed din Tabelul 6.4 are un AND sub /r = /4, nseamn# c# instruc!iunea AND rmv,ib

poate fi codificat! folosind 83 ca OPCODE "i 100 pentru bi#ii REG din octetul ModR/M. Din moment ce primul operand este registrul ECX, bi#ii Mod trebuie s! fie 11 "i R/M s! con#in! 001 (adresa registrului ECX). A"adar, octetul ModR/M este format din bi#ii 11 100 001, sau E1H. ib nseamn! imediat de tip octet valoarea sa se adaug! la restul codului instruc#iune. n final, pentru AND ECX,64 se ob#ine 83 E1 40.

6.2.3. Spa!iul codurilor 386 (0F + ...)


La procesorul 8086 octetul 0FH codific! instruc#iunea de extragere din stiv! a registrului CS. La urm!toarele procesoare aceast! intruc#iune a fost nl!turat!, astfel nct 0FH, acum disponibil, a permis o extindere semnificativ! a setului de instruc#iuni. Octetul 0FH se nume"te prefix de extindere a codurilor de opera#ie. Tabelul 6.5 dezv!luie spa#iul nou creat.
Tabelul 6.5 Spa!iul 386 [13]

Ca "i Tabelul 6.3, Tabelul 6.5 prezint! informa#ia transmis! de un singur

octet - n acest caz, octetul care urmeaz! octetului 0F. Majoritatea instruc"iunilor din acest tabel au ap!rut pentru prima dat! la procesorul 80386. Informa"iile furnizate de acest octet pot fi incluse n urm!toarele clase: Specific! complet o instruc"iune. De exemplu, 0F CA este codul pentru BSWAP EDX. Determin! tipul opera"iei, dar operanzii sunt specifica"i de octetul ModR/M. De exemplu, instruc"iunea XADD (0F C1). Determin! o categorie de opera"ii, iar octetul ModR/M specific! o anumit! opera"ie. De exemplu, dac! primii doi octe"i ai instruc"iunii sunt 0F 01, opera"ia este determinat! de bi"ii REG ai octetului ModR/M. Din Tabelul 6.6 reiese c!, atunci cnd bi"ii REG din ModR/M sunt 011, instruc"iunea este LIDT. Reprezint! instruc"iuni MMX.
Tabelul 6.6 Instruc!iunile OF specificate de bi!ii REG

/0 000 SLDT LocalT rm2 SGDT GlobalT m6 Bits

/r

/1 001 STR rm2 SIDT m6

/2 010 LLDT rm2 LGDT m6

/3 011 LTR rm2 LIDT m6

/4 100 /5 101 /6 110 /7 111 VERR VERW rm2 rm2 SMWS LMSW rm2 rm2 BT BTS BTR BTC rmv,ib rmv,ib rmv,ib rmv,ib

Instruc"iunile prezente n Tabelul 6.5 mai provin, pe lng! procesorul 80386, de la 80486 #i Pentium. De exemplu, XADD #i BSWAP au ap!rut pentru prima dat! la procesoarele 80486, iar CPUID #i RDTSC la Pentium.

6.2.4. Prefix de dimensiune operand


Pn! acum am studiat numai instruc"iuni ma#in! care primesc drept operanzi registre de 8 sau 32 de bi"i. n continuare studiem modul n care sunt codificate instruc"iunile cu operanzi de 16 bi"i. Cteva exemple: 1 2 3 4 89D8 6689D8 B808000000 66B80800 mov mov mov mov eax,ebx ax,bx eax,8H AX,8H

Instruc"iunea MOV EAX,EBX este codificat! 89 D8. Echivalentul ei pe 16 bi"i este MOV AX,BX. Surprinz!tor, codul pentru aceast! comand! este tot 89 D8

(ignora!i primul octet). Procesorul 80386 a fost proiectat s" foloseasc" acelea#i codific"ri att pentru opera!ii cu registre de 32 de bi!i ct #i pentru opera!ii cu registre de 16 bi!i. Modul de operare implicit al instruc!iunilor, fie pe 16, fie pe 32 de bi!i, depinde de bitul D din descriptorul segmentului de cod. Bitul D specific" dimensiunea implicit" att pentru operanzi ct #i pentru adresa loca!iilor de memorie. D = 0 indic" opera!ii pe 16 bi!i, D = 1 indic" opera!ii pe 32 de bi!i. Bitul D determin" dac" 89 D8 nseamn" MOV EAX,EBX sau MOV AX,BX. Acest lucru nu nseamn" c" instruc!iunea MOV AX,BX nu este disponibil" la procesoarele de 32 de bi!i. La aceste procesoare, asamblorul semnalizeaz" procesorului faptul c" prezum!ia cu privire la num"rul de bi!i setat" implicit de bitul D este gre#it" prin ad"ugarea prefixului 66 nainte de instruc!iune. Prefixul 66 este numit prefix de dimensiune operand. Astfel, pentru un mod de lucru implicit pe 32 de bi!i (D = 1), codificarea 66 89 D8 nseamn" MOV AX,BX. Similar, pentru pentru un mod de lucru implicit pe 16 bi!i (D = 0), codul 66 89 D8 nseamn" MOV EAX,EBX. Prefixul dimensiune operand indic" faptul c" dimensiunea operandului nu este cea implicit". n mod implicit, sistemul Linux seteaz" bitul D (nu acela#i lucru se poate spune de DOS), a#adar pe sistemele noastre 66 89 D8 nseamn" MOV AX,BX. Acum, odat" ce am v"zut cum aceea#i codificare poate avea dou" semnifica!ii, ne este u#or s" explic"m de la ce provine simbolul v din instruc!iunile de genul MOV rmv,rv. Simbolul v din fiecare operand nseamn" variabil, unde variabil se refer" la faptul c" dimensiunea operandului poate fi de 16 sau 32 de bi!i. n mod asem"n"tor, simbolul e (extended) din reprezent"rile registrelor, de exemplu eAX, indic" faptul c", n codificarea de 32 de bi!i, ne referim la registrul EAX, iar n codificarea de 16 bi!i, la registrul AX.

6.3. Codificarea adreselor de memorie


Toate intr"rile din Tabelul 6.3 care includ simbolul m descriu instruc!iuni de acces la memorie. Observ"m c" toate instruc!iunile MOV, ADD, ADC, SUB, SBB, OR, AND #i XOR pot avea ca surs" sau destina!ie operanzi afla!i n memorie. Ace#tia pot fi adresa!i n diverse moduri. n capitolul precedent am discutat pe larg formatul general de adresare a memoriei. Aspectul func!ional [baz! + index " scal! + deplasament] rescris structural, arat" astfel: [reg + reg " scal! + imediat]

unde,

scal! este un factor de scal!, care trebuie s! fie 1, 2, 4 sau 8; registrul multiplicat de factorul de scal! este numit registru index; cel!lalt registru este numit registru de baz!; imediatul este un num!r pe 8, 16 sau 32 de bi"i. Rezult! o mare varietate de formate, majoritatea deja studiate, [reg] [imediat] [reg+reg] [reg+imediat] [reg+reg+imediat] [reg+scal!"reg] [scal!"reg+imediat]

n care imediatul reprezint! fie adresa complet! a operandului (deplasamentul), fie o constant! implicat! n adresare (o deplasare). Poate este greu de crezut c! instruc"iuni cu asemenea grad de complexitate sunt codificate u#or de procesor. Costul acestei complexit!"i, n termeni de dimensiune (lungimea instruc"iunii care folose#te formatul complet), este de un singur octet. Octetul este numit SIB (Scale Index Base).

6.3.1. Octetul SIB


Prefix OPCODE ModR/M SIB instruc#iune Pn! la 4 prefixuri Cod 1 octet 1 octet de cte un octet opera"ional (dac! este (dac! este (op"ionale) de 1, 2 sau 3 necesar) necesar) octe"i Deplasament Deplasament de 1,2 sau 4 octe"i (op"ional) Imediat Date imediate de 1,2 sau 4 octe"i (op"ional)

Mod

Reg/Opcode

R/M

Scal!

Index

Baz!

Figura 6.3 Formatul instruc!iunilor IA-32

n englez!, un joc de cuvinte define#te SIB ca fiind sibling cu octetul ModR/M, aluzie la faptul c! prezen"a sa n corpul instruc"iunii este indicat! de ModR/M (numai n codific!rile pentru care acesta este insuficient). Octetul SIB con"ine:

factorul de scal!, pe primii doi bi!i; registrul index utilizat, pe urm"torii trei bi!i (ca registre index pot fi utilizate 7 din cele 8 registre de uz general, mai pu!in registrul ESP); registrul de baz! utilizat, pe ultimii trei bi!i (ca registre de baz" pot fi utilizate toate registrele de uz general).

6.4. Formatul instruc!iunilor


Toate codific"rile instruc!iunilor IA-32 sunt subseturi ale formatului de instruc!iune general prezentat n Figura 6.3. Instruc!iunile constau din prefixe de instruc!iune op!ionale (n orice ordine), unul sau doi octe!i de cod opera!ie (unele din instruc!iunile SSE #i SSE2 au trei octe!i de cod opera!ie), un identificator al formatului de adres" (dac" este necesar) - format din octetul ModR/M #i, uneori, octetul SIB, un deplasament (dac" este necesar), #i un cmp de date imediate.

6.4.1. Prefixele de instruc!iune


Prefixele de instruc!iune sunt valori speciale de un octet care afecteaz" opera!ia instruc!iunii. Prefixele de instruc!iune sunt mp"r!ite n patru grupuri, fiecare cu un set de coduri admisibil. Prefixe de instruc!iune (de blocare sau repetare) (Grup1) o F0H, LOCK (garanteaz" c" instruc!iunea va avea acces exclusiv la toat" memoria partajat", pe toat" durata execu!iei sale). o F2H, REPNE/REPNZ (folosite numai n opera!ii pe #iruri). o F3H, REP sau REPE/REPZ (folosite numai n opera!ii pe #iruri). Prefixe de segment (Grup 2) o 2EH, registrul CS. o 36H, registrul SS. o 3EH, registrul DS. o 26H, registrul ES. o 64H, registrul FS. o 65H, registrul GS. Prefixe de indiciu de ramificare (Grup 2) o 2EH, ramificare inactiv" (folosit numai cu instruc!iuni de salt condi!ionat). o 3EH, ramificare activ" (folosit numai cu instruc!iuni de salt condi!ionat).

66H, prefix de dimensiune operand (Grup 3) 67H, prefix de dimensiune adres! (Grup 4)

Pentru orice instruc"iune se poate folosi un prefix din fiecare grup, n orice ordine. Prefixul LOCK determin! activarea semnalului de magistral! omonim pe durata execu"iei acelei instruc"iuni. Are ca efect interdic"ia de cedare a magistralelor unui alt dispozitiv. ntr-un sistem multiprocesor, acest semnal poate fi utilizat de opera"ii atomice18 pentru a ob"ine acces exclusiv la memoria partajat!. Prefixele de repetare provoac! repetarea unei instruc"iuni pentru fiecare element al unui #ir. Acestea pot fi utilizate numai cu instruc"iuni pe #iruri: MOVS, CMPS, SCAS, LODS, STOS, INS #i OUTS (vor fi studiate ntr-un capitol viitor). Prefixele de segment for"eaz! unitatea de management a memorie s! foloseasc! registrul de segment specificat n loc de cel implicit. Prefixele de indiciu ramificare permit unui program s! indice procesorului cea mai probabil! cale urmat! de o instruc"iune de salt. Aceste prefixe pot fi utilizate numai cu instruc"iuni de salt condi"ionat. Au fost introduse n procesoarele Pentium 4 #i Intel Xeon ca parte din extensiile SSE2. Prefixul de dimensiune operand modific! dimensiunea implicit! a datelor (de la 32 la 16 bi"i, sau invers). Prefixul de dimensiune adres! modific! dimensiunea implicit! a adreselor (de la adrese de 32 de bi"i comut! la adrese de 16 bi"i, sau invers).

6.4.2. Modurile de adresare prin octetul ModR/M


Cmpul Mod din registrul ModR/M reprezint! o codificare a modului de calcul a adresei efective sau lungimea deplasamentului #i, mpreun! cu cmpul R/M, este utilizat pentru a determina adresa efectiv!. Pn! acum ne-am concentrat aten"ia asupra instruc"iunilor n care bi"ii cmpului Mod sunt 11. n aceste situa"ii, cmpul R/M specific! un registru #i utilizeaz! aceea#i codificare ca #i cmpul REG. Am putut ob"ine coduri pentru instruc"iuni de genul MOV EAX,EDX,ce folosesc adresarea la registre. Ca o scurt! recapitulare, reamintim pa#ii procesului. Din Tabelul 6.3 am identificat codul opera"iei ca fiind 89H. Ultimii doi bi"i ai octetului OPCODE, d, respectiv w, dau informa"ii cu privire la destina"ia rezultatului #i la dimensiunea operanzilor. Deoarece bitul d este zero, nseamn! c! n cmpul REG se afl! codul registrului surs!, a#adar 010 (EDX), iar n cmpul
18

O opera"ie atomic! este indivizibil! si nu poate fi ntrerupt!; odat! ce opera"ia ncepe nu va fi oprit! sau ntrerupt! pn! cnd nu este finalizat!, #i nici o alt! opera"ie nu-i va lua locul n timpul acesta.

R/M trebuie s! se afle codul registrului destina"ie, 000 (EAX). Valoarea con"inut! n ModR/M se ob"ine grupnd bi"ii Mod REG R/M mpreun!. Rezult! 11 010 000 n binar, adic! D0H. Instruc"iunea complet! este codificat! sub forma 89D0.
Tabelul 6.7 Formele de adresare pe 32 de bi!i cu ajutorul octetului ModR/M

Tabelul 6.7 face parte din manualul oficial pus la dispozi"ie de Intel pentru dezvoltatorii de programe19 #i prezint! toate formele de adresare pe 32 de bi"i care folosesc octetul ModR/M. Numerele hexazecimale reprezint! valorile octetului
19

Intel Architecture Software Developer's Manual, Volume 2: Instruction Set Reference

ModR/M n aceste cazuri. Prima coloan! arat! modul de calcul al adresei efective, a doua "i a treia, setarea bi#ilor Mod, respectiv R/M. Coloanele care urmeaz! prezint! valoarea octetului ModR/M pe ansamblu, dar "i adresa registrului care se g!se"te n cmpul REG. Privi#i rndul corespunz!tor coloanei Mod = 11 (ultimul rnd) "i c!uta#i codul D0. Prima coloan! denot! mecanismul de adresare la registre, coloana R/M arat! c! n cmpul R/M se afl! adresa registrului EAX, iar coloana pe care se afl! D0 arat! c! n cmpul REG se afl! registrul EDX. Dimensiunea registrelor a fost descifrat! anterior cu ajutorul bitului w din octetul codului de opera#ie. Consider!m urm!torul exemplu mov ah,ch Din Tabelul 6.3 codul opera#iei pentru o instruc#iune de genul MOV rmb,rb este 88. Valoarea 0 a bitului w din OPCODE (1000 1000) indic! opera#ie la nivel de octet. Valoarea 0 a bitului d (10001000) specific! faptul c! sursa (registrul CH) se afl! n REG "i destina#ia (registrul AH) n R/M. n concluzie, octetul ModR/M este format din "irul de bi#i 11 101 100, EC. Codul complet al instruc#iunii este 88EC. n cazul mov edx,ecx codul instruc#iunii este 89CA. Dac! n acest cod schimb!m bi#ii Mod de la 11 la 00, valoarea octetului ModR/M devine 0A (00 001 010). Instruc#iunea devine: mov [edx],ecx n acest caz, bi#ii Mod indic! un operand aflat n memorie. Codurile 01 "i 10 sunt utilizate la codificarea deplasamentelor imediate, precum MOV EDI,[EAX+5], unde deplasamentul este de tip ib sau iv. A"adar, codul pentru MOV EDI,[EAX+5] este 8B78 05. Codul pentru MOV EDI,[EAX+12345678H] este 8BB8 78563412. Totu"i, dac! aceast! schem! de codificare se folosea uniform nu ar fi fost disponibil destul spa#iu pentru formatele complexe ale modurilor de adresare. Din acest motiv, codul pentru registrul ESP a fost ndep!rtat, pozi#ia acestuia folosindu-se ca intrare ntr-un nou spa#iu de codificare ce folose"te octetul SIB. n urm!toarele rnduri descriem pe larg posibilit!#ile introduse de octetul ModR/M. Mod = 00 nseamn! mod de adresare indirect (prin registre), direct prin deplasament (R/M = 101) sau SIB f!r! deplasament (R/M = 100). Din Tabelul 6.7 reiese c! Mod = 00 nseamn! adresare bazat!. Cmpul R/M specific! un mod de adresare indirect! sau bazat!/indexat!, mai pu#in pentru R/M = 101, care denot! adresare direct! prin deplasament, "i R/M = 100, care indic! c!tre

octetul SIB. Slotul ocupat de modul de adresare direct! prin deplasament apar"inea adres!rii indirecte prin registrul EBP. Intel a decis c! n locul acesteia, programatorii pot utiliza adresarea indirect! [EBP+ib], cu ib = 0 (de#i instruc"iunea este pu"in mai lung!). A#adar, Mod = 00 poate fi folosit pentru urm!toarele cazuri: [reg] [deplasament] [deplasament + constant!] Mod = 01 nseamn! c! octetul (octe"ii) modului de adresare este urmat de un deplasament (imediat) de 8 bi"i. Aten"ie, nu confunda"i deplasamentul cu dimensiunea datelor. Dimensiunea datelor este specificat! n octetul OPCODE prin bitul w. Un deplasament de 8 bi"i nu nseamn! date de 8 bi"i, ci o ajustare n segment curpins! n gama -128..+127. Cmpul deplasament din formatul general al instruc"iunilor IA-32 va fi format dintr-un singur octet pozi"ionat imediat dup! octe"ii OPCODE (rapiditate). Mod = 10 nseamn! c! octetul (octe"ii) modului de adresare este urmat de un deplasament de 32 de bi"i.

6.4.3. Modurile de adresare prin octetul SIB


Toate intr!rile din Tabelul 6.7 definite prin intermediul cmpului Mod #i R/M = 100 trimit c!tre octetul SIB #i arat! c! instruc"iunea folose#te o form! de adresare indexat!. [r32 + eax " scal!] [imediat + r8 + eax " scal!] [imediat + r32 + eax " scal!] A#a cum se desprinde din Tabelul 6.8, octetul SIB specific! registrul de baz!, registrul index #i factorul de scal!. Codul factorului de scal! precizeaz! valoarea cu care va fi nmul"it registrul index.

Tabelul 6.8 Formele de adresare pe 32 de bi!i cu ajutorul octetului SIB

Tabelul 6.9 Valoarea factorului de scal"

Valoarea factorului de scal! Valoarea (Registru index " Factor de scal!) 00 Index " 1 01 Index " 2 10 Index " 4 11 Index " 8

Pentru fiecare mod de adresare cu octet SIB, cmpul Mod din octetul ModR/M specific! dimensiunea deplasamentului (constant! de deplasare). Poate fi zero, unu sau patru octe"i.
Tabelul 6.10 Adresarea cu SIB

Mod 00 01 10

R/M 100 100 100

Mod de adresare SIB SIB + deplasament SIB + deplasament

Niciun mod de adresare cu SIB nu permite utilizarea registrului ESP ca registru index. Un caz special apare cnd Mod = 00 #i cmpul registrului de baz! este 101. Sunt adres!rile de tip: [deplasament + eax ! scal"]

6.5. Studiu de caz


Primul listing prezint! fi#ierul prog.lst generat la asamblare, urm!torul reprezint! dezasamblarea executabilului prog. n primul, codific!rile instruc"iunilor nu includ adresele de memorie la care se vor afla acestea n momentul rul!rii programului #i este mai u#or s! descifr!m codul opera"ional. Listing 1. cat prog.lst 2 3 00000000 0A000000140000001E4 00000000 0000002800000032005 00000000 00003C000000 6 7 8 9 00000000 90 10 00000001 B8[00000000] 11 00000006 8B1D[00000000] 12 0000000C 8B08 13 0000000E 8B5004 15 00000017 B803000000 [section .data] valori: dd 10,20,30,40,50,60 [section .text] [global _start] _start: nop mov eax,valori mov ebx,[valori] mov ecx,[eax] mov edx,[eax+4] mov eax,3

16 0000001C 17 00000022 18 00000027 19 0000002A 20 0000002B 21 0000002D 22 0000002F 23 00000032 24 00000037 25 26 0000003B 27 00000040 28 00000045 Listing 2.

8BB0[00000000] BB[00000000] 8B0C83 41 6641 0409 83C009 05FF000000 6605FF00 B801000000 BB00000000 CD80

mov esi,[valori+eax*1] mov ebx,valori mov ecx,[ebx+eax*4] inc ecx inc cx add al,9 add eax,9 add eax,255 add ax,255 mov eax,1 mov ebx,0 int 080

objdump -d -M intel prog prog: file format elf32-i386

Disassembly of section .text: 08048080 <_start>: 8048080: 90 8048081: b8 c8 90 04 08 8048086: 8b 1d c8 90 04 08 804808c: 8b 08 804808e: 8b 50 04 8048097: b8 03 00 00 00 804809c: 8b b0 c8 90 04 08 80480a2: bb c8 90 04 08 80480a7: 8b 0c 83 80480aa: 41 80480ab: 66 41 80480ad: 04 09 80480af: 83 c0 09 80480b2: 05 ff 00 00 00 80480b7: 66 05 ff 00 80480bb: b8 01 00 00 00 80480c0: bb 00 00 00 00 80480c5: cd 80 nop mov eax,0x80490c8 mov ebx,DWORD PTR ds:0x80490c8 mov ecx,DWORD PTR [eax] mov edx,DWORD PTR [eax+0x4] mov eax,0x3 mov esi,DWORD PTR [eax+0x80490c8] mov ebx,0x80490c8 mov ecx,DWORD PTR [ebx+eax*4] inc ecx inc cx add al,0x9 add eax,0x9 add eax,0xff add ax,0xff mov eax,0x1 mov ebx,0x0 int 0x80

Codificarea instruc!iunii MOV eAX,iv Instruc!iunea MOV EAX,valori este codificat" n acela#i mod ca MOV EAX,1 - nc"rcarea unui imediat de 32 de bi!i n registrul de uz general EAX (MOV eAX,iv). Diferen!a const" din faptul c" valoarea imediatului, 1, este cunoscut" la asamblare #i asamblorul formeaz" instruc!iunea complet". Observa!i c" valorile sunt scrise n little-endian imediat dup" singurul octet de cod opera!ional. Instruc!iune: MOV eAX,iv Codificare: B8 [00 00 00 00] Binar: 1011 1000 [imediat] Opcode = 10111000, indic" nc"rcarea n registrul EAX sau AX a unui imediat de 32 sau 16 bi!i, n func!ie de modul de lucru implicit. Deoarece, n cazul nostru, modul de lucru implicit este pe 32 de bi!i, nseamn" c" instruc!iunea se traduce: MOV EAX,imm32. Imediatul poate fi specificat explicit sau simbolic (printr-o etichet"). Adresare direct" prin deplasament Instruc!iune: MOV EBX,[valori] Codificare: 8b 1d [00 00 00 00] Binar: 1000 1011 0001 1101 [depl32] Opcode = 100010, indic" o instruc!iune MOV. d = 1, cmpul REG este destina!ie. w = 1, operanzi de 32 de bi!i. REG = 011, registrul EBX. combina!ia Mod = 00 #i R/M = 101 indic" mod de adresare prin deplasament (de 32 de bi!i). A#adar, dup" instruc!iune va urma un astfel de deplasament. Deplasamentul este vizibil n al doilea listing #i reprezint" adresa de la care ncep datele n memorie (0x80490c8 ). Registrul DS din fa!a deplasamentului arat" c" datele se afl" n segmentul de date implicit (adresat cu DS).

Tabelul 6.11 Registrele de segment implicite utilizate la adresare

Tip referin!" la memorie Citire instruc!iune Date Opera!ii pe #iruri - #ir surs" - #ir destina!ie Opera!ii cu stiva EBP utilizat ca registru de baz"

Segment implicit CS DS DS ES SS SS

Deplasament EIP Adresa efectiv" ESI EDI ESP Adresa efectiv"

Adresare indirect" prin registre Instruc!iune: MOV ECX,[EAX] Codificare: 8B 08 Binar: 1000 1011 0000 1000 Opcode = 100010, identific" o instruc!iune MOV. d = 1, cmpul REG este destina!ie. w = 1, operanzi de 32 de bi!i. Mod = 00, adresare f"r" deplasament. REG = 001, registrul ECX. R/M = 000, indic" utilizarea modului de adresare [EAX]. Adresare bazat" (deplasament de 8 bi!i) Instruc!iune: MOV EDX,[EAX+4] Codificare: 8B 50 [04] Binar: 1000 1011 0101 0000 [depl8] Opcode = 100010, identific" o instruc!iune MOV. d = 1, cmpul REG este destina!ie. w = 1, operanzi de 32 de bi!i. Mod = 01, cmpul deplasament are 8 bi!i. REG = 010, registrul EDX. R/M = 000, indic" utilizarea modului de adresare [EAX+depl8]. Deplasamentul de 8 bi!i urmeaz" imediat dup" octe!ii de cod de opera!ie #i ocup" un singur octet.

Adresare bazat! (deplasament de 32 de bi"i) Instruc!iune: MOV ESI,[valori+EAX*1] Codificare: 8B B0 [00 00 00 00] Binar: 1000 1011 1011 0000 [depl32] Opcode = 100010, identific" o instruc!iune MOV. d = 1, cmpul REG este destina!ie. w = 1, operanzi de 32 de bi!i. Mod = 10, cmpul deplasament are dimensiune complet". Deoarece modul de lucru implicit este pe 32 de bi!i, deplasamentul are 32 de bi!i. REG = 110, registrul ESI. R/M = 000, indic" utilizarea modului de adresare [ESI+depl32]. Deplasamentul de 32 de bi!i urmeaz" imediat dup" octe!ii de cod de opera!ie #i ocup" patru octe!i. Observa!i c" asamblorul a interpretat ultimele dou" instruc!iuni n acela#i mod. De fapt, prima va produce o eroare de tip Segmentation Fault, programatorul a specificat o adres" efectiv" inexistent" sau la care nu are drept de acces. Adresare indexat! #i scalat! Instruc!iune: MOV ECX,[EBX+EAX*4] Codificare: 8B 0C 83 Binar: 1000 1011 0000 1100 1000 0011 Opcode = 100010, identific" o instruc!iune MOV. d = 1, cmpul REG este destina!ie. w = 1, operanzi de 32 de bi!i. REG = 001, registrul ECX. R/M = 100 mpreun" cu Mod = 00, indic" faptul c" urm"torul octet este SIB. o SS = 10, registrul index se nmul!e#te cu 4. o Index = 000, registrul index este EAX. o Baz" = 011, registrul de baz" este EBX. Prefix de dimensiune operand Ambele instruc!iuni, INC ECX #i INC CX, sunt codificate conform

aceluia!i criteriu, INC eCX. Programele de 32 de bi"i nu folosesc foarte des operanzi de 16 bi"i, dar cnd folosesc, procesorul trebuie n!tiin"at. Acesta este rolul prefixului de dimensiune operand, 66H. Programatorul nu trebuie s# specifice explicit acest lucru, imediat cum g#se!te n instruc"iune un operand de 16 bi"i asamblorul adaug# automat acest prefix. Totu!i, re"ine"i c# oricnd folosi"i operanzi de 16 bi"i n programe de 32, dimensiunea instruc"iunii cre!te cu un octet. Totodat#, din cauza efectului acestora asupra mecanismului cache, execu"ia este mai lent#. Codific!ri alternative pentru instruc"iuni Pentru unele instruc"iuni utilizate frecvent, cu scopul de a scurta codul programului, Intel a creat codific#ri alternative (mai scurte). De exemplu, setul de instruc"iuni Intel x86 ofer# opcode de un singur octet pentru instruc"iuni de genul: add al,constant! add eax,constant! Codurile de opera"ie sunt 04H !i 05H. De asemenea, aceste instruc"iuni sunt cu un octet mai mici dect instruc"iunile standard ADD imediat. Chiar !i instruc"iunea ADD ax,constant!, care necesit# un prefix de dimensiune, este mai mic# dect versiunea standard a lui ADD imediat. Un compilator sau asamblor alege automat instruc"iunea cea mai scurt#. Intel ofer# alternative de codificare numai pentru registrele acumulator: AL, AX, EAX. A!adar, suntem ncuraja"i s# utiliz#m aceste registre oricnd putem.

7. OPERA!II CU NUMERE NTREGI

Numerele ntregi sunt numerele f!r! parte frac"ionar!. Am f!cut cuno#tin"! cu ele nc! din primul capitol al acestei c!r"i, sau, mai degrab!, avnd n vedere c! am lucrat numai cu ntregi f!r! semn, cu un tip al acestora. Numerele ntregi se mpart n dou! categorii: ntregi cu semn #i ntregi f!r! semn. Acest capitol se deschide cu o discu$ie referitoare la reprezentarea ntregilor cu semn.Un rol foarte important n opera$iile cu numere ntregi sunt indicatorii de stare. De aceea, tot aici vom discuta pe larg modul n care indicatorii de stare afecteaz! opera$iile aritmetice %i logice. ncepem cu prezentarea instruc$iunilor care permit opera$ii aritmetice %i logice cu numere ntregi. nspre final abord!m opera$ii mai complexe: execu$ie condi$ionat!, procesarea %irurilor %i lucrul cu stiva.

7.1. Reprezentarea numerelor cu semn


Problema numerelor cu semn const! n reprezentarea semnului. Pe hrtie, semnul unui num!r, de exemplu -15, poate fi reprezentat printr-un simbol distinct: 1111. Deoarece calculatorul reprezint! informa"ia numai ca #iruri de 0 #i 1, cel mai u#or pentru programatori a fost s! considere bitul cel mai semnificativ ca fiind bit de semn: 0 - num!r pozitiv, 1 - num!r negativ. Acest mecanism poart! numele de reprezentare cu bit de semn #i magnitudine. Magnitudinea este format! din ceilal"i bi"i ai reprezent!rii #i furnizeaz! valoarea propriu zis! a num!rului. ns!, a$a cum vom vedea n paragrafele urm!toare, acest mod de reprezentare are probleme de consisten%!. De aceea, n prezent, exist! trei tehnici generale de reprezentare a ntregilor cu semn: magnitudine cu semn; complement fa"! de unu; complement fa"! de doi. Pentru toate, bitul cel mai semnificativ al unei reprezent!ri poate fi considerat bit de semn. Dar aten"ie la nuan"!, am spus poate fi considerat; numerele negative sunt reprezentare diferit n cele trei metode de reprezentare. Pentru c! este foarte important, preciz!m de la nceput c! arhitectura IA32 folose#te metoda complementului fa"! de doi.

7.1.1. Reprezentarea cu bit de semn !i magnitudine


n aceast! reprezentare, numit! "i reprezentare n magnitudine cu semn, cel mai semnificativ bit are rol de semn (1 pentru numere negative, 0 pentru numere pozitive), iar bi#ii r!ma"i dau valoarea. Astfel, pentru numerele cu semn reprezentate pe un octet, bitul 7 reprezint! semnul, ceilal$i valoarea.
semn 7 magnitudine 0

Figura 7.1 Reprezentarea cu bit de semn !i magnitudine

Cel mai mic num!r este 1 1111111, adica 127, cel mai mare num!r este 0 111 1111, adica +127. De unde rezult! c! domeniul de reprezentare al numerelor cu semn pe un octet este -127 ..+127. Se procedeaz! similar pentru numerele reprezentate pe doi octe#i, pe patru octe#i, etc.. Totu"i, la o privire mai atent!, descoperim lucruri nu tocmai pl!cute. De exemplu, valoarea zero are dou! reprezent!ri distincte: 10000000 (-0) "i 00000000 (+0). Lucru care complic! unele opera$ii matematice. Mai mult, opera#iile aritmetice care folosesc reprezentarea cu bit de semn "i magnitudine sunt complexe. Daca adun!m +1 cu 1, rezultatul este -2; rezultat fals (principiul de adunare al numerelor binare este similar cu cel al numerelor zecimale: se adun! cifr! cu cifr! %i se $ine cont de transport): 0000 0001 + 1000 0001 ------------1000 0010 = -2 Enumer!m dezavantajele reprezent!rii n magnitudine "i bit de semn: dou! modalit!#i diferite de a reprezenta valoarea zero; opera#ii aritmetice complexe; numerele cu semn necesit! instruc#iuni aritmetice diferite fa#! de cele ale numerelor f!r! semn.

7.1.2. Reprezentarea n complement fa"# de unu


Num!rul negativ este reprezentat ca fiind complementul fa#! de unu al num!rului pozitiv. Complementul fa#! de unu nseamn! c! se inverseaz! num!rul pozitiv bit cu bit (1 devine 0 "i 0 devine 1). Complementul fa#! de unu al num!rului 0000 0001 este 1111 1110, al num!rului 0101 1100 este 1010 0011, ".a.m.d. n aceast! reprezentare, num!rul -127 ar fi complementul fa#! de unu al

num!rului 127. Cum 127 n binar este 0111 1111, complementul lui fa"! de unu, #i implicit num!rul -127, va fi 1000 0000. Num!rul -1 este complementul fa"! de unu al #irului binar 0000 0001, adic! 1111 1110. Dar #i de aceast! dat! avem dou! reprezent!ri diferite pentru valoarea 0: 0000 0000 (+0) #i 1111 1111 (-0), cu efecte nedorite n efectuarea unor opera"ii matematice. n plus, aritmetica n complement fa"! de unu este la fel de complicat!.

7.1.3. Reprezentarea n complement fa!" de doi


Am specificat de la nceput c! arhitectura Intel reprezint! numerele ntregi cu semn prin metoda complementului fa"! de doi. Aceast! metod! rezolv! problemele aritmetice ale reprezent!rilor cu bit de semn #i magnitudine sau complement fa"! de unu printr-un simplu artificiu matematic: reprezentarea negativ! a unui num!r se ob$ine prin adunarea lui 1 la complementul fa"! de unu al reprezent!rii pozitive. Asfel, -1 este reprezentarea n complement fa"! de unu a lui 0000 0001, plus 1: 1111 1110 + 1 ---------1111 1111 A#adar, -1 este reprezentat ca fiind #irul de bi"i: 1111 1111. -2, este complementul fa"! de unu al %irului binar 0000 0010, plus 1: 1111 1101 + 1 ---------1111 1110 Pe baza aceluia%i principiu ob$inem: ntreg cu semn Reprezentare -3 1111 1101 ... - 127 1000 0001 - 128 1000 0000 ... +127 0111 1111 +126 0111 1110 ...

2 1 0

0000 0010 0000 0001 0000 0000

Acest mecanism rezolv! toate problemele care afecteaz! modurile de reprezentare discutate anterior. De exemplu, -1 + 1 = 0 CF = 1 1111 1111 + 0000 0001 -----------0000 0000

Carry Flag (CF) este ignorat n aritmetica numerelor cu semn. n concluzie: avem o singur! reprezentare pentru valoarea 0, adunarea se realizeaz! u"or, adunarea "i sc!derea numerelor, cu sau f!r! semn, folose#te acelea"i circuite hardware (acelea"i ciruite logice). Domeniul de reprezentare al numerelor cu semn este dat n Tabelul 7.1.
Tabelul 7.1 Domeniul de reprezentare al ntregilor cu semn

Bi!i de reprezentare 8 16 32

Plaj" de valori -128 ..+127 -32 768 ..+32 767 -2 147 483 648 ..+ 2 147 483 647

Nu trebuie s! confunda$i numerele f!r! semn cu numerele pozitive cu semn. De exemplu, domeniul de reprezentare pentru numere f!r! semn, de 32 de bi$i, este 0 .. 4 294 967 295, iar domeniul numerelor pozitive cu semn de 32 de bi$i este 0 ..+ 2 147 483 647. Reprezentarea ntregilor cu semn, ca #i cea a ntregilor f!r! semn, are natur! circular!. Pentru un anumit num!r de bi$i, exist! o grani$! la care reprezentarea numerelor negative se continu! cu cea a numerelor pozitive, sau invers. De asemenea, observ!m c! toate valorile negative ncep cu bit de 1 "i toate valorile pozitive cu bit de 0. n consecin$!, avem posibilitatea s! deducem imediat dac! un num!r este negativ sau pozitiv. Din aceast! perspectiv!, putem considera bitul cel mai semnificativ ca fiind bit de semn. Re$ine$i totu#i c! acest bit nu este bit de semn propriu-zis (n sensul reprezent!rii cu bit semn #i magnitudine), nu semnific! semnul exclusiv, ci intr! n procesul de calcul al valorii. Altfel spus, indic! semnul, nu l reprezint!.

Urm!torul program ne permite s! studiem reprezentarea binar! a ntregilor cu "i f!r! semn. ; ;intSemn.asm ; section .data b1 db -127 ;10000001 b2 db 127 ;01111111 b3 db -1 ;11111111 w1 dw -32768 ;10000000 00000000 w2 dw 32767 ;01111111 11111111 w3 dw -1 ;11111111 11111111 d1 dd -1 ;11111111 11111111 11111111 11111111 d2 dd -45 ;11111111 11111111 11111111 11010011 section .text global _start _start: nop mov al,[b1] mov bl,[b2] mov cl,[b3] mov ax,[w1] mov bx,[w2] mov cx,[w3] mov eax,[d1] mov ebx,[d2] mov eax,1 mov ebx,0 int 080h Rula#i programul prin intermediul depanatorului GDB. Identifica#i fiecare valoare prezent! n memorie. (gdb) x /1bd &b1 0x80490c0 <b1>: -127 (gdb) x /1bt &b1 0x80490c0 <b1>: 10000001 (gdb) x /1hd &w1 0x80490c3 <w1>: -32768 (gdb) x /1ht &w1

0x80490c3 <w1>: 1000000000000000 Executa!i prima instruc!iune "i afi"a#i registrele AL "i EAX prin comenzile info reg al "i info reg eax. (gdb) i r al al 0x81 (gdb) i r eax eax 0x81 -127 129

Verifica#i reprezentarea binar$: (gdb) p /t $al $2 = 10000001 (gdb) p /t $eax $3 = 10000001 Reprezentarea n hexazecimal a %irului 1000 0001 este n ambele cazuri 0x81, dar valoarea zecimal$ difer$. Depanatorul interpreteaz$ aceea"i reprezentare binar$ ca fiind -127 n registrul AL "i 129 n registrul EAX. Nu este nicio eroare. Aceea%i reprezentare binar$ este interpretat$ diferit. De fapt, orice reprezentare binar$ a ntregilor poate fi interpretat$ n dou$ moduri, cu semn %i f$r$ semn. Cnd judec$ o valoare, depanatorul se ghideaz$ dup$ dimensiunea reprezent$rii "i valoarea bitului de semn. Am specificat anterior c$ bitul cel mai semnificativ indic$ semnul. n acest caz, instruc!iunea mov al, [b1] introduce n registrul AL valoarea binar$ 1000 0001, interpretat n zecimal ca fiind 127, deoarece bitul cel mai semnificativ al octetului este 1. Depanatorul judec$ la fel de corect "i valoarea prezent$ n registrul EAX. Urm$toarea reprezentare a registrului EAX ne ajut$ s$ n#elegem mai u"or fenomenul cu care ne confrunt$m. Din cei patru octe!i prezen#i n EAX, AL reprezint$ octetul mai pu!in semnificativ. 0000000000000000
31

00000000 AH

10000001 AL 0

De%i depanatorul, la judecarea valorii din EAX, nu arat$ bi!ii de 0 din fa!a registrului AL, ace%tia sunt lua!i n considerare. Dac$ judec$m din aceast$ perspectiv$ valoarea zecimal$ existent$ n EAX, ob#inem chiar 129 (MSB = 0).

Ca regul! general!, valorile registrelor, atunci cnd sunt afi"ate n zecimal, sunt judecate ca fiind cu semn. Situa!ia discutat" semnalizeaz" un lucru extrem de util: are foarte mare importan#! ceea ce se afl! anterior n registre. Dac" introducem o valoare n AL, nu trebuie s" consider"m c" registrul EAX are acea valoare.

7.2. Extinderea ntregilor


n sec!iunea precedent" am v"zut cum sunt judecate valorile din registre. Cteodat" avem nevoie s" exindem valoarea unui ntreg (de la octet la cuvnt sau de la cuvnt la dublu cuvnt). Extinderea ntregilor f!r! semn Dac" rul"m programul de mai jos ; ;faraSemn.asm ; section .data val db 127 section .text global _start _start: nop mov eax,0ffffaaaah mov al,[val] ;movzx eax, al mov eax,1 mov ebx,0 int 080h observ"m c" valoarea din registrul EAX este eronat" (presupunnd c" dorim s" avem n EAX valoarea 127). Pentru a ob#ine un rezultat corect, ar fi trebuit n prealabil s" ini#ializ"m registrul EAX cu zero. ns" Intel a pus la dispozi#ie o instruc#iune capabil" s" extind" un ntreg f"r" semn, completnd cu zero ceilal#i octe#i. Sintaxa instruc#iunii este

movzx destina!ie,surs" unde sursa poate fi registru sau loca!ie de memorie de 8 sau 16 bi!i, iar destina!ia registru de 16 sau 32 de bi!i. Activa"i instruc!iunea MOVZX din program #i studia!i efectul acesteia. Extinderea ntregilor cu semn ; ;cuSemn.asm ; section .data val db -127 section .text global _start _start: nop mov al,[val] movsx eax,al mov eax,1 mov ebx,0 int 080h n programul de mai sus, rezultatul este cel a#teptat numai dup$ folosirea instruc!iunii movsx destina!ie,surs" La fel ca n cazul instruc"iunii MOVZX, sursa poate fi registru sau loca!ie de memorie de 8 sau 16 bi!i, iar destina!ia registru de 16 sau 32 de bi!i. Extinderea ntregilor cu semn este diferit$ de extinderea ntregilor f$r$ semn. n cazul numerelor negative, MOVSX completeaz$ bi!ii de semn cu 1, nu cu 0. Bi!ii de zero ar schimba valoarea numerelor negative. De exemplu, octetul -1 (11111111) nc$rcat ntr-o loca!ie de tip cuvnt unde octetul superior este completat cu bi!i de 0, d$ 0000000011111111, care n nota!ia cu semn este +127, nu -1. Pentru a se p$stra valoarea unui ntreg cu semn, bi!i introdu%i trebuie s$ fie de acela#i tip cu bitul de semn. n acest caz, se ob"ine valoarea 11111111111111. n nota!ia cu semn, un #ir de bi!i de 1 reprezent$ -1. n cazul unui num$r pozitiv, extinderea se face cu bi!i de 0. Modifica"i valoarea lui val n 127.

7.3. Indicatori de stare


Indicatorii de stare au fost men!iona"i fugitiv n sec"iunea dedicat# arhitecturii IA-32, cnd am discutat rolul registrul EFLAGS. Am afirmat la momentul respectiv c# fiecare bit din registrul EFLAGS are rol de sine st#t#tor $i se nume$te indicator de stare. Un indicator de stare reprezint# un singur bit de informa!ie, a c#rui semnifica!ie este independent# de oricare alt bit. Pozi!ionat ini!ial n 0, la apari!ia unui eveniment specific comut# n 1, semnaliznd astfel o anumit# condi"ie prezent# la nivelul procesorului. Un program poate testa condi"ia respectiv# %i ac!iona n consecin"#. Totodat#, prin modificarea unui indicator de stare, programatorul poate seta un anumit comportament al procesorului. &ase din ace%ti indicatori de stare sunt folosi"i exclusiv pentru monitorizarea condi"iilor rezultate n urma opera"iilor aritmetice %i logice, sau nrudite. Ace%tia sunt: Indicatorul de zero (ZF Zero Flag); Indicatorul de transport (CF Carry Flag); Indicatorul de dep#%ire (OF Overflow Flag); Indicatorul de semn (SF Sign Flag); Indicatorul de transport la jum#tate (AF Auxiliary Flag); Indicatorul de paritate (PF Parity Flag).

7.3.1. Indicatorul de zero


Rolul indicatorului de zero este s# indice dac# rezultatul ultimei opera!ii aritmetice sau logice este nul. Dac# rezultatul este zero, indicatorul ZF se pozi"ioneaz# automat n 1 (la prima vedere acest lucru este confuz, dar aminti"i-v# c# indicatorii de stare sunt ini"ial pozi"iona"i n 0 %i comut# n 1 numai la apari"ia unui eveniment). Re"ine"i c# nu con"inutul unui registru modific# indicatorul ZF, ci numai rezultatul unei opera"ii aritmetice sau logice. De exemplu, o instruc"iune care ncarc# valoarea zero n acumulator mov eax,0 nu trece ZF n 1, pentru c# opera"ia de transfer nu este aritmetic# sau logic#. n schimb, opera"ia de sc#dere afecteaz# acest indicator. Posibilitatea de apari"ie a unui rezultat nul n urma unei opera"ii de sc#dere este destul de evident#, lucru care nu se poate spune n cazul altor opera"ii. De exemplu, o adunare pe 8 bi"i sau incrementarea/decrementarea unor valori nvecinate cu zero.

0000 1111 + 1111 0001 0000 0000

1111 1111 + 0000 0001 0000 0000

0000 0001 0000 0001 0000 0000

Indicatorul de zero este folosit n principal n cazuri de testare a egalit!"ii unor valori #i num!rare pn! la o valoarea prestabilit!. Din acest motiv, este folosit extensiv de instruc$iunile de salt condi$ionat.

7.3.2. Indicatorul de transport


Indicatorul de transport este utilizat n opera!iile aritmetice f"r" semn. Indicatorul de transport semnalizeaz! faptul c! rezultatul unei opera"ii aritmetice ntre numere f!r! semn a dep!#it intervalul (prea mare sau prea mic) corespunz!tor capacit!$ii destina"iei (registru sau loca"ie de memorie). De exemplu, atunci cnd se execut! o adunare ntre dou! numere f!r! semn, este posibil s! rezulte transport spre rangul superior, care dep!%e%te dimensiunea registrului ce con$ine rezultatul. n mod asem!n!tor, la sc!derea unor numere f!r! semn, poate ap!rea necesitatea unui mprumut de la rangul superior. n aceste cazuri, indicatorul CF se pozi"ioneaz! n 1. 0100 1000 + 0000 0011 0100 1011
adunare f!r! transport(CF=0)

1000 1000 + 1000 0011 0000 1011

adunare cu transport(CF=1)

Indicatorul de transport este setat atunci cnd se dep!#e#te capacitatea de reprezentare a destina"iei n condi"iile unei opera"ii cu ntregi f!r! semn. Capacitate (bi!i) 8 16 32 Domeniu de reprezentare 0 .. 255 0 .. 65 535 0 .. 4 294 967 295

Orice opera"ie care genereaz! un rezultat ce dep!%e%te limitele acestor domenii de reprezentare este semnalizat! cu CF = 1. Este evident c! orice rezultat negativ se g!se#te n afara domeniului de reprezentare. De exemplu, BE BF = FF #i CF = 1:

1011 1110 1011 1111 1111 1111

Instruc!iunile aritmetice pot opera cu date de 8, 16 sau 32 de bi!i. Dac" sunt aduna!i operanzi mai mari de 32 de bi!i, se nsumeaz" pe rnd dou" numere de 32 de bi!i. Urm"torul exemplu ilustreaz" cum putem aduna pe arhitecturi de 32 de bi!i dou" numere ntregi f"r" semn de 64 de bi!i (folosim reprezentarea hexazecimal"): 1 # transport din prima adunare 2610 15E8 1357 9AE7 + 59AC B341 FE70 5324 7FBC C92A 11C7 EE0B Efectu"m dou" opera!ii de adunare. nti adun"m primii 32 de bi!i mai pu!in semnificativi ai operanzilor. Se ob!ine jum"tatea inferioar" a rezultatului. Totodat", aceast" opera!ie de adunare poate produce transport, lucru care seteaz" indicatorul de transport. A doua opera!ie nsumeaz" urm"torii 32 de bi!i ai operanzilor mpreun" cu indicatorul de transport generat de prima adunare. Acest" opera!ie produce jum"tatea superioar" a rezultatului de 64 de bi!i. n mod similar, adunarea a dou" numere de 128 de bi!i implic" un proces n patru etape, n fiecare se adun" cuvinte de 32 de bi!i.

7.3.3. Indicatorul de dep!"ire


Indicatorul de dep!"ire este utilizat n opera#iile aritmetice cu semn. Indicatorul de dep"$ire este echivalentul indicatorului de transport pentru aritmetica numerelor cu semn. Rolul principal al indicatorului de dep"$ire este s" indice dac" rezultatul unei opera!ii cu numere cu semn a dep"$it domeniul de reprezentare. Ne amintim c" domeniul de reprezentare al numerelor cu semn pe 8, 16 $i 32 de bi!i este: Capacitate (bi!i) 8 16 32 Domeniu de reprezentare -128 ..+127 -32 768 ..+32 767 -2 147 483 648 ..+2 147 483 647

Cnd se execut" opera%ii aritmetice ntre operanzi cu semn, este posibil s" apar" bit de transport c"tre bitul de semn, ceea ce face ca rezultatul s" fie eronat. Indicatorul de dep"&ire semnalizeaz" generarea unui transport de la bitul 6 c"tre 7,

14 c!tre 15, sau 30 c!tre 31, n func"ie de num!rul de bi"i ai reprezent!rii. Altfel spus, OF semnalizeaz! valorile interzise ale rezultatului n cazul opera#iilor n complement fa#! de doi. De exemplu, adun!m +127 cu +127. 0111 1111 + 0111 1111 1111 1110 Num!rul +127 este reprezentat pe un octet cu semn ca 0111 1111. MSB (Most Significant Bit) este 0. Cnd adun!m ob#inem rezultatul 1111 1110, rezultat eronat n logica aritmeticii cu semn. MSB este 1 $i nu 0, a$adar 1111 1110 va fi interpretat ca num!r negativ, adic! -2. n astfel de situa#ii, indicatorul de dep!%ire se pozi"ioneaz! n 1.

7.3.4. Indicatorul de semn


SF indic! semnul rezultatului unei opera"ii. A%adar, este util numai cnd efectu!m opera#ii aritmetice ntre numere cu semn. Dac! rezultatul ultimei opera#ii este negativ, SF devine 1. Indicatorul de semn este copia valorii bitului de semn al rezultatului unei opera"ii aritmetice. Pe lng! principala func"ie a indicatorului de semn, care const! n testarea semnului pentru rezultatul generat de o opera"ie aritmetic!, acesta se mai folose%te la implementarea buclelor de num!rare, unde itera"iile sunt efectuate pn! cnd variabila de control este zero. Din punctul de vedere al utilizatorului, semnul unui num!r poate fi testat printr-o instruc"iune de deplasare logic!. Comparativ cu ceilal"i trei indicatori de stare prezenta"i pn! acum, indicatorul de semn este utilizat relativ rar n programe. Totu%i, procesorul utilizeaz! bitul de semn n cazul execu"iei instruc"iunilor de salt condi"ionat.

7.3.5. Indicatorul de transport la jum!tate


Indicatorul de transport la jum!tate basculeaz! n 1 dac! n cadrul unei opera#ii aritmetice exist! transport de la bitul trei la bitul patru (sau mprumut de la bitul patru la bitul 3. De exemplu: 1 0000 1000 1001 & transport 1000 + 1000 0000 1 0010 0101 1100 ' mprumut 1011 1100 1111

7.3.6. Indicatorul de paritate


Indicatorul de paritate se folose!te de obicei la controlul de paritate, metod" elementar" de detectare a erorilor ce pot ap"rea la transferul datelor pe magistrale sau n comunica#iile seriale, etc.. Indicatorul PF se pozi$ioneaz" n 1 atunci cnd num"rul bi#ilor de 1 dintr-un cuvnt este par. De exemplu, dac" rezultatul unei opera#ii aritmetice este 0E3H, deoarece 1110 0011 con#ine un num"r impar de bi#i de 1, PF devine 0. Similar, rezultatul 33H va seta indicatorul de paritate n 1, deoarece 0011 0011 con#ine un num"r par (patru) de bi#i de 1. Trebuie s! re"inem c! descrierile anterioare sunt numai generaliz!ri #i sunt influen"ate de modul de lucru impus de instruc"iunile individuale. Setarea indicatorilor de stare variaz! de la instruc"iune la instruc"iune. De exemplu, sunt instruc"iuni aritmetice care pot produce o valoare de zero pentru rezultatul final, dar care nu seteaz! indicatorul de zero. Comportamentul unei instruc"iuni cu privire la influen$area indicatorilor de stare trebuie verificat prin studierea manualului de instruc$iuni. Dou" exemple elocvente sunt instruc#iunile INC !i DEC. Acestea incrementeaz", respectiv decrementeaz", un operand. Ambele folosesc un singur operand, care poate fi registru sau loca#ie de memorie. ; ;incDec.asm ; section .text global _start _start: nop mov eax, 0fffffffh mov ebx, 0 inc eax dec ebx mov eax,1 mov ebx,0 int 80h Studia#i efectele instruc$iunilor de incrementare !i decrementare. Comanda info reg eflags afi%eaz" registrul indicatorilor de stare. Incrementarea registrului EAX transform" valoarea acestuia n 0. n mod normal, ar fi trebuit ca indicatorul de transport s" fie pozi$ionat n 1, dar nu este.

Indicatorul de transport nu este afectat de instruc!iunea INC. Instruc"iunile INC #i DEC nu influen"eaz$ indicatorul de transport. Motivele sunt dou$: Instruc"iunile INC #i DEC sunt folosite n special la contorizarea itera"iilor unor bucle. Cu 32 de bi"i, num$rul de itera"ii maxim este 4 294 967 295. Acest num$r este destul de mare pentru majoritatea aplica"iilor. n plus, dac$ acesta este dep$#it, deoarece INC #i DEC modific$ valoarea numai cu valori de 1, condi"ia detectat$ de indicatorul de transport este detectat$ #i de indicatorul de zero. De exemplu, presupunem c$ registrul ECX ajunge la valoare sa maxim$ 4 294 967 295 (FFFFFFFFH). Dac$ execut$m INC ECX ne a#tept$m ca indicatorul de transport s$ fie setat n 1. Totu#i, detect$m aceast$ condi"ie #i prin faptul c$ ECX = 0, eveniment care seteaz$ indicatorul de zero. n consecin"$, pentru aceste instruc"iuni, modificarea indicatorului de transport este redundant$.

7.4. Instruc!iuni de transfer condi!ionat


Instruc!iunile de transfer condi!ionat au ap$rut ncepnd cu familia de procesoare P6 (Pentium Pro, Pentium II, %i mai noi). O instruc!iune MOV condi!ional$ (CMOV Conditional Move) este o instruc!iune MOV efectuat$ numai dac$ sunt satisf$cute anumite condi!ii. Sintaxa general$ este CMOV<x> destina!ie,surs" unde x reprezint$ una sau dou$ litere care specific$ condi!ia ce va declan%a instruc!iunea MOV. Condi!iile sunt bazate pe valorile curente din registrul EFLAGS. Bi!ii folosi!i de instruc!iunile MOV condi!ionale sunt CF, OF, PF, SF, ZF. Instruc!iunile condi!ionale sunt mp$r!ite n: instruc!iuni de transfer condi!ionat pentru opera!ii f$r$ semn (la determinarea diferen!ei ntre doi operanzi sunt folosi!i indicatorii CF, ZF, PF).
Tabelul 7.2 Instruc!iuni MOV condi!ionale pentru operanzi f"r" semn

Instruc!iune CMOVA/CMOVNBE CMOVAE/CMOVNB CMOVNC CMOVB/CMOVNAE

Descriere above/not below or equal above or equal/not below not carry below/not above or equal

Condi!ie (CF sau ZF) = 0 CF = 0 CF = 0 CF = 1

CMOVC CMOVBE/CMOVNA CMOVE/CMOVZ CMOVNE/CMOVNZ CMOVP/CMOVPE CMOVNP/CMOVPO

carry below or equal/not above equal/zero not equal/not zero parity/parity even not parity/parity odd

CF = 1 (CF sau ZF) = 1 ZF = 1 ZF = 0 PF = 1 PF = 0

Instruc!iuni de transfer condi!ionat pentru operanzi cu semn (la determinarea condi!iei folosesc indicatorii SF "i OF).
Tabelul 7.3 Instruc!iuni MOV condi!ionale pentru operanzi cu semn

Instruc!iune CMOVGE/CMOVNL CMOVL/CMOVNGE CMOVLE/CMOVNG CMOVO CMOVNO CMOVS CMOVNS

Descriere greater or equal/not less less/not greater or equal less or equal/not greater overflow not overflow sign (negative) not sign

Condi!ie (SF xor OF) = 0 (SF xor OF) = 1 ((SF xor OF) or ZF) = 1 OF = 1 OF = 0 SF = 1 SF = 0

Instruc!iunile de transfer condi!ionat se g#sesc n perechi, deoarece o valoare val1 poate fi mai mare dect o valoarea val2 (CMOVA), dar la fel de bine val1 nu este mai mic# sau egal# cu val2 (CMOVNBE). ; ;transfCond.asm ; section .data val dd 105,106,107,100,110,103 section .text global _start _start: nop mov ebx,[val] mov edi,1 mov eax,[val+edi*4] cmova ebx,eax ;dac# EAX > EBX, atunci EBX = EAX = 106 inc edi mov ecx,[val+edi*4] cmovnbe ebx,ecx ;dac# ECX ! $ EBX, atunci EBX = ECX = 107 mov eax,1

mov ebx,0 int 080h

7.5. Opera!ii aritmetice


Instruc!iunile aritmetice realizeaz" opera!iile aritmetice elementare (adunare, sc"dere, nmul!ire, mp"r!ire). Fiecare instruc!iune afecteaz" o parte din indicatorii de stare SF, ZF, AF, CF, OF, numi!i din acest motiv #i indicatori aritmetici.

7.5.1. Instruc!iuni de adunare


Opera$ia de adunare a ntregilor se efectueaz" cu instruc!iunea ADD. add destina!ie,surs" unde sursa poate fi un imediat, un registru sau loca!ie de memorie de 8, 16, 32 de bi!i, iar destina!ia registru sau loca!ie de memorie de 8, 16 sau 32 de bi!i. Rezultatul adun"rii se p"streaz" n destina!ie. Indicatorii de stare sunt seta!i n concordan!" cu rezultatul opera!iei. Observa!ii: operanzii nu pot fi simultan loca!ii de memorie; operanzii trebuie s" aib" aceea#i dimensiune. ; ;adunare1.asm ; section .text global _start _start: nop xor ax,ax mov al,100 add al,[val] movsx ecx,al ;num"rul din AL este considerat cu semn mov bx,50 add bx,45 add bx,-1 movsx ebx,bx ;instruc$iune redundant" (explica$i de ce)

add ebx,10 mov eax,1 mov ebx,0 int 080h section .data val db 132 Indiferent de semnul ntregilor, instruc!iunea ADD execut" adunarea corect, ceea ce nseamn" c" poate fi folosit" att pentru ntregi cu semn ct #i pentru ntregi f"r" semn. Dac" rul"m programul de mai jos: ; ;adunare2.asm ; section .text global _start _start: nop xor eax,eax xor ebx,ebx mov al,254 mov bl,1 add bl,al mov eax,1 mov ebx,0 int 080h n registrul BL vom avea rezultatul 255. nc"rc"m n BL valoarea 2 #i reasambl"m. Cnd rul"m pas cu pas suntem foarte aten!i la registrul indicatorilor de stare. naintea instruc!iunii de adunare ADD BL,AL, singurul indicator setat este IF. n urma adun"rii, rezultatul din BL este 0, iar registrul indicatorilor de stare are setat CF. Indicatorul de transport semnalizeaz" c" a fost dep!"it domeniul de reprezentare al numerelor f!r! semn pe un octet. Dup" cum #tim, valoarea maxim" a unui num"r f"r" semn pe un octet este 255. Rezultatul adun"rii 254 + 2 este 256. Indicatorul de transport a semnalat dep"#irea capacit"!ii registrului care trebuia s" con!in" rezultatul, adic" apari!ia unui transport spre rangul superior. Cnd lucr!m cu ntregi f!r! semn, CF semnalizeaz! faptul c! rezultatul adun!rii a dep!"it limita domeniului de reprezentare. Dac! nu suntem siguri c!

adunarea operanzilor se ncadreaz! n domeniu trebuie ntotdeauna s! verific!m indicatorul de transport. n cazul ntregilor cu semn, indicatorul de transport este lipsit de importan!" - acesta va fi setat ori de cte ori rezultatul este num"r negativ (vezi sc"derea), indiferent dac" este valid sau nu. n schimb, atunci cnd folosim ntregi cu semn, trebuie s" !inem eviden!a indicatorului de dep"#ire (OF). Introduce$i n program urm"toarele instruc$iuni %i observa$i efectul: mov bl,2 mov al,127 add bl,al n urma urma opera$iri de adunare ntre AL = 127 %i BL = 2, indicatorul de dep"%ire este setat, indicnd dep"#irea limitei superioare a domeniului de reprezentare pentru numere cu semn: [-128 ..+127]. Adunarea numerelor mai mari de 32 de bi!i Instruc$iunea ADD permite adunarea operanzilor de 8, 16 sau 32 de bi$i. Presupunem c" dorim s" adun"m dou" numere de 64 de bi!i fiecare: 401D0219D18D50E1H #i 4016EDECE09C1528H. Deoarece sunt reprezentate pe 64 de bi!i, nu le putem aduna direct (nu avem la dispozi!ie registre de 64 de bi!i). De aceea, fiecare num"r va fi reprezentat pe cte dou" registre de 32 de bi!i. EAX 401d0219 ECX 4016edec EBX d18d50e1 EDX e09c1528

Mecanismul a fost prezentat n sec$iunea dedicat" indicatorului de transport. Presupune dou" etape. n prima etap" se adun" cuvintele de 32 de bi$i din dreapta. n a doua etap" se adun" cuvintele de 32 de bi$i din stnga, plus eventualul transport generat de adunarea anterioar". Pentru acest lucru, pe lng" instruc!iunea ADD, Intel a pus la dispozi$ie %i instruc!iunea ADC (Add with Carry). adc destina!ie,surs" unde destina!ia #i sursa respect" acelea%i reguli men$ionate la ADD. Numai c", spre deosebire de instruc!iunea ADD, ADC adun" la suma celor doi operanzi #i valoarea lui CF (0 sau 1).

A!adar, vom aduna registrele EBX "i EDX, apoi registrele EAX "i ECX, rezultatul final reg#sindu-se n EAX:EBX. ncepem prin adunarea registrelor EBX, EDX folosind ADD. Deoarece este posibil ca suma celor dou# valori s# dep#"easc# domeniul de reprezentare adic# s# fie setat CF, urm#toarele dou# registre: EAX "i ECX, vor fi adunate cu ADC. ; ;add64bit.asm ; section .data alfa dq 0401d0219d18d50e1H beta dq 04016edece09c1528H section .bss rez resd 2 section .text global _start _start: nop mov ebx,[alfa] mov eax,[alfa+4] mov edx,[beta] mov ecx,[beta+4] add ebx,edx adc eax,ecx mov dword [rez],ebx mov dword [rez+4],eax mov eax,1 mov ebx,0 int 080h Se ruleaz# urmrindu-se evolu$ia CF dup# prima adunare. Adunarea unor valori de dimensiune diferit! Cnd adun#m dou# valori de dimensiuni diferite trebuie s# fim aten$i la conversia acestora. ; ;adunare3.asm ; section .data b db 100

w dw 300 d dd 65800 section .text global _start _start: nop mov al,[b] mov bx,[w] movsx ax,al add bx,ax mov ax,[w] mov ecx,[d] movsx eax,ax add ecx,eax mov eax,1 mov ebx,0 int 080h

;convertim octet la cuvnt

;convertim cuvnt la dublu cuvnt

Programul folose!te instruc"iunea MOVSX. Alte instruc"iuni de extindere sunt: CBW (Convert Byte to Word) extinde AL la AX; fiecare bit din AH ia valoarea celui mai semnificativ bit (bitul de semn) din AL. CWD (Convert Word to Double word) extinde AX la DX:AX; fiecare bit din DX ia valoarea MSB-ului din AX. CWDE (Convert Word to Double EAX) extinde AX la EAX CDQ (Convert Double word to Quad) extinde EAX la EDX:EAX; fiecare bit din EDX ia valoarea MSB-ului din EAX.

Another thing I regret is that some of my well-chosen instruction mnemonics were renamed when the instruction set was published. I still think it's catchier to call the instruction SIGN-EXTEND, having the mnemonic of SEX, than to call it CONVERT-BYTE-TO-WORD with the boring mnemonic CBW. Stephen Morse Toate aceste instruc"iuni extind o valoare mai mic# la una mai mare prin replicarea bitului de semn al valorii originare. ; ;intExt.asm

; section .data b1 db 100 b2 db -100 w dw 300 d1 dd 65800 d2 dd -354059 section .text global _start _start: nop mov al,[b2] cbw mov al,[b1] cbw mov bx,[w] add ax,bx mov ax,[w] cwde mov ecx,[d1] add eax,ecx mov eax,[d1] cdq mov eax,[d2] cdq mov eax,1 mov ebx,0 int 080h

;AH = FFh - bitul de semn a lui AL ;AH = 00H - bitul de semn a lui AL

;EDX = 0000H - bitul de semn a lui EAX ;EDX = FFFFh - bitul de semn a lui EAX

7.5.2. Instruc!iuni de sc"dere


Instruc!iunea SUB scade sursa din destina!ie, rezultatul fiind stocat n destina!ie: sub destina!ie,surs" unde sursa poate fi un imediat, un registru sau loca!ie de memorie de 8,

16, 32 de bi!i, iar destina!ia registru sau loca!ie de memorie de 8, 16 sau 32 de bi!i. Indicatorii de stare sunt seta!i n concordan!" cu rezultatul opera!iei. Observa!ii: operanzii nu pot fi simultan loca!ii de memorie; operanzii trebuie s" aib" aceea#i dimensiune. ; ;scadere1.asm ; section .text global _start _start: nop xor ax,ax mov al,100 sub al,[val] movsx ecx,al ;num"rul din AL este considerat cu semn mov bx,50 sub bx,45 sub bx,-1 movsx ebx,bx sub ebx,10 mov eax,1 mov ebx,0 int 080h section .data val db 90 Instruc!iunea SUB execut" corect sc"derea indiferent de semnul ntregilor, ceea ce nseamn" c" poate fi folosit" att pentru ntregi cu semn ct #i pentru ntregi f"r" semn. Dac" rul"m programul urm"tor ; ;scadere2.asm ; section .text global _start _start: nop

;instruc$iune redundant" (explica$i de ce)

xor xor mov mov sub

eax,eax ebx,ebx al,4 bl,2 bl,al

mov eax,1 mov ebx,0 int 080h n registrul BL vom avea rezultatul -2. Rul!m pas cu pas "i suntem foarte aten#i la registrul indicatorilor de stare. naintea instruc#iunii de sc!dere SUB BL,AL, singurul indicator setat este IF. Dup! sc!dere, rezultatul din BL devine 0 iar registrul indicatorilor de stare are setat CF. Indicatorul de transport semnalizeaz! c! a fost dep!"it domeniul de reprezentare al numerelor f!r! semn pe un octet. Dup! cum "tim, valoarea minim! a unui num!r f!r! semn pe un octet este 0. Rezultatul sc!derii 2 4 este -2. Indicatorul de transport a semnalat dep!"irea limitei inferioare a domeniului de reprezentare a numerelor f!r! semn. Cnd sc!dem dou! numere f!r! semn, CF semnalizeaz! trecerea rezultatului sub valoarea zero. n cazul numerelor considerate cu semn, acest lucru se ntmpl! foarte des "i CF este lipsit de importan#!. n schimb, trebuie s! #inem cont de indicatorul OF. S! judec!m urm!torul exemplu: ; ;scadere3.asm ; section .text global _start _start: nop mov eax,7 mov ebx,3 sub ebx,eax jc sfarsit mov eax,1 int 080h sfarsit:

mov eax,1 mov ebx,0 int 080h Programul scade dou! numere f!r! semn: 3 "i 7 (ambele pozitive). Deoarece rezultatul sc!derii este un num!r negativ (3 7 = - 4), instruc#iunea de salt va fi executat!. La sfr"itul programului vom avea n EBX valoarea 0 (n cazul unui rezultat pozitiv, saltul nu s-ar fi executat). C!nd sc!dem dou! numere f!r! semn, 3 "i 7, un rezultatul mai mic de zero este considerat invalid (pentru c! limita minim! de reprezentare a numerelor f!r! semn este 0). Totu"i, n ciuda faptului c! valorile se presupuneau a fi f!r! semn "i rezultatul invalid, procesorul trece rezultatul -4 n EBX. De ce? Deoarece procesorul nu "tie ce fel de numere gndim noi, cu sau f!r! semn, el ia n calcul ambele variante "i seteaz! indicatorii de stare CF "i OF n concordan#!. Programul trebuie s! determine dac! valoarea este n afara domeniului de reprezentare al ntregilor cu/f!r! semn. n cazul sc!derii unor ntregi f!r! semn, CF indic! faptul c! aceasta s-a soldat cu rezultat negativ. n ce prive"te ntregii cu semn, din moment ce rezultatul poate fi negativ $i CF nu este semnificativ, trebuie s! ne baz!m pe OF, care semnalizeaz! dep!"irea domeniului de reprezentare a numerelor cu semn. n concluzie, procesorul nu "tie dac! numerele sunt cu semn sau f!r! semn. El seteaz! CF sau OF lund n calcul ambele posibilit!#i. CF setat dac! a fost dep!"it domeniul de reprezentare al numerelor f!r! semn. o [0 ..255] pentru 8 bi#i o [0 ..65535] pentru 16 bi#i o [0 ..4294967295] pentru 32 de bi#i n cazul unui octet putem reprezenta astfel: CF = 1 0 f!r! semn 255 CF = 1

La adunarea numerelor f!r! semn, CF = 1 cnd rezultatul dep!"e"te valoarea maxim! a reprezent!rii folosite (255, 65535, etc.). La sc!derea numerelor f!r! semn, CF = 1 cnd rezultatul este sub zero. OF setat dac! a fost dep!"it domeniul de reprezentare al numerelor cu semn. o [-128 ..+127] pentru 8 bi#i o [-32768 ..+32767] pentru 16 bi#i

[-2147483648 ..+ 2147483647] pentru 32 de bi!i

n cazul unui octet putem reprezenta astfel: OF = 1 - 128 cu semn OF = 1 +127

OF este setat atunci cnd adun"m sau sc"dem doi ntregi de acela#i semn #i se ob!ine un rezultat de semn diferit. Sc!derea numerelor mai mari de 32 de bi"i Pentru a sc"dea dou" numere de 64 de bi!i, mp"r!im numerele n dou" p"r!i de 32 de bi!i fiecare #i efectu"m opera$ia de sc"dere pe rnd. La a doua opera$ie se scade %i valoarea lui CF. Instruc!iunea necesar" se nume%te SBB (Subtract with Borrow). ; ;sub64bit.asm ; section .data alfa dq 0401d0219d18d50e1h beta dq 04016edece09c1528h section .bss rez resd 2 section .text global _start _start: nop mov ebx,[alfa] mov eax,[alfa+4] mov edx,[beta] mov ecx,[beta+4] sub ebx,edx sbb eax,ecx mov dword [rez],ebx mov dword [rez+4],eax mov eax,1 mov ebx,0

int 080h O instruc!iune nrudit" cu SUB este instruc!iunea NEG. Instruc!iunea NEG calculeaz" complementul fa!" de doi al unei valori. Acela#i rezultat se poate ob!ine prin sc"derea valorii respective din zero, cu instruc!iunea SUB. Instruc!iunea NEG se execut" ns" mai rapid.

7.5.3. Instruc!iuni de comparare


Compararea a doi operanzi se efectueaz" cu instruc!iunea CMP (CoMPare). CMP realizeaz" aceea$i opera%ie ca instruc%iunea SUB, dar nu salveaz" rezultatul. Instruc%iunea cmp destina!ie,surs" simuleaz" sc"derea destina!ie surs", f"r" a genera rezultat. n schimb, sunt modifica%i indicatorii de stare. Instruc!iunea se folose#te pentru testarea unei condi!ii: dac" destina!ie > surs", rezult" ZF=0, CF=0; dac" destina!ie = surs", rezult" ZF=1, CF=0; dac" destina!ie < surs", rezult" ZF=0, CF=1.

7.5.4. Incrementare "i decrementare


Instruc!iunile INC $i DEC au fost deja prezentate. Am v"zut c" sunt folosite la incrementarea #i decrementarea unui ntreg f"r" semn #i nu afecteaz" indicatorul de transport. n acest fel se poate incrementa sau decrementa valoarea unui contor f"r" afectarea opera!iilor de adunare sau sc"dere din interiorul unei bucle. Formatul instruc!iunilor este: inc destina!ie dec destina!ie unde destina!ia poate fi registru sau loca!ie de memorie de 8, 16 sau 32 de bi!i. Instruc!iunile INC "i DEC privesc valoarea din destina!ie ca fiind ntreg f#r# semn. Dac# decrement#m valoarea 0 reprezentat# pe 32 de bi!i, noua valoare va fi FFFFFFFF judecat# 4294967295 (indicatorul de transport nu va fi setat) "i

nu -1 (a!a cum ar fi judecat din perspectiva numerelor cu semn). Aten"ie cnd folosi"i aceste instruc"iuni asupra unor ntregi considera"i ca fiind cu semn.

7.5.5. Instruc!iuni de nmul!ire


nmul!irea numerelor f#r# semn se realizeaz" cu instruc!iunea MUL. mul surs! unde sursa este registru sau loca!ie de memorie de 8, 16 sau 32 de bi!i. Cel"lalt operand al nmul!irii #i rezultatul au loca!ie implicit", dup" cum urmeaz": MUL r/m8, AL este multiplicat cu r/m8 $i rezultatul este stocat n AX. MUL r/m16, AX este multiplicat cu r/m16 $i rezultatul este stocat n DX:AX. MUL r/m32, EAX este multiplicat cu r/m32 $i rezultatul este stocat n EDX:EAX.
Tabelul 7.4 Instruc"iunea de nmul"ire MUL

Surs! 8 bi!i 16 bi!i 32 bi!i

Operand implicit AL AX EAX

Rezultat AX DX:AX EDX:EAX

nmul!irea numerelor cu semn se realizeaz" cu instruc!iunea IMUL. Spre deosebire de instruc!iunea anterioar", ntlnim trei tipuri de instruc!iune IMUL: 1. IMUL cu un singur operand. Are sintaxa identic" cu instruc!iunea MUL. imul surs!
Tabelul 7.5 Instruc"iunea de nmul"ire IMUL cu un singur operand

Surs! 8 bi!i 16 bi!i 32 bi!i

Operand implicit AL AX EAX

Rezultat AX DX:AX EDX:EAX

2. IMUL cu doi operanzi


imul destina"ie,surs!

cu urm!toarele cazuri: imul imul imul imul imul imul r16,r/m16 r32,r/m32 r16,imm8 r16,imm16 r32,imm8 r32,imm32

Aceast! variant! nmul"e#te cei doi operanzi #i stocheaz! rezultatul n operandul destina"ie. 3. IMUL cu trei operanzi imul destina!ie,surs",imediat cu urm!toarele cazuri: imul imul imul imul r16,r/m16,imm8 r16,r/m16,imm16 r32,r/m32,imm8 r32,r/m32,imm16

Aceast! variant! nmul"e#te cei trei operanzi #i stocheaz! rezultatul n operandul destina"ie. Observa"ii: Instruc"iunea cu doi operanzi este o variant! prescurtat! a instruc"iunii cu trei operanzi. n cazurile 2 #i 3 destina"ia are acela#i ordin de m!rime ca sursa. n cazul nmul"irii este foarte ntlnit! situa"ia n care rezultatul are num!r dublu de bi"i fa"! de operanzii nmul"i"i. De aceea, trebuie s! fim aten"i ca nmul"irea celor doi, respectiv trei, operanzi s! nu dep!#easc! capacitatea destina"iei (se verific! cu ajutorul lui CF #i OF).

7.5.6. Instruc!iuni de mp"r!ire


La mp!r"ire, demp!r"itul va avea ntotdeauna un num!r dublu de bi"i fa"! de mp!r"itor, iar n urma opera"iei vom ob"ine un ct #i un rest, fiecare de m!rimea mp!r"itorului. mp!r"irea numerelor f!r! semn se realizeaz! cu instruc"iunea DIV.

div divizor
Tabelul 7.6 Instruc!iunea de mp"r!ire DIV

Demp!r"it AX DX:AX EDX:EAX

Divizor 8 bi!i 16 bi!i 32 bi!i

Ct AL AX EAX

Rest AH DX EDX

Numerele cu semn se mpart cu instruc"iunea IDIV, care respect# n totalitate sintaxa DIV.

7.6. Instruc!iuni de interschimbare a datelor


Cteodat# este necesar s# schimb#m ntre ele valorile a dou# registre. Un dezavantaj al instruc!iunilor MOV este chiar faptul c# nu poate interschimba valorile a dou# registre direct, f#r# a folosi un alt registru intermediar. De exemplu, pentru a interschimba valorile registrelor EAX $i EBX trebuie s# folosim ca intermediar un alt registru, sau o loca!ie de memorie. mov ecx,eax mov eax,ebx mov ebx,ecx Sunt necesare trei instruc!iuni, precum $i un registru liber; consum semnificativ de resurse pentru aceast# opera!ie simpl#. De aceea, setul de instruc!iuni cuprinde cteva instruc!iuni care interschimb# date f#r# intermediar. Cea mai simpl# este XCHG. Instruc!iunea XCHG poate interschimba date ntre dou# registre sau ntre un registru $i o loca!ie de memorie. Operanzii nu pot fi n acela$i timp loca!ii de memorie. Formatul instruc!iunii este: xchg operand1,operand2 Instruc!iunea prime$te operanzi de 8, 16 sau 32 de bi!i, dar ntotdeauna de aceea$i dimensiune. Cu ajutorul acestei instruc!iuni, interschimbarea valorilor din registrele EAX $i EBX necesit# o singur# linie de cod: xchg eax,ebx

Dac! unul din operanzi se afl! n memorie, procesorul activeaz! n mod automat semnalul LOCK (n cazul unei structuri multiprocesor, acest lucru asigur! accesul exclusiv la memorie pentru un singur procesor). De"i util n unele situa#ii mai speciale, acest proces este mare consumator de timp "i penalizeaz! performan#a programelor. Instruc#iunea XCHG este foarte util! n opera#iile de sortare. De asemenea, este la fel de util! n interschimbarea octe#ilor unui cuvnt, procedur! care corespunde conversiei ntre formatele little-endian "i big-endian. De exemplu, xchg al,ah converte"te valoarea din registrul AX dintr-o form! n cealalt!. Gndi#i-v! cum pute#i converti dintr-un format n altul valoarea unui registru de 32 de bi#i. Nu este o problem! lipsit! de semnifica#ie, n unele situa#ii ordinea octe#ilor are mare importan#!. De exemplu, transferul datelor n re#ea se face conform conven#iei bigendian. S! facem un experiment. Am v!zut n capitolele precedente c! asamblorul permite forme interesante de adresare imediat!. De exemplu, urm!toarea instruc#iune este perfect legal! "i nseamn! introducerea unui "ir de caractere n registrul EAX: mov eax,'ABCD' Introduce#i instruc#iunea ntr-un program "i afi"a#i con#inutul registrului EAX imediat dup! execu#ia acesteia: (gdb) i r eax eax 0x44434241
31

1145258561
15 0

'D' (44H)

'C' (43H)

'B' (42H)

'A' (41H)

Figura 7.2 Registrul EAX n reprezentare little-endian

n registrul EAX sunt caracterele ASCII: 'A' (41H), 'B' (42H), 'C' (43H) "i 'D' (44H). Deoarece caracterele ASCII sunt reprezentate pe 8 bi#i, cele patru elemente ale "irului ncap perfect n cei 32 de bi#i ai registrului. Chiar dac! la prima vedere pare c! sunt introduse n ordine invers!, acest lucru nu este adev!rat. Ne aducem aminte c! arhitectura IA-32 lucreaz! conform conven#iei little-endian, care stocheaz! octetul mai pu#in semnificativ la adresa mai mic!. Acest criteriu se aplic! "i la registre. n registrul EAX, AL se afl! pe pozi#ia celui mai pu#in semnificativ octet, urmat de AH "i de ceilal#i doi octe#i. ntr-un "ir de caractere, caracterul mai pu#in semnificativ este cel din extrema stng!. A"adar, 'A' este introdus n registrul

AL, 'B' n registrul AH, !.a.m.d.. Rezultatul este cel men"ionat. Dac# ave"i nc# dubii, introduce"i valoarea 'ABCD' n memorie !i compara"i ordinea octe"ilor. Presupunem c# trebuie s# transmitem con"inutul registrului EAX prin re"ea !i trebuie s#-l convertim n format big-endian.
31 15 0

'A' (41H)

'B' (42H)

'C' (43H)

'D' (44H)

Figura 7.3 Registrul EAX n reprezentare big-endian

Opera"ia de conversie ntre little- !i big-endian presupune interschimbarea octe"ilor 1 cu 4 !i 2 cu 3. Este important de re"inut c# ordinea bi"ilor din octe"ii individuali nu se modific#. Procesoarele Pentium au introdus o instruc"iune care efectueaz# aceast# opera"ie. Formatul acesteia este: bswap registru Instruc"iunea BSWAP comut# numai octe"ii unui registru de 32 de bi"i. (gdb) i r eax eax 0x41424344 1094861636

Urm#torul program exemplific# comportamentul instruc"iunilor XCHG !i BSWAP. ; ;swapBig.asm ; section .text global _start _start: nop mov bx,'AB' xchg bl,bh mov eax,'ABCD' bswap eax mov eax,1 mov ebx,0 int 80h Alte instruc"iuni din aceast# familie sunt prezentate n Tabelul 7.7.

Tabelul 7.7 Instruc!iuni de interschimbare

Instruc!iune XCHG BSWAP XADD CMPXCHG CMPCHG8B

Descriere Comut! valori ntre dou! registre sau ntre un registru "i o loca#ie de memorie. Converte"te octe#ii unui registru de 32 de bi#i din ordine littleendian n big-endian, sau invers. Comut! dou! valori "i stocheaz! suma n operandul destina#ie. Compar! acumulatorul cu o valoare extern! "i schimb! operanzi n func#ie de rezultatul compara#iei. Compar! dou! valori de 64 de bi#i fiecare "i le schimb! n func#ie de rezultatul compara#iei.

Instruc#iunea XADD comut! valorile ntre dou! registre sau ntre un registru "i o loca#ie de memorie, apoi adun! valorile "i stocheaz! rezultatul n destina#ie. xadd destina!ie,surs" unde sursa trebuie s! fie obligatoriu un registru de 8, 16 sau 32 de bi#i, iar destina!ia registru sau loca#ie de memorie de dimensiunea corespunz!toare. Instruc#iunea XADD este disponibil! ncepnd cu procesoarele 80486. Instruc#iunea CMPXCHG compar! operandul destina#ie cu o valoare din AL, AX sau EAX. cmpxchg destina!ie,surs" Dac! valorile sunt egale, valoarea operandului surs! se ncarc! n destina#ie. Dac! valorile sunt diferite, operandul destina#ie este nc!rcat n EAX, AX sau Al. Operandul destina#ie poate fi registru sau loca#ie de memorie de 8, 16 sau 32 de bi#i. Operandul surs! trebuie s! fie un registru de dimensiune corespunz!toare. Instruc#iunea CMPXCHG este disponibil! ncepnd cu procesoarele 80486. ; ;cmpxchg.asm ; section .data val dd 5 section .text global _start _start: nop

mov eax,5 mov ebx,3 cmpxchg [val],ebx mov eax,1 mov ebx,0 int 80h Instruc!iunea CMPXCHG8B are acela"i efect cu instruc!iunea CMPXCHG, numai c# lucreaz# cu valori de 8 octe!i (de aici "i 8B de la sfr"it). Aceast# instruc!iune a ap#rut odat# cu procesorul Pentium. Formatul instruc!iunii prime"te un singur operand: cmpxchg8b destina!ie Operandul destina!ie adreseaz# o loca!ie de memorie de 8 octe!i. Ace"tia sunt compara!i cu valoarea con!inut# n perechea de registre EDX:EAX (EDX registrul superior "i EAX registrul inferior). Dac# valorile sunt egale, valoarea de 64 de bi!i aflat# n perechea de registre ECX:EBX este compiat# n loca!ia de memorie adresat# de destina!ie. Dac# nu sunt egale, valoarea din loca!ia de memorie este nc#rcat# n perechea de registre EDX:EAX. ; ;cmpxchg8b.asm ; section .data val dq 1122334455667788h section .text global _start _start: nop mov edx,11223344h mov eax,55667788h mov ecx,ffffffffh mov ebx,aaaaaaaah cmpxchg8b [val] mov eax,1 mov ebx,0 int 80h

7.7. Instruc!iuni de prelucrare la nivel de bit


Instruc!iunile de control din limbajele de nivel nalt, de selec!ie sau itera!ie, sunt implementate pe baza evalu"rii unor expresii logice sau booleene. Majoritatea acestora sunt traduse n limbaj de asamblare ca opera!ii de manipulare a operanzilor la nivel de bit. n setul de instruc!iuni exist" trei grupuri de instruc!iuni pentru manipularea bi!ilor: instruc!iuni logice; instruc!iuni de deplasare; instruc!iuni de rota!ie. Pe lng" aceastea, exist" #i cteva instruc!iuni de testare #i modificare sau scanare pe bit.

7.7.1. Instruc"iuni logice


Opera!iile logice pot avea ca rezultat o singur" valoare (numit" valoare de adev"r), din dou" posibile: adev!rat sau fals. Pentru reprezentarea acesteia este suficient un singur bit. Din acest motiv, toate instruc!iunile logice discutate n aceast" sec!iune opereaz" la nivel de bit. Prin conven!ie, valoarea logic" fals este asociat" valorii 0, orice valoare diferit" avnd semnifica!ia adev!rat. Exist" patru opera!ii logice de baz": AND (conjuc!ie), OR (disjunc!ie), XOR (disjunc!ie exclusiv") $i NOT (nega!ie). Folosim denumirile din englez" deoarece acestea reprezint" #i numele instruc!iunilor n limbaj de asamblare echivalente. Fiecare opera!ie logic" are un tabel de adev"r. Repet, opera%iile logice se realizeaz" bit cu bit, ntre bi%ii de acela$i rang.

AND 0 1 OR 0 1 XOR 0 1 NOT 0 1

0 0 0 0 0 1 0 0 1

1 0 1 1 1 1 1 1 0

Rezultatul unei opera!ii AND este 1 numai atunci cnd ambii bi!i sunt 1. Rezultatul unei opera!ii OR este 0 numai atunci cnd ambii bi!i sunt 0. Rezultatul unei opera!ii XOR este 0 atunci cnd ambii bi!i sunt egali. Func!ia NOT schimb" valoarea de adev"r. Aplicat" asupra unui operand, rezult" complementul fa!" de unu al acestuia. 1100 1001 OR 0100 1010 1100 1011 0011 0011 XOR 1111 0000 1100 0011

1 0

Exemple: 0000 1111 AND 1001 0110 0000 0110 1100 1100 NOT 0011 0011 Cu excep#ia operatorului NOT, to#i ceilal#i operatori logici necesit" doi operanzi. Ca de obicei, instruc#iunile logice primesc operanzi de 8, 16 sau 32 de bi#i. Sintaxa general" este de forma OP destina!ie,surs"

care are ca efect


destina!ie = destina!ie OP surs" unde OP este opera!ia care se dore$te a fi efectuat": AND, OR, XOR. Destina!ia poate fi un registru sau o loca!ie de memorie iar sursa un registru, o loca!ie de memorie sau o constant" de un anumit num"r de bi!i. n continuare prezent"m opera!iile tipice n care sunt utilizate instruc!iunile logice. !tergerea rapid" a unui registru

xor eax,eax xor al,al

;eax = 0 ;al = 0

XOR ntre operanzi identici duce la ob!inerea valorii 0. 1110 1100 XOR 1110 1100 0000 0000 For!area unor bi!i n 0, restul r"mnnd neschimba!i masca equ mov al, 0E3h and al, masca 00001111 ; al = 0000 0011

n urma opera!iei "I logic, bi!ii din registru afla!i pe pozi!ia celor cu valoarea 0 din masc#, vor deveni 0, cei afla!i pe pozi!ia cu valoarea 1 din masc# vor r#mne neschimba!i. For!area unor bi!i n 1, restul r"mnnd neschimba!i masca equ mov al,0E3h or al,masca 00001111 ; al = 1110 1111

n urma opera!iei SAU logic, bi!ii din registrul AL afla!i pe pozi!ia celor cu valoarea 0 din masc# vor r#mne neschimba!i, cei afla!i pe pozi!ie 1 din masc# vor fi seta!i. Pe lng# instruc!iunile echivalente func!iilor logice, exist# $i instruc!iunea TEST. TEST realizeaz# opera!ia logic# "I bit cu bit ntre doi operanzi, dar nu modific# nici sursa nici destina!ia. TEST nu genereaz# rezultat, dar modific# indicatorii de stare. Este echivalentul logic al instruc%iunii CMP. Instruc!iunea TEST ne permite s# test#m un singur bit dintr-un operand sau s# pozi!ion#m indicatorii de stare f#r# a modifica operandul. De exemplu, n cazul instruc%iunii test al,00000100b indicatorul de zero se pozi%ioneaz# n 1 dac# bitul din registru aflat pe pozi%ia echivalent# a celui marcat cu 1 n masc# este 0.

n urma instruc!iunii test ax,ax indicatorii de stare sunt pozi"iona"i ca #i cnd a fost efectuat$ o instruc!iune AND, dar con"inutul registrului AX nu se modific$.

7.7.2. Instruc!iuni de deplasare


Deplas$rile pot fi logice sau aritmetice. Instruc!iuni de deplasare logic" Acest grup de instruc"iuni realizeaz$ opera"ii de deplasare la nivel de bit, spre stnga sau spre dreapta. Sunt folosite la nmul"irea sau mp$r"irea ntregilor f!r! semn cu puteri ale lui doi. De exemplu, 4 n binar este 0100. Deplas$m un bit la stnga, 1000, ob"inem 8. Dac$ reprezent$m num$rul 4 pe un octet: 0000 0100 #i deplas$m doi bi"i la stnga, rezult$: 00010 0000, adic$ 16. ntotdeauna, deplas$rile logice cu un bit nspre stnga trec bitul cel mai semnificativ n CF #i completeaz$ bitul !! cu 0. CF 0 CF 0 CF 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0

Instruc"iunea care efectueaz$ opera"ii de deplasare logic$ spre stnga este SHL (Shift logic Left). Are trei formate diferite: shl destina!ie shl destina!ie,CL shl destina!ie,imm8 unde destina!ia poate fi registru sau loca"ie de memorie de 8, 16 sau 32 de bi"i. Varianta cu un singur operand presupune c$ deplasarea se face cu un singur bit (nmul"im destina"ia cu 2). Celelalte dou$ variante permit declararea num$rului de bi"i cu care va fi deplasat$ destina"ia. Num$rul poate fi specificat direct, ca imediat de 8 bi!i (imm8), sau prin intermediul registrului CL.

Deplasarea logic! spre dreapta mparte destina"ia (ntreg f!r! semn) cu puteri ale lui doi. Instruc"iunea este SHR (Shift Logic Right); cel mai pu"in semnificativ bit va trece n CF, iar bi"ii vacan"i se vor completa cu zero. shr destina!ie shr destina!ie,CL shr destina!ie,imm8 Opera!iile de deplasare logic" la stnga sau la dreapta sunt folosite la nmul!irea/mp"r!irea ntregilor f"r" semn. n cazul unor operanzi cu semn nu dau rezultatul scontat. Unele limbaje de nivel nalt pun la dispozi#ia programatorului operatori logici pe bi#i. De exemplu, limbajul C include urm!torii operatori logici: ~ (NOT), & (AND), | (OR), ^ (XOR). Ace$tia sunt implementa#i cu instruc#iunile logice din limbajul de asamblare. De asemenea, limbajul C dispune de operatori de deplasare la stnga (<<), respectiv la dreapta (>>), echivalentul instruc#iunilor n limbaj de asamblare SHL $i SHR. Instruc!iuni de deplasare aritmetic" Aceste instruc"iuni permit nmul"irea sau mp!r"irea rapid! cu puteri ale lui doi a ntregilor cu semn. Ele conserv! bitul cel mai semnificativ (care, a%a cum am precizat la reprezentarea n complement fa"! de doi, poate fi gndit ca fiind bit de semn). sal destina!ie,1 sar destina!ie,1 sal destina!ie,CL sar destina!ie,CL sal destina!ie,imm8 sar destina!ie,imm8 Deoarece ad!ugarea unor valori de zero n partea dreapt! nu schimb! bitul cel mai semnificativ, SAL (Shift Arithmetic Left) este un alias pentru SHL (acela%i cod ma%in!). Toate numerele negative reprezentate n complement fa"! de doi au MSB = 1. Ct timp deplasarea nu modifica bitul cel mai semnificativ rezultatul este corect. Problema apare atunci cnd domeniul de reprezentare este dep!%it. De exemplu, pentru un octet, -128 deplasat la stnga cu 1 d! 0. Chiar dac" este vorba de acela#i cod ma#in", YASM face diferen!a ntre denumirile instruc!iunilor; n schimb, dezasamblorul NDISASM ntotdeauna dezasambleaz" acel cod ca fiind SHL. ; ;deplAritm.asm

; section .text global _start _start: nop mov al,-64 shl al,1 movsx ebx,al shl al,1 movsx ecx,al mov al,-64 sal al,1 movsx ebx,al sal al,1 movsx ecx,al mov eax,1 mov ebx,0 int 080h Instruc!iunea SAR (Shift Arithmetic Right) este diferit" de instruc!iunea SHR, deoarece completarea bi!ilor vacan!i cu zero ar duce la suprascrierea celui mai semnificativ bit (bitul de semn). Astfel, instruc!iunea SAR introduce bitul cel mai pu!in semnificativ n CF #i deplaseaz" cu o pozi!ie spre dreapta ceilal!i bi!i, dar conserv" bitul cel mai semnificativ. CF S 1 0 0 0 0 0 1 Astfel, dac" deplas"m un octet spre dreapta cu instruc!iunea SAR, numai cei 7 bi!i mai pu!in semnificativi sunt deplasa!i. Cel mai semnificativ bit se p"streaz". ; ;deplAritm2.asm ; section .text global _start _start: nop mov al,-4 sar al,1

movsx ebx,al mov al,-4 shr al,1 movsx ecx,al mov eax,1 mov ebx,0 int 080h Instruc!iuni de deplasare dubl" Setul de instruc!iuni cuprinde "i dou# instruc!iuni pentru deplas#ri de 32 "i 64 de bi!i. Aceste dou# instruc!iuni primesc ca operanzi de intrare cuvinte sau dublu cuvinte "i genereaz# un rezultat de aceea"i lungime (cuvnt sau dublu cuvnt). Instruc!iunile de deplasare dubl# au trei operanzi: shld destina!ie,surs",contor shrd destina!ie,surs",contor unde destina!ia "i sursa pot fi cuvinte sau dublu cuvinte. Operandul destina!ie poate fi registru sau loca$ie de memorie, iar operandul surs# obligatoriu registru. Contorul num#rului de bi!i deplasa!i poate fi specificat direct, ca valoarea imediat#, sau de registrul CL. O diferen!# semnificativ# fa!# de instruc!iunile de deplasare este c# bi!ii introdu"i n destina!ie prin deplasament provin de la operandul surs#. shld
15/31 0 15/31 0

CF

destina!ie(reg/mem)

surs"(reg)

shrd

15/31

15/31

surs"(reg)

destina!ie(reg/mem)

CF

Observa!i c# bi!ii deplasa!i n exteriorul operandului surs# sunt introdu"i n operandul destina!ie. Totu"i, operandul surs# nu se modific#, el r#mne la valoarea avut# anterior deplas#rii. Numai operandul destina!ie este actualizat. La fel ca n cazul celorlalte instruc!iuni de deplasare, ultimul bit care p#r#se"te destina!ia este memorat n indicatorul de transport.

7.7.3. Instruc!iuni de rota"ie


n cazul instruc!iunilor de deplasare, bi!ii deplasa!i n afara operandului destina!ie sunt pierdu!i. Exist" situa!ii n care este dezirabil s" p"str"m ace#ti bi!i. Instruc$iunile de rota!ie deplaseaz" operandul spre stnga sau spre dreapta, exact ca instruc$iunile de deplasare, numai c" bi$ii care dep"%esc octetul, cuvntul sau dublu cuvntul sunt reintrodu%i n octet, cuvnt sau dublu cuvnt prin cel"lalt cap"t al valorii. De exemplu, rota$ia unui octet la stnga cu un bit ia valoarea bitului 7 %i o plaseaz" pe pozi$ia bitului 0, iar ceilal$i bi$i sunt deplasa$i la stnga cu o pozi$ie. Instruc$iunile care realizeaz" rota$ii sunt: ROL (Rotate Left), ROR (Rotate Right), RCL (Rotate Left and include CF), RCR (Rotate Right and include CF). Ultimele dou" instruc$iuni folosesc indicatorul CF ca bit adi$ional, lucru care permite deplasarea a 9, 17 sau 33 de bi$i. Formatul instruc$iunilor de rota$ie este acela%i cu formatul instruc$iunilor de deplasare. De exemplu: rol destina!ie,1 rol destina!ie,CL rol destina!ie,imm8

7.7.4. Instruc!iuni de testare #i modificare a unui bit


Setul de instruc!iuni con!ine patru instruc!iuni de testare #i modificare a unui bit specificat n instruc!iune prin deplasamentul s"u fa!" de bitul cel mai pu!in semnificativ al operandului. Ca de obicei, bitul cel mai pu!in semnificativ este considerat bitul de pe pozi!ia 0. Toate instruc!iunile au acela#i format. D"m ca exemplu instruc!iunea: bt operand,pozi"ie Operandul este un cuvnt sau dublu cuvnt aflat n memorie sau registru. Pozi!ia specific" indexul bitului testat. Poate fi o valoare imediat" sau un registru de 16 sau 32 de bi!i. Toate cele patru instruc!iuni copiaz" bitul respectiv n CF #i l modific" conform opera!iei descrise de numele lor: Instruc!iune BT (Bit Test) BTS (Bit Test and Set) BTR (Bit Test and Reset) BTC (Bit Test and Complement) Efect asupra bitului selectat niciun efect bitul selectat este pozi!ionat n 1 bitul selectat este pozi!ionat n 0 bitul selectat este negat

Instruc!iunile din acest grup modific" numai indicatorul de transport. Ceilal!i cinci

indicatori de stare r!mn nemodifica"i.

7.7.5. Instruc!iuni de scanare pe bit


Instruc"iunile de scanare pe bit returneaz! ntr-un registru pozi"ia primului bit de 1 ntlnit. Sunt dou! instruc"iuni una pentru scanare direct! (ncepe scanarea de la bitul mai pu"in semnificativ), cealalt! pentru scanare invers!. Formatul instruc"iunilor este: bsf destina!ie,operand bsr destina!ie,operand ;Bit Scan Forward ;Bit Scan Reverse

unde operandul este un cuvnt sau dublu cuvnt aflat n memorie sau registru. Destina"ia va re"ine indexul primului bit de 1 ntlnit n operand n timpul scan!rii directe sau inverse. Destina"ia trebuie s! fie obligatoriu un registru de 16 sau 32 de bi"i. Dac! to"i bi"ii sunt zero, indicatorul de zero se pozi"ioneaz! n 1; n caz contrar, ZF = 0 #i registrul destina"ie memoreaz! pozi"ia. Instruc"iunile de scanare pe bit afecteaz! numai indicatorul de zero. Ceilal"i cinci indicatori de stare r!mn nemodifica"i.

7.7.6. Instruc!iuni de setare condi!ionat"


Instruc"iunile din aceast! categorie permit pozi"ionarea unui octet pe zero sau unu, n func"ie de una din cele 16 condi"ii definite de indicatorii de stare. Forma general! a instruc"iunii este: set<condi"ie> operand unde operandul, de tip octet, poate fi registru sau loca"ie de memorie. Condi"iile sunt urm!toarele: Instruc!iune SETE/SETZ SETNE/SETNZ SETL/SETNGE SETLE/SETNG SETNL/SETGE SETNLE/SETG SETB/SETNAE/SETC Condi!ie ZF = 1 ZF = 0 SF < > OF, valori cu semn SF < > OF sau ZF = 1, valori cu semn SF = OF, valori cu semn SF = OF #i ZF = 0, valori cu semn CF =1, valori f!r! semn

SETBE/SETNA SETNB/SETAE/SETNC SETNBE/SETA SETO/SETNO SETP/SETPE SETNP/SETPO SETS/SETNS

CF = 1 sau ZF = 1, f!r! semn CF = 0, valori f!r! semn CF = 0 "i ZF = 0, f!r! semn OF = 1 / respectiv OF = 0 PF = 1, paritate par! PF = 0, paritate impar! SF = 1 / respectiv SF = 0

Aceste instruc#iuni sunt folosite pentru implementarea expresiilor booleene din limbajele de nivel nalt. Nu modific! nici un indicator de stare.

7.8. Instruc!iuni de transfer al controlului


Rula#i, prin intermediul depanatorului, oricare program din cele prezentate pn! acum, de exemplu deplAritm2.asm, "i monitoriza#i la fiecare pas valoarea registrului EIP. Observa#i cum execu$ia unei instruc$iuni modific! con$inutul acestuia. Ei bine, con$inutul registrului EIP reprezint! adresa instruc$iunii ce urmeaz! a fi executat!. EIP se nume%te contor de instruc$iune "i memoreaz! adresa urm!toarei instruc$iuni din program. Pentru c! instruc$iunile sunt formate de obicei din mai mul$i octe$i, valoarea indicatorului de instruc$iune cre%te n concordan$! cu num!rul acestora %i nu trebuie s! ne a%tept!m s! creasc! cu unu la fiecare instruc$iune executat!. Nici programatorul, nici programul nu poate modifica direct registrul EIP (nici nu este de dorit). Altfel spus, nu putem folosi instruc$iunea MOV ca s! nc!rc!m n EIP adresa unei anumite loca#ii de memorie (de ex., adresa unei anumite instruc#iuni). Pe de alt! parte, exist! instruc$iuni care modific! indirect valoarea EIP. Acestea sunt instruc$iunile de ramificare (salt) %i iterative (buclele). Asfel de instruc$iuni pot altera valoarea registrului EIP necondi$ionat sau condi$ionat (modificarea se face numai dac! este ndeplinit! o anumit! condi$ie bazat! pe starea indicatorilor din registrul EFLAGS). Pe baza acestui criteriu putem mp!r#i instruc#iunile de transfer al controlului programlui n dou! categorii. Instruc$iuni de ramificare necondi$ionat!: 1. instruc$iuni de salt necondi$ionat 2. instruc$iuni de apel (call) 3. instruc#iuni de ntrerupere Instruc$iuni de ramificare condi$ionat!: 4. instruc$iuni de salt condi$ionat n continuare vom studia numai instruc$iunile de salt necondi$ionat %i

condi!ionat (1 si 4), urmnd ca instruc!iunile de apel "i ntrerupere s# fac# obiectul unor capitole viitoare.

7.8.1. Instruc!iuni de salt necondi!ionat


Formatul general al instruc!iunii de salt necondi!ionat este: jmp adres!

unde adresa specific# adresa de memorie de la care se va continua rularea programului (adresa care va fi trecut# n registrul EIP). Adresa de memorie este declarat# n cadrul codului surs# ca etichet# (asamblorul sau editorul de leg#turi modific# numele etichetei cu adresa corect#). ; ;saltNcond.asm ; section .data val dd 105,106,107,100,110,103 section .text global _start _start: nop mov ebx,[val] mov edi,1 mov eax,[val+edi*4] cmova ebx,eax jmp sfarsit inc edi mov ecx,[val+edi*4] cmovnbe ebx,ecx sfarsit: mov eax,1 mov ebx,0 int 080h

Rula!i programul pas cu pas "i observa!i efectul instruc$iunii de salt necondi$ionat asupra registrului EIP. Dac# dezasambl#m programul cu comanda objdump -D saltNcond -j .text -M intel

vedem adresa n clar: 08048080 <_start>: 8048080 90 8048081: 8b 1d b0 90 04 08 8048087: bf 01 00 00 00 804808c: 8b 04 bd b0 90 04 08 8048093: 0f 47 d8 8048096: eb 0b 8048098: 47 8048099: 8b 0c bd b0 90 04 08 80480a0: 0f 47 d9 080480a3 <sfarsit>: 80480a3: b8 01 00 00 00 80480a8: bb 00 00 00 00 80480ad: cd 80 nop mov ebx,DWORD PTR ds:0x80490b0 mov edi,0x1 mov eax,DWORD [edi*4+0x80490b0] cmova ebx,eax jmp 80480a3 <sfarsit> inc edi mov ecx,DWORD [edi*4+0x80490b0] cmova ebx,ecx mov eax,0x1 mov ebx,0x0 int 0x80

JMP indic! procesorului c! urm!toarea instruc"iune care trebuie executat! se afl! la adresa specificat! sub form! de etichet!. n momentul execu#iei sale, valoarea indicatorului de instruc"iune este schimbat! cu adresa respectiv! de memorie.

7.8.2. Instruc!iuni de salt condi!ionat


Instruc"iunile de salt condi"ionat transfer! execu"ia programului la alt! adres! numai dac! este satisf!cut! o anumit! condi"ie. Formatul general este: j<condi!ie> adres"

unde <condi!ie> rezult! din starea indicatorilor de stare CF, OF, PF, SF, ZF, iar adresa este o etichet! n cadrul codului.
Tabelul 7.8 Instruc!iuni de salt condi!ionat

Instruc!iune Descriere JA Jump if Above JAE Jump if Above or Equal JB Jump if Below JBE Jump if Below or Equal JC Jump if Carry

Condi!ie CF=0 and ZF=0 CF=0 CF=1 CF=1 or ZF=1 CF=1

JCXZ JE JG JGE JL JLE JMP JNA JNAE JNB JNBE JNC JNE JNG JNGE JNL JNLE JNO JNP JNS JNZ JO JP JPE JPO JS JZ

Jump if CX Zero Jump if Equal Jump if Greater (signed) Jump if Greater or Equal (signed) Jump if Less (signed) Jump if Less or Equal (signed) Unconditional Jump Jump if Not Above Jump if Not Above or Equal Jump if Not Below Jump if Not Below or Equal Jump if Not Carry Jump if Not Equal Jump if Not Greater (signed) Jump if Not Greater or Equal (signed) Jump if Not Less (signed) Jump if Not Less or Equal (signed) Jump if Not Overflow (signed) Jump if No Parity Jump if Not Signed (signed) Jump if Not Zero Jump if Overflow (signed) Jump if Parity Jump if Parity Even Jump if Parity Odd Jump if Signed (signed) Jump if Zero

CX=0 ZF=1 ZF=0 and SF=OF SF=OF SF != OF ZF=1 or SF != OF unconditional CF=1 or ZF=1 CF=1 CF=0 CF=0 and ZF=0 CF=0 ZF=0 ZF=1 or SF != OF SF != OF SF=OF ZF=0 and SF=OF OF=0 PF=0 SF=0 ZF=0 OF=1 PF=1 PF=1 PF=0 SF=1 ZF=1

Rezultatul saltului condi!ionat depinde de starea registrului EFLAGS la momentul execu!iei instruc!iunii de salt. Fiecare instruc!iune de salt condi!ionat testeaz" condi!ia specific" prin examinarea unor anumi!i indicatori de stare. La prima vedere putem crede c" unele instruc!iuni de salt condi!ionat sunt redundante. De exemplu, JA #i JG. Diferen!a const" n faptul c" unele lucreaz" cu valori cu semn, altele cu valori f"r" semn. Instruc!iunile de salt care folosesc cuvintele cheie above #i below sunt folosite pentru evaluarea valorilor ntregilor f"r" semn, n timp ce greater #i lower se refer" la rela!ia dintre dou" valori cu semn. n func!ie de distan!a la care se poate efectua saltul, sunt trei tipuri de instruc!iuni de salt (condi!ionat sau nu): SHORT saltul se poate efectua numai ntr-o raz" de 128 de octe!i de memorie (nainte sau napoi). Avantajul principal fa!" de urm"toarele

dou! tipuri prezentate este c! instruc"iunea de salt ocup! mai pu"in! memorie. Pentru stocarea indexului de salt folose#te un singur octet cu semn. Indexul de salt este num!rul de octe"i aduna"i sau sc!zu"i din adresa aflat! n registrul EIP la momentul respectiv. Un astfel de salt este specificat prin cuvntul cheie SHORT introdus imediat dup! instruc"iunea de salt, nainte de etichet!: jmp SHORT adres!. NEAR este tipul standard, att pentru salturile condi"ionate ct #i pentru cele necondi"ionate. Poate fi folosit la selectarea oric!rei loca"ii din segment. Arhitecturile de 32 de bi"i suport! dou! tipuri de salturi NEAR. Unul memoreaz! indexul de salt pe doi octe"i (permite saltul, nainte sau napoi, ntr-o raz! de aproximativ 32 000 de octe"i), cel!lalt pe patru octe"i (lucru care permite adresarea oric!rei loca"ii din segmentul de cod, n"eles ca segment de 4 GB). n modul protejat, tipul de salt implicit este NEAR cu patru octe"i de adres!. Tipul NEAR cu doi octe"i poate fi specificat prin cuvntul cheie WORD, astfel: jmp WORD adres!. FAR este folosit n cazul modelului de memorie segmentat (Modul REAL sau Virtual). Permite adresarea unei loca"ii aflate n alt segment de cod. Instruc"iunile de salt condi"ionat nu suport! acest tip de salt.

7.8.3. Instruc!iuni de ciclare


Scriem #i rul!m pas cu pas programul de mai jos. ; ;bucla.asm ; section .text global _start _start: nop mov eax,5 mov ebx,2 mov edx,0 bucla: inc edx dec eax cmp eax,ebx jnz bucla mov eax,1

mov ebx,0 int 080h Atunci cnd valoarea din EAX devine 2, compara!ia va seta indicatorul de stare ZF "i instruc!iunea de salt condi!ionat nu se va efectua. Astfel, ceea ce este cuprins ntre eticheta bucla "i instruc!iunea JNZ bucla este o secven!# de program care se repet# de un anumit num#r de ori. Putem presupune c# scopul este s# increment#m registrul EDX cu 3. De"i putem folosi acest cod, Intel a pus la dispozi!ie un set de instruc!iuni dedicate realiz#rii de bucle repetitive.
Tabelul 7.9 Instruc!iuni iterative

Instruc!iune LOOP LOOPE/LOOPZ LOOPNE/LOOPNZ

Descriere Repet# bucla pn# cnd registrul ECX devine 0 Repet# bucla pn# cnd registrul ECX devine 0 sau ZF = 0 Repet# bucla pn# cnd registrul ECX devine 0 sau ZF = 1

Sintaxa acestora este: loop adres! unde adresa este o etichet# din segmentul de cod la care se va efectua saltul. Din p#cate, instruc!iunile LOOP suport# numai un deplasament de 8 bi!i, n consecin!# pot fi realizate numai salturi de tip SHORT. Instruc!iunea LOOP folose"te n calitate de contor registrul ECX, c#ruia i decrementeaz# automat valoarea. Cnd acesta devine 0, LOOP nu se mai execut#. nainte de nceputul instruc!iunii LOOP trebuie s# set#m n ECX num#rul de itera!ii dorite. <instruc!iuni nainte de bucl#> mov ecx,100 etichet#: <instruc!iuni n bucl#> loop etichet! <instruc!iuni dup# bucl#> Observa!ii: Dac# codul din interiorul buclei altereaz# valoarea registrului ECX, aceast# modificare este luat# n considera!ie. Instruc!iunile LOOP nu schimb# valoarea indicatorilor de stare. Cnd ECX ajunge la zero, ZF nu este setat. nainte s# execute o instruc!iune LOOP, procesorul decrementeaz#

valoarea din ECX cu 1, apoi verific! daca aceasta este zero. Programul poate fi rescris astfel: ; ;bucla.asm ; section .text global _start _start: nop mov edx,0 mov ecx,3 bucla: inc edx loop bucla mov eax,1 mov ebx,0 int 080h Modifica"i valoarea de ini"ializare a registrului ECX cu 0. Explica"i ce s-a ntmplat. De cte ori s-a repetat bucla?

7.9. Procesarea !irurilor


#irul reprezint! o secven"! de caractere. Exist! cinci opera"ii de baz! care opereaz! pe $iruri, numite $i primitive: mutare, comparare de $iruri, scanarea unui $ir pentru o valoare, transfer la/de la acumulator. Pentru fiecare opera"ie exist! o instruc"iune dedicat!.

7.9.1. Instruc"iuni de transfer


Presupunem c! avem un $ir n memorie $i trebuie s! copiem unul sau mai multe elemente, poate chiar tot $irul, n alt! zon! de memorie. Ne amintim c! instruc"iunea clasic! de copiere, MOV, nu poate primi n acela$i timp ca argumente dou! loca"ii de memorie, a$adar nu poate copia date din memorie n memorie. Pentru acest lucru, Intel a pus la dispozi"ie instruc"iunea MOVS. MOVS permite programatorului s! transfere p!r"i sau $iruri ntregi dintr-o loca"ie de memorie n alta. Sintaxa general! a instruc"iunii este:

MOVS<x> unde x reprezint! dimensiunea loca"iei de memorie ce va fi tranferat! la execu"ia instruc"iunii: B, W sau D. Astfel, instruc"iunea mbrac! trei forme: MOVSB (MOVe String Byte) copiaz! un singur octet. MOVSW (MOVe String Word) copiaz! un singur cuvnt. MOVSD (MOVe String Double) copiaz! un dublu cuvnt.

Chiar dac! este considerat! intruc"iune dedicat! prelucr!rilor pe #iruri, instruc"iunea MOVS, prin cele trei variante ale sale, copiaz! unul, doi sau patru octe"i o dat!. Fiecare din acestea are la rndul s!u dou! variante, n func"ie de num!rul de bi"i ai procesorului. Pentru procesoarele de 16 bi"i, MOVSB copiaz! un singur octet de la loca"ia de memorie adresat! de registrele DS:SI n loca"ia de memorie adresat! de registrele ES:DI (modul real de adresare a memoriei) #i incrementeaz! automat SI #i DI. Pentru procesoarele de 32 de bi"i, MOVSB copiaz! un singur octet de la loca"ia de memorie adresat! de registrele DS:ESI n loca"ia de memorie adresat! de registrele ES:EDI (modul protejat de adresare a memoriei) #i incrementeaz! automat ESI (adresa operandului surs!) #i EDI (adresa operandului destina"ie). Instruc"iunile MOVSW #i MOVSD au aceea#i sintax!, numai c! vor copia cte 2, respectiv 4 octe"i.
IA-32 Surs! ES:EDI

Destina"ie DS:ESI 7 0 7 0

Figura 7.4 Comportamentul instruc"iunii MOVSB

;sir.asm ; section .data sir1 db 10,20,30,40,50,60,70,80 section .bss sir2 resb 8 section .text global _start _start: nop mov esi, sir1 ;sau lea esi,[sir1] mov edi, sir2 ;sau lea edi,[sir2] movsb movsb movsb movsb movsb movsb movsb movsb mov eax,1 mov ebx,0 int 080h Instruc!iunea LEA (Load Effective Address) calculeaz" adresa efectiv" al celui de al doilea operand #i o stocheaz" n registrul specificat ca prim operand. n cazul de mai sus, rezultatul este identic cu cel al instruc!iunii MOV ESI,sir1 (n acest caz sir1 nu este inclus n paranteze p"trate deoarece ne intereseaz" tocmai adresa). Spre deosebire de instruc!iunea MOV, LEA necesit" paranteze p"trate pentru cel de al doilea operand al s"u: lea edi,[sir1] ;EDI va con!ine adresa de nceput a sir1.

;sau putem folosi 4 instr. movsw sau 2 instr. movsd

Instruc!iunea calculeaz" adresa unui operand. n cazul exemplului precedent, adresele #irurilor s-au aflat u#or prin instruc!iunea MOV, dar, a#a cum am specificat ntr-un capitol anterior, instruc!iunrea LEA este mai flexibil". LEA poate determina adresa unui operand prin metode mai sofisticate: lea eax,[ebx+ecx*4+100]

Observa!ii: Pentru a copia un "ir de 8 octe!i, avem nevoie de 8 instruc!iuni MOVSB. MOVSB nu face dect s# copieze un singur octet de la adresa dat# de ESI la adresa dat# de EDI "i apoi s# incrementeze automat ESI "i EDI. Putem mic"ora num#rul de linii ale programului nlocuind cele 8 instruc!iuni MOVSB cu 4 instruc!iuni MOVSW sau cu 2 instruc!iuni MOVSD. De asemenea, putem copia "irul ncepnd cu primul c#tre ultimul element al "irului (de la adres# mai mic# c#tre adres# mai mare) sau ncepnd de la ultimul c#tre primul element (de la adres# mai mare c#tre adres# mai mic#). Direc!ia de execu!ie a instruc!iunii MOVS poate fi setat# prin intermediul indicatorul de direc!ie (DF - Direction Flag) din registrul EFLAGS. dac# DF = 0 (ini!ial), instruc!iunile MOVS incrementeaz# ESI "i EDI cu 1, 2 respectiv 4. daca DF = 1, instruc!iunile MOVS decrementeaz# ESI "i EDI cu 1, 2, respectiv 4. Pozi!ionarea indicatorului de direc!ie se face cu ajutorul instruc!iunilor CLD (CLear Direction) "i STD (SeT Direction). Cnd copiem "irul de la sfr"it la nceput trebuie s# fim aten!i ca n ESI "i EDI s# avem adresele de sf#r"it. n acest caz, exemplul trebuie modificat astfel: lea lea std esi, [sir1+7] edi, [sir2+7]

Dac# copiem un "ir foarte mare, de exemplu un "ir cu 1578 de octe!i, trebuie s# folosim foarte multe instruc!iuni MOVS. n acest caz este indicat s# g#sim un mecanism de repetare automat# a instruc!iunii MOVS. De exemplu, putem folosi o bucl# realizat# cu ajutorul instruc!iunii LOOP: mov ecx,8 bucla: movsb loop bucla Codul rezultat func!ioneaz#. Prin folosirea instruc!iunii de buclare, MOVSB se execut# de opt ori "i "irul este copiat n ntregime. Totu"i, instruc!iunea LOOP nu este foarte rapid# (de fapt, se mai folose"te din motive de compatibilitate, codul DEC reg; JNZ este mai rapid), n plus, pentru astfel de cazuri, Intel a pus la

dispozi!ie o instruc!iune repetitiv" dedicat", numit" REP. rep instruc!iune Aten!ie, dup" REP urmeaz" ntotdeauna o instruc!iune. Aceasta repet" o instruc!iune de un num"r de ori specificat n registrul ECX. REP repet" instruc!iunea care i urmeaz" pn" cnd ECX = 0. Schimb"m n program #i rul"m: rep movsb La rulare observ"m c" instruc!iunea REP MOVSB a fost executat" o singur" dat", nu de 8 ori precum LOOP. Un singur pas, dar dup" acel pas, to!i cei 8 octe!i ai #irului surs" sunt copia!i la destina!ie. n fapt, REP nu este att o instruc!iune, ct un prefix al lui MOVSB. Pe lng" instruc!iunea REP, care monitorizeaz" numai valoarea din registrul ECX, mai sunt #i alte variante care, pe lng" ECX, dau aten!ie #i la indicatorul de stare ZF.
Tabelul 7.10 Variantele instruc!iunii REP

Instruc!iune REPE REPNE REPZ REPNZ

Descriere Repeat while equal Repeat while not equal Repeat while zero Repeat while not zero

Instruc!iunile REPE #i REPZ denot" aceea#i instruc!iune (aliasuri). La fel #i REPNE cu REPNZ. Pe lng" faptul c" putem copia #iruri dintr-o loca!ie de memorie n alta, avem la dispozi!ie #i instruc!iuni capabile s" transfere elementele #irului ntre memorie #i acumulator.

7.9.2. Instruc!iuni de transfer la/de la acumulator


Instruc!iunea LODS (LOaD String) ncarc" con!inutul unei loca!ii de memorie n acumulator. La fel ca instruc!iunea MOVS, are trei variante: LODSB (Load String Byte) ncarc" un octet din memorie n registrul AL;

LODSW (Load String Word) ncarc! un cuvnt din memorie n registrul AX; LODSD (Load String Double) ncarc! un dublu cuvnt din memorie n registrul EAX.

Fiecare din aceste forme are dou! variante, n func"ie de num!rul de bi"i ai procesorului. Pentru procesoarele de 16 bi"i, LODSB copiaz! un singur octet de la loca"ia de memorie adresat! de registrele DS:SI n registrul AL (modul real de adresare a memoriei) #i automat, n func"ie de starea indicatorului DF, incrementeaz! sau decrementeaz! SI. Pentru procesoarele de 32 de bi"i, LODSB copiaz! un singur octet de la loca"ia de memorie adresat! de registrele DS:ESI n registrul AL (modul protejat de adresare a memoriei) #i automat, n func"ie de starea indicatorului DF, incrementeaz! sau decrementeaz! ESI. Instruc!iunile LODSW "i LODSD au aceea"i sintax#, numai c# vor copia cte 2, respectiv 4 octe!i, n registrul AX, respectiv EAX, "i vor incrementa sau decrementa corespunz#tor ESI.

IA-32 AL 7 0

DS:ESI 7 0

Figura 7.5 Comportamentul instruc!iunii LODSB

Instruc"iunea STOS (STOre String) stocheaz! ntr-o loca"ie de memorie con"inutul registrului acumulator. Are trei forme: STOSB (Store String Byte) stocheaz! n memorie octetul din registrul AL. STOSW (Store String Word) stocheaz! n memorie cuvntul din registrul AX. STOSD (Store String Double) stocheaz! n memorie dublu cuvntul din registrul EAX.

ES:EDI IA-32

AL 7 0 IA-32

Figura 7.6 Comportamentul instruc!iunii STOSB

Fiecare din aceste trei forme are dou! variante, n func"ie de num!rul de bi"i ai procesorului, similar instruc"iunilor MOVS #i LODS. Instruc!iunile STOSW "i STOSD au aceea"i sintax#, numai c# vor copia n memorie cte 2, respectiv 4 octe!i, din registrul AX, respectiv EAX, "i vor incrementa sau decrementa EDI. Urm!torul program exemplific! comportamentul instruc"iunilor LODSD #i STOSD. ; ;addElem.asm ; section .data vector1 dd 10,20,30,40,50,60,70,80,90 section .bss vector2 resd 9 section .text global _start _start: nop lea esi,[vector1] lea edi,[vector2] mov ecx,9 L1: lodsd add eax,5 stosd

dec ecx jnz L1 mov eax,1 mov ebx,0 int 80h

7.9.3. Instruc!iuni de comparare


Instruc!iunea CMPS (CoMPare String) compar" dou" valori de tip octet, cuvnt sau dublu cuvnt, ambele aflate n memorie. Seam"n" cu instruc!iunea clasic" de comparare a dou" valori (CMP) o sc"dere f"r" rezultat, dar cu setarea indicatorilor de stare. A#a cum ne-am obi#nuit, prezint" trei forme: CMPSB (Compare String Byte) CMPSW (Compare String Word) CMPSD (Compare String Double)
IA-32 Surs! ES:EDI

Destina"ie DS:ESI 7 0 7 0

Figura 7.7 Comportamentul instruc!iunii CMPSB

La fel ca la toate celelalte instruc!iuni de operare pe #iruri, fiecare form" de COMPS are dou" variante, n func!ie de num"rul de bi!i ai procesorului. Instruc!iunile CMPSW "i CMPSD au aceea"i sintax#, numai c# vor compara 2, respectiv 4 octe!i, "i vor incrementa sau decrementa ESI "i EDI. Urm"torul program compar" dou" #iruri de caractere. n cazul n care sunt egale, valoarea din registrul EBX este 0. Dac" nu sunt egale, valoarea din registrul EBX indic" num"rul de caractere care mai erau de verificat. ;

;cmpStr.asm ; section .data sir1 db "Sir de caractere" sir2 db "Sir decaractere" section .text global _start _start: nop mov eax,1 lea esi,[sir1] lea edi,[sir2] mov ecx,16 cld repe cmpsb je egale mov ebx,ecx int 80h egale: mov ebx,0 int 80h Nu este necesar s! rula"i programul prin intermediul depanatorului. Valoarea din registrul EBX poate fi ob"inut! din linie de comand! cu: ./cmpStr echo $?

7.9.4. Instruc!iuni de parcurgere


Instruc"iunea SCAS (SCAn String) permite scanarea #irului pentru o valoare dat!. Cele trei forme sunt: SCASB (Scan String Byte) SCASW (Scan String Word) SCASD (Scan String Double) La fel ca la toate celelalte instruc"iuni de opera"ii pe #iruri, fiecare form! are dou! variante, n func"ie de num!rul de bi"i ai procesorului. Instruc!iunile SCASW "i SCASD au aceea"i sintax#, numai c# vor compara 2, respectiv 4 octe!i, cu valorile din registrele AX, respectiv EAX, "i vor incrementa

sau decrementa EDI. Urm!torul program determin! primul caracter egal cu un caracter dat (caracterul spa"iu) prin parcurgerea #irului n sens direct. ; ;scanStr.asm ; section .data sir db "abcde jklmnoprst" section .text global _start _start: nop lea edi,[sir] mov ecx,20 cld mov al,' ' repne scasb je L1 mov ebx,0 mov eax,1 int 80h L1: mov eax,1 mov ebx,ecx int 80

7.10. Opera!ii cu stiva


Stiva este o zon! special! a memoriei principale. Caracteristica stivei const! n modul n care sunt introduse #i extrase datele. n mod obi#nuit, datele sunt plasate n memoria principal! secven"ial, ncepnd cu loca"ia de la adresa mai mic! c!tre loca"ia cu adresa mai mare. Stiva se comport! exact invers. Memoria stiv! este rezervat! la sfr#itul segmentului de memorie #i, introducnd date n stiv!, vrful acesteia cre#te n jos. Adresa de nceput a stivei este memorat! de registrul indicator de stiv! ESP. ESP con"ine adresa primei loca"ii libere din stiv!. La introducerea unui element n stiv!, adresa scade, la extragerea unui element, adresa cre#te. Primul element extras din stiv! va fi ultimul intrat, ceea ce se nume#te LIFO (Last In First Out).

7.10.1.

Introducerea !i extragerea datelor

Datele sunt introduse n stiv! cu instruc"iunea PUSH. Sintaxa acesteia este: push surs! unde sursa poate fi registru de uz general sau loca"ie de memorie de 16 sau 32 de bi"i, sau imediat de 8, 16 sau 32 de bi"i. sursa poate fi #i registru de segment. Extragerea datelor din stiv! se face cu instruc"iunea POP. pop destina"ie unde destina"ia poate fi registru de uz general sau loca"ie de memorie de 16 sau 32 de bi"i. destina"ia poate fi #i registru de segment. ; ;stiva1.asm ; section .data val dd 125 section .text global _start _start: nop mov ecx,244420 mov bx,350 mov eax,100 push ecx push bx push eax ;introduce n stiv! adresa lui val push val ;introduce n stiv! valoarea lui val, valoare reprezentat! pe patru octe"i push dword [val] pop pop pop pop pop eax eax eax ax eax

mov eax,1

mov ebx,0 int 080h Asambl!m "i rul!m programul pas cu pas. Adresa de nceput a stivei se afl! n registrul ESP. La momentul acestei rul!ri adresa con#inut! de ESP este 0xbfc7b4f0. n urma introducerii registrului ECX n stiv!, adresa devine
0xbfc7b4ec,

ceea ce nseamn! o sc!dere cu 4. Putem afi"a valorile din stiv! prin comanda: (gdb) x /4bx $esp
Reprezent!m introducerea lui ECX n stiv!: 00 03 ba c4
7 0

ESP = 0xbfc7b4f0 0xbfc7b4ef 0xbfc7b4ee 0xbfc7b4ed ESP = 0xbfc7b4ec

Execut!m urm!toarele dou! instruc#iuni. Pn! aici am introdus n stiv! un num!r de 10 octe#i (doi de la BX "i cte patru EAX, ECX). Stiva arat! astfel: ESP = 0xbfc7b4f0 0xbfc7b4ef 0xbfc7b4ee 0xbfc7b4ed ESP = 0xbfc7b4ec ESP = 0xbfc7b4ea

00 03 ba c4 01 5e 00 00 00 64
7 0

ESP = 0xbfc7b4e6

Instruc#iunile PUSH VAR "i PUSH DWORD [VAR] exemplific! faptul c!

putem stoca n stiv! att o valoare ct "i adresa unei valori. Continua#i rularea "i observa#i cum se modific! adresa din registrul ESP pentru fiecare instruc#iune POP.

7.10.2.

Introducerea !i extragerea registrelor

Urm!toarele perechi de instruc#iuni salveaz! sau extrag din stiv! starea curent! a tuturor registrelor de uz general.
Tabelul 7.11 Introducerea sau extragerea registrelor n stiv!

Instruc!iuni Descriere PUSHA/POPA Introduce/extrage din stiv! to#i regi"trii de uz general de 16 bi#i PUSHAD/POPAD Introduce/extrage din stiv! to#i regi"trii de uz general de 32 de bi#i PUSHF/POPF Introduce/extrage din stiv! primii 16 bi#i mai pu#in semnificativi din reg. EFLAGS PUSHFD/POPFD Introduce/extrage din stiv! registrul EFLAGS Registrele salvate n stiv! de c!tre instruc#iunea PUSHAD sunt: EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI. Primul registru care poate fi extras este EDI. Instruc#iunea POPAD extrage din stiv! n ordinea invers! a salv!rii lor cu PUSHAD. ; ;stiva2.asm ; section .bss val resd 1 section .text global _start _start: nop mov eax,0ffffaaaah mov ebx,012345678h mov ecx,055556666h mov edx,011112222h mov ebp,0bbbbcccch mov esi,0ddddeeeeh mov edi,088889999h pusha pushf popf

popa pushad pop dword [val] pushfd popad popfd mov eax,1 mov ebx,0 int 080h

7.10.3.

Exemple de lucru cu stiva

Instruc!iunile PUSH "i POP nu sunt singurele care pot introduce sau extrage date din stiv#. Putem introduce sau extrage date din stiv# prin adresare bazat#, folosind ca adres# de baz# adresa memorat# n registrul ESP. De cele mai multe ori ns#, n locul utiliz#rii directe a lui ESP, se copiaz# adresa din ESP n EBP. Instruc!iunile care acceseaz# parametrii stoca!i n stiv# folosesc ca adres# de baz# valoarea lui EBP. Dar nu intr#m acum n detalii, acesta este subiectul unui capitol viitor. Stiva este utilizat# n trei scopuri principale: spa!iu de stocare a datelor temporare; transferul controlului n program; transmiterea parametrilor n timpul unui apel de procedur#. n paragrafele urm#toare dezbatem primul caz, cel al salv#rii temporare a datelor, celelalte dou# sunt studiate pe larg n capitolul intitulat Func!ii. De exemplu, s# presupunem c# dorim s# interschimb#m con!inutul a dou# loca!ii de memorie de 32 de bi!i. Nu putem interschimba con!inutul acestora direct, deoarece instruc!iunea XCHG nu poate primi ca operanzi dou# loca!ii de memorie. ns# putem folosi un registru intermediar. Secven!a de instruc!iuni mov eax,[val1] xchg [val2],eax mov [val1],eax ndepline"te sarcina propus#, dar are nevoie de un registru suplimentar. Din cauza num#rului limitat de registre de uz general, acesta nu este tocmai u"or de g#sit. De obicei con!ine date care trebuie salvate nainte de secven!# "i ref#cute dup#, ca n urm#torul exemplu: ;

;swap.asm ; section .data val1 dd 125 val2 dd 225 section .text global _start _start: nop mov eax,0ffffffffh push eax mov eax,[val1] xchg eax,[val2] mov [val1],eax pop eax mov eax,1 mov ebx,0 int 080h

;salv!m con"inutul registrului EAX

;aducem registrul EAX la starea ini"ial!

Codul acceseaz! memoria de cinci ori. V! aminti"i c! instruc"iunea XCHG, n cazul n care acceseaz! memoria, este mare consumatoare de timp? Din considerente de performan"!, probabil ar fi fost mai indicat s! folosim patru instruc"iuni MOV, astfel: mov mov mov mov eax,[val1] ebx,[val2] [val1],ebx [val2],eax

n acest caz, programul complet acceseaz! memoria de opt ori (4 instruc"iuni MOV plus 4 instruc"iuni necesare salv!rii #i restaur!rii registrelor intermediare). Dar stiva este o structur! de tip LIFO, secven"a de instruc"iuni POP realizeaz! procesul invers al secven"ei de instruc"iuni PUSH. O modalitate elegant! de interschimbare a unor valori este s! folosim numai stiva. ; ;swapWithStack.asm ; section .data var1 dd 125 var2 dd 225 section .text

global _start _start: nop mov eax,0ffffffffh push [var1] push [var2] pop [var1] pop [var2] mov eax,1 mov ebx,0 int 080h De aceast! dat! nu este necesar! salvarea con"inutului vreunui registru (nu mai folosim registre intermediare). Observa"i #i faptul c! instruc"iunile PUSH #i POP permit transferul datelor de la memorie la memorie. Stiva este folosit! frecvent atunci cnd trebuie eliberat un set de registre utilizat de secven"a de cod care urmeaz!.

7.11. Exerci!ii

8. OPERA!II CU NUMERE N VIRGUL" MOBIL"

n capitolele anterioare am lucrat numai cu numere ntregi. A!a cum !ti"i, unele rela"ii numerice nu pot fi definite prin intermediul numerelor ntregi !i a fost introdus conceptul de frac"ie. Astfel, ntre dou# numere ntregi putem avea un num#r infinit de valori. Pe lng# num#rul infinit de valori ntre dou# numere ntregi, n sistemul de numera"ie exist# un num#r infinit de numere ntregi. Toate aceste numere combinate formeaz# domeniul numerelor reale. Numerele reale pot con"ine orice valoare numeric# de la minus infinit la plus infinit, cu orice num#r de cifre zecimale dup# virgul#. Acest capitol descrie standardele de reprezentare a numerelor reale, arhitectura unit#$ii de calcul n virgul# mobil# pentru arhitecturile Intel de 32 de bi$i %i opera$iile principale pe care procesoarele de acest tip le pot efectua asupra numerelor reale.

8.1. Reprezentarea numerelor reale


Reprezentarea numerelor reale ntr-un sistem de calcul este o provocare, mai ales c! acestea au dimensiuni diferite (magnitudine). Primele procesoare Intel, de la 8086 pn! la 80386 inclusiv, nu puteau opera cu numere reale. Pentru reprezentarea acestora Intel punea la dispozi"ie coprocesoarele aritmetice separate (8057, 80287 #i 80387). De abia ncepnd cu 486 opera"iile n virgul! mobil! sunt realizate de o unitate integrat!, denumit! prescurtat FPU (Floating Point Unit).

8.1.1. Formatul n virgul# mobil#


Formatul n virgul! mobil! a fost dezvoltat ca metod! standard pentru reprezentarea numerelor reale n sistemele de calcul. Formatul n virgul! mobil! reprezint! numerele reale utiliznd nota"ia #tiin"ific! (exponen"ial!). n nota"ia #tiin"ific! zecimal! numerele sunt exprimate prin dou! p!r"i: o parte frac"ional! cu semn, numit! mantis!, #i o parte exponen"ial! ce indic! puterea lui 10 la care trebuie ridicat! mantisa astfel nct s! ob"inem valoarea num!rului. A#adar, pentru a exprima 0.125 n nota"ie #tiin"ific!, putem scrie !!!"!!"!! . Sistemele de calcul folosesc numere binare. Deoarece numerele sunt n

format binar, mantisa !i exponentul trebuie reprezentate ca valori binare, nu zecimale. Exemplul nostru n formatul exponen"ial binar devine !!!!!!! . Ne amintim conversia din zecimal n binar, este un proces n doi pa!i: convertim partea ntreag# n binar prin mp#r"ire succesiv# la 2; convertim partea frac"ionar# multiplicnd succesiv cu 2 pn# cnd ajungem la zero, !i re"innd partea ntreag#. Convertim 23.25 din zecimal n binar: convertim 23 23: 2 = 11 rest 11: 2 = 5 rest 5: 2 = 2 rest 2: 2 = 1 rest 1: 2 = 0 rest convertim .25 .25 ! 2 = 0.50 .50 ! 2 = 1.0 Rezultat final: 10111.01 Convertim 0.85: convertim .85 .85 .7 .4 .8 .6 .2 .4

1 1 1 0 1

! ! ! ! ! ! !

2 2 2 2 2 2 2

= = = = = = =

1.7 1.4 0.8 1.6 1.2 0.4 0.8

Nu ajungem niciodat# la zero. Acest num#r are o reprezentare finit# n zecimal, dar infinit# n binar. Echivalentul lui 1/6 n zecimal (0.1666666...). Calculatorul va putea numai s#-l aproximeze. O caracteristic# cheie a opera"iilor cu numere ntregi este c# rezultatul este ntotdeauna precis. De exemplu, dac# adun#m doi ntregi, ob"inem ntodeauna rezultatul exact. n contrast, opera"iile cu numere reale sunt ntotdeauna predispuse la aproxim#ri. Numerele reale reprezentate n nota"ie !tiin"ific# au trei componente ! ! !! !!! ! ! ! !! unde, S reprezint# bitul de semn M, mantisa

E, exponent

Sistemele digitale reprezint! aceste componente sub forma unor cmpuri de dimensiune fix!:
S E M

Cmpul S are ntotdeauna un singur bit "i reprezint! semnul mantisei. n schimb, num!rul de bi#i utiliza#i pentru exponent "i mantis! depinde de optimiz!rile dorite. M!rimea cmpului E determin! dimensiunea domeniului de reprezentare, iar m!rimea cmpului M precizia reprezent!rii. Un format oarecare n aceast! sec#iune presupunem un format de reprezentare n virgul! mobil! de 14 bi#i, cu un exponent de 5 bi#i, o mantis! de 8 bi#i "i un bit de semn.
1bit 5 bi#i Semn Exponent 8 bi#i Mantis!

Mantisa num!rului n virgul! mobil! con#ine valoarea frac#ionar! n binar "i este ntotdeauna precedat! de un punct binar implicit. Exponentul reprezint! puterea lui 2 la care este ridicat! mantisa. Reprezent!m num!rul 32. $tim c! 32 este !! , a"adar, n nota#ia "tiin#ific! binar! !" ! !!!!!! ! !!!!!! !!Folosind aceast! informa#ie, introducem 110 (= 6 n zecimal) n cmpul exponent "i 1 n mantis!, astfel:
0 0 0 1 1 0 1 0 0 0 0 0 0 0

O problem! evident! a acestui model este c! nu poate reprezenta exponen#i negativi. Nu avem nicio posibilitate s! reprezent!m 0.125 de exemplu, deoarece 0.125 este !!! "i exponentul -3 nu poate fi reprezentat. Am putea rezolva problema prin ad!ugarea unui bit de semn pentru exponent, dar s-a dovedit c! este mult mai eficient s! deplas!m (adun!m la) valoarea ini#ial! a acestuia cu o valoare predefinit! (bias). Ideea din spatele valorii predefinite este de a transforma fiecare valoare exponent ntr-un ntreg pozitiv. Valoarea predefinit! este un num!r aflat la mijlocul intervalului exponent "i reprezint! zero. n cazul nostru, valoarea predefinit! este 16 deoarece este la mijlocul intervalului 0 "i 31 (exponentul nostru are 5 bi#i, a"adar permite 32 de valori). Orice num!r mai mare ca 16 n cmpul exponent indic! o valoare pozitiv!. Numerele mai mici de 16 indic! valori negative. Acest mod de reprezentare se nume"te reprezentare n exces cu 16 (excess-16) deoarece pentru a ob#ine valoarea real! a exponentului trebuie s!

sc!dem 16. Re"ine"i c! exponen"ii care au to"i bi"ii de zero sau unu sunt rezerva"i pentru numere speciale (precum zero sau infinit). Revenind la reprezentarea num!rului 32, valoarea ini"ial! a exponentului, 6, se adun! cu valoarea predefinit!, 16, #i rezult! 22:
0 1 0 1 1 0 1 0 0 0 0 0 0 0

Dac! am dori s! reprezent!m num!rul !!!"# ! !!!!!!! ! !!!!!!! , am avea 16 + (-2) = 14.
0 0 1 1 1 0 1 0 0 0 0 0 0 0

Dar mai ntmpin!m o problem! deloc de neglijat. Numerele pot avea mai multe reprezent!ri. Altfel spus, sistemul nu garanteaz! unicitatea reprezent!rii. Toate formele urm!toare reprezint! num!rul 32 (!!!!!! , !!!"!!! , !!!!"!!! , etc.). 0 1 0 1 1 0 1 0 0 0 0 0 0 0
0 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 0 1 0 0 0 1 0 0 0 0

Nu numai c! aceste sinonime ocup! spa"iu suplimentar, dar pot provoca confuzii. n consecin"!, s-a stabilit ca virgula s! fie plasat! dup! primul digit diferit de 0. Acesta se nume#te normalizare. n acest mod, mantisa stocheaz! numai partea frac"ional! a num!rul normalizat. Astfel, dac! 32 este n binar 100000, normalizat nseamn! c! mut!m virgula n dreapta primei cifre de 1. Valoarea noastr! binar! devine !!!!!!!!!! sau !!!!!! ! n consecin"!, aceasta este valoarea care va fi reprezentat!. Bitul din stnga punctului binar nu se mai reprezint!, fiind ntotdeauna 1, #i conven"ia ofer! efectiv un bit suplimentar de precizie (cre#te precizia cu o putere a lui 2). Totu#i, reprezentarea 0.0 are nevoie de aten"ie special!. Reprezentarea lui 32 este:
0 1 0 1 0 1 0 0 0 0 0 0 0 0

Formatul acestui num!r normalizat poate fi reprezentat astfel: ! ! !!!!! !!!! !!!!!!!"#$

unde, ca s! afl!m exponentul, sc!dem valoarea prestabilit! din cmpul E. Opera!ii aritmetice cu numere n virgul" mobil" Adunarea "i sc!derea n virgul! mobil! se face n mod obi"nuit. Primul lucru de care trebuie s! #inem cont este s! exprim!m ambii operanzi n aceea"i putere exponen#ial!, apoi se adun! numerele din mantis! p!strnd exponentul. n caz c! este nevoie, exponentul se ajusteaz! la final. n urm!torul exemplu calcul!m suma numerelor 12 "i 1.25 folosind modelul de reprezentare pe 14 bi#i. !" ! !!!!!! , iar !!!" ! !!!"!!!! ! !!!!"!"!!!
0 1 0 0 1 1 1 0 0 0 0 0 0 0 + 0 1 0 0 1 1 0 0 1 0 1 0 0 0

0 1 0 0 1 1 1 0 1 0 1 0 0 0

A"adar, suma este !!!"!"!!!! ! !!"!!!" ! !"!!"! Observa#i c! pentru 12 am folosit forma normalizat!. 1.25 a trebuie adus la forma exponentului lui 12. nmul#irea este la fel de simpl!, se nmul#esc valorile din mantis! "i se adun! exponen#ii. Dac! exponentul are nevoie, se ajusteaz! la final. nmul#im 12 cu 1.25. Nu folosim formele normalizate: !!!!!!! "i !!!"!!!! . n plus, de aceast! dat! nu este nevoie s! aducem exponen#ii la aceea"i valoare.
0 1 0 1 0 0 1 1 0 0 0 0 0 0 $ 0 1 0 0 0 1 1 0 1 0 0 0 0 0

0 1 0 1 0 1 0 1 1 1 1 0 0 0

nmul#im mantisa !!!!"!!!!"! ! !!!"""""i adun!m exponen#ii !! ! !! ! !! . Ob#inem !!!""""!!! ! !!!!!! ! !". Defini!ii "i erori Cnd discut!m de numerele n virgul! mobil! este important s! n#elegem termeni ca domeniu de reprezentare, precizie, exactitate. Domeniul unui format numeric ntreg reprezint! diferen#a ntre valoarea cea mai mare "i cea mai mic! care poate fi reprezentat!. Acurate#ea se refer! la ct

de exact aproximeaz! o reprezentare numeric! valoarea real! (ct de aproape este reprezentarea de valoarea corect!). Precizia unui num!r indic! cantitatea de informa"ie de care dispunem pentru reprezentarea unei valori. Precizia se refer! la num!rul de bi"i pe care i are mantisa la dispozi"ie ca s! reprezinte un num!r. Un num!r poate fi precis, dar nu exact. De exemplu, spunem c! n!l"imea cuiva este 1.7402 m, lucru foarte precis (precizie de aproximativ 1/1000). Totu#i, poate fi inexact, deoarece n!l"imea persoanei poate fi cu totul alta. n #tiin"!, precizia este definit! de num!rul de bi"i ai mantisei. De exemplu, !!!"!!"!" are aceea#i precizie cu !!!"!!"!!" , de#i a dou! valoare este mult, mult mai mic! dect prima. Acesta este o precizie diferit! de cea cu care probabil suntem obi#nui"i. De exemplu, dac! avem un cntar cu precizie de 1kg, eroarea poate fi de +/- 1/2 kg. Majoritatea consider! precizia ca fiind valoarea minim! care poate fi m!surat!. Indiferent de c"i bi"i avem la dispozi"ie pentru a reprezenta un num!r real, modelul nostru trebuie s! fie finit. Cnd folosim sistemele de calcul pentru opera"ii n virgul! mobil!, nu facem dect s! model!m un sistem infinit de numere reale ntr-un sistem finit de numere ntregi. Ceea ce ob"inem n mod real, este o aproximare a sistemului numerelor reale. Cu ct folosim mai mul"i bi"i, cu att aproxima"ia este mai exact!. Totu#i, la un moment dat, orice model de reprezentare #i atinge limitele #i calculele sunt afectate de erori. Prin cre#terea num!rului de bi"i vom putea reduce num!rul acestora, dar nu vom putea niciodat! s! le elimin!m. Rolul nostru este s! reducem posibilit!"ile de apari"ie a erorilor sau cel pu"in s! fim con#tien"i de magnitudinea acestora n calculele noastre. Erorile pot cre#te prin opera"ii aritmetice repetitive. De exemplu, este evident c! modelul nostru de 14 bi"i nu poate reprezenta valori ce dep!#esc capacitatea de 8 bi"i a mantisei, dar mai pu"in evident este faptul c! nu poate reprezenta exact nici valori din interiorul domeniului de reprezentare. De exemplu, 128.5, convetit n binar rezult! 10000000.1, 9 bi"i. Cum mantisa poate reprezenta 8 bi"i, n mod obi#nuit, bitul cel mai mai pu"in semnificativ este eliminat #i rotunjit la urm!torul bit. Deja am introdus o eroare n sistemul nostru. Erorile pot fi evidente, subtile sau neobservate. Erorile evidente, precum dep!#irea valorii maxime sau minime a domeniului duc la ntreruperea programului. Erorile subtile pot genera rezultate eronate greu de detectat pn! nu ncep s! produc! probleme.

8.1.2. Standardul IEEE 754


Modelul de reprezentare al numerelor n virgul! mobil! din sec"iunea anterioar! are rol educativ, dar putem extinde acest model cu orice num!r dorit de bi"i. Pn! n anii '80 deciziile de acest tip erau des ntlnite, fiecare produc!tor de sisteme avea propriul format. Acestea foloseau un num!r diferit de bi"i pentru reprezentarea mantisei #i exponentului, diferite modalit!"i de tratare a erorilor

cauzate de dep!"irea domeniului de reprezentare sau a condi#iilor speciale (mp!r#irea la 0, extragerea r!d!cinii p!trate dintr-un num!r negativ, etc.). n 1985, IEEE a publicat un standard de reprezentare a numerelor n virgul! mobil! n simpl! "i dubl! precizie. Acest standard este cunoscut oficial ca IEEE-754 (1985). Reprezentarea n simpl! precizie Standardul IEEE-754 n simpl! precizie utilizeaz! un exponent de 8 bi#i "i o valoare predefinit! (bias) egal! cu 127 (excess-127). Mantisa are 23 de bi#i "i este normalizat! cu un bit ascums 1.M. mpreun! cu bitul de semn, dimensiunea total! a formatului este de 32 de bi#i. ! ! !!!!! !!!!!"# !!!! !! Re#inem c! 1 < E < 254. Valorile 0 "i 255 reprezentnd cazuri speciale. Domeniul de reprezentare valid pentru formatul n simpl! precizie poate fi definit ca fiind: !!"#$%& ! !"#$"%& ! !! ! !!!!"#"$%&'%(")"% !!!!"#$#% , pentru valori pozitive !!!"#$%& ! !"#$"%& ! !!! ! !!!!"#"$%&'%(")"% !!!!"#$#% , pentru valori negative unde, minexp este valoarea legal! minim! a exponentului pentru numere normalizate. Aceasta este egal! cu -126 care, atunci cnd se adun! valoarea predefinit! de 127, va rezulta un exponent deplasat de valoare 1 (00000001b). maxexp este valoarea legal! maxim! a exponentului pentru numere normalizate. Aceasta este 127 care, adunat! cu valoarea predefinit! 127, va rezulta un exponent deplasat de valoare 254 (11111110b). bitideprecizie este num!rul bi#ilor din mantis!. Pentru precizia simpl!, acest! valoare este 24 (23 plus bitul implicit). Introducnd valorile enumerate n expresii, rezult! urm!toarele domenii de valori: !!!"# ! !"#$"%& ! !! ! !!!" !!!!"# , pentru numere pozitive !!!!"# ! !"#$"%& ! !!! ! !!!" !!!!"# , pentru numere negative ceea ce nseamn!, cu aproxima#ie, de la !!!"!!"!!" pn! la !!!"!!"!" . Num!rul 0 este un caz special a lui E = 0 ("irul binar 00000000) "i are dou! reprezent!ri. La fel, cnd E = 255 ("irul binar 11111111), valoarea reprezentat! este !! (mantisa este egal! cu zero) sau NaN (mantisa este diferit! de zero). Valoarea NaN (Not a Number) reprezint! un num!r invalid folosit de obicei ca indicator de eroare. Valorile speciale sunt redate n tabelul urm!tor:

Tabelul 8.1 Valorile speciale ale reprezent!rii n simpl! precizie

Condi!ie E = 255 !i ! ! ! E= 255 !i M = 0 E = 0 !i ! ! ! E= 0 !i M = 0

Valoare N NaN !! !!! ! !!!!! !!!!"# !!!! !! !! !!! !

Reprezent"ri Not a Number !! Num"r denormalizat !!

Zero Zero nu poate fi reprezentat direct. Deoarece avem bit de semn, pentru 0 exist" reprezentare pozitiv" !i negativ". Infinit Avem reprezentare separat" pentru plus !i minus infinit. Un num"r diferit de zero mp"r#it la zero d" infinit. De exemplu, 1.0/0.0 produce infinit. NaN De obicei apare n cazurile unor opera#ii definite gre!it. Exemplul standard este mp"r#irea 0.0/0.0, care nu are o valoare definit". Ele sunt identificate printr-un exponent care are to#i bi#ii de 1 !i o mantis" diferit" de cea pentru configura#ia valorilor de tip infinit. Exist" dou" tipuri de astfel de configura#ii, denumite NaN de semnalizare (SNaN Signaling NaN) !i NaN t"cut (QNaN Quiet NaN). SNaN are mantisa de forma 1.0xx ... x, unde x poate avea orice valoare (dar nu pot fi to#i zero, deoarece reprezint" valoarea infinit). Cnd ntlne!te o astfel de configura#ie FPU genereaz" o excep#ie ce semnalizeaz" efectuarea unei opera#ii invalide. Programatorul o poate folosi pentru a indica unele condi#ii de eroare, cum ar fi o variabil" n virgul" mobil" neini#ializat". Cealalt" configura#ie, QNaN, are mantisa de forma 1.1xxx...x. Primul 1 este cel implicit. O astfel de configura#ie apare cnd rezultatul unei opera#ii aritmetice este nedefinit matematic. Orice instruc#iune care are un operand de unul din cele dou" tipuri de NaN va genera un rezultat de tip NaN.

Numere denormalizate Fa#" de numerele normalizate, acestea sunt numere cu mai pu#ini bi#i de precizie !i valori mai mici. S" presupunem c" permitem tuturor bi#ilor dintr-un num"r

normalizat s! fie 0 (n fapt este chiar reprezentarea valid! pentru 0). Un "ir de 32 de bi#i de zero ar fi !!!!!!!"# . O valoare mic!, dar am putea reprezenta numere mult mai mici dac! pentru un E = 0000 0000b: renun#!m la bitul de 1 ascuns "i fix!m valoarea exponentului la -126. V! aminti#i c! exponentul este scris ca valoare adunat! cu 127? n consecin#!, v-a#i a"tepta ca din moment ce bi#ii cmpului E sunt 0000000, ace"tia trebuie s! reprezinte un exponent de 127, nu -126. Totu"i, e un motiv ntemeiat pentru care este -126. Vom explica pu#in mai trziu. Deocamdat! accept!m faptul c! valoarea exponentului este -126 ori de cte ori "irul de bi#i din cmpul exponent este !! (8 bi#i de zero). A"adar, cel mai mare num!r pozitiv denormalizat este format din "irul de bi#i (semn, exponent, mantis!): 0 0000 0000 1111 1111 1111 1111 1111 111

care este mapat la num!rul !! !!!" !!!!!"# , unde !!" nseamn! un "ir de 23 de bi#i de 1. Din moment ce punctul binar este urmat de 23 de bi#i, acest num!r are precizie de 23 de bi#i. Cel mai mic num!r denormalizat este format din "irul de bi#i: 0 0000 0000 0000 0000 0000 0000 0000 001

care se traduce prin !!!!! !!!!!"# , sau !!!!!!!"# . Acest num!r are un singur bit de precizie. Cei 22 de zero nu afecteaz! precizia num!rului. Dac! nu crede#i, gndi#i-v! c! num!rul zecimal 256 are trei digi#i de precizie, iar 00256 are tot trei digi#i de precizie. Cifrele de zero nu afecteaz! num!rul digi#ilor de precizie. n mod similar, dac! avem 0.000256, cifrele de zero ne ajut! s! plas!m 256 corect, dar nu sunt digi#i care trebuie plasa#i n mantis!. 0.02560 are patru digi#i de precizie deoarece cifra 0 din dreapta se adaug! preciziei. A"adar, n urma punctului binar avem 22 de bi#i de zero urma#i de un 1, "i cei 22 de zero nu au leg!tur! cu num!rul de bi#i ai mantisei. Prin denormalizare am ob#inut !!!!!!!"# ca fiind cel mai mic num!r, spre deosebire de !!!!!!!"# , cea mai mic! valoare pe care am fi ob#inut-o dac! num!rul ar fi fost normalizat. S-au sacrificat totu"i 22 de bi#i de precizie. Un "ir de bi#i !! n cmpul exponent este mapat la un exponent -126. Totu"i, pentru numerele n virgul! mobil! reprezentate cu standardul IEEE-754, valoarea predefinit! este -127. De ce este -126 n loc de -127? Ca s! r!spundem la aceast! ntrebare trebuie s! ne uit!m la cel mai mic num!r pozitiv normalizat,

0000 0001

0000 0000 0000 0000 0000 000

adic! !!!!!!!"# . S! studiem cele dou! posibilit!"i pe care le avem pentru a reprezenta cel mai mare num!r pozitiv denormalizat. !! !!!" !!!!!"# (bias 127) !! !!!" !!!!!"# (bias 126 - acesta este folosit de IEEE 754 n simpl! precizie) Amndou! sunt mai mici dect valoarea minim! a numerelor normalizate, !!!!!!!"# . Acesta este un lucru bun, deoarece dorim s! evit!m suprapunerea numerelor normalizate #i denormalizate. De asemenea, observa"i c! num!rul cu exponent -126 este mai mare dect num!rul cu exponent -127. A#adar, prin alegerea lui -126, diferen"a dintre cel mai mic num!r normalizat #i cel mai mare num!r denormalizat este mai mic!. Aceasta este #i ra"iunea pentru care standardul n simpl! precizie IEEE-754 folose#te ca cel mai mic num!r denormalizat !! !!!" !!!!!"# . Reprezentarea n dubl! precizie Numerele n dubl! precizie folosesc un cuvnt cu semn format dintr-un exponent de 11 bi"i #i o mantis! de 52 de bi"i, pentru un total de 64 de bi"i. Valoarea predefinit! este 1023 (excess-1023). Valorile pe care le poate lua acest format sunt prezentate n Tabelul 8.2.
Tabelul 8.2 Valorile reprezent!rii n dubl! precizie

Condi!ie E = 2047 #i ! ! ! E= 2047 #i M = 0 0 < E < 2047 E = 0 #i ! ! ! E= 0 #i M = 0

Valoare N NaN !! !!! ! !!!!! !!!!!"#$ !!!! !! !!!!! !!!!"## !!!! !! !! !!! !

Reprezent"ri Not a Number !! Num!r normalizat Num!r denormalizat !!

Aceast! combina"ie produce un domeniu de valori ntre !!!"!!"!!"# #i !!!"!!"!"# .

8.1.3. Valori n virgul! mobil! specifice IA-32


Platformele IA-32 folosesc formatele standardului IEEE 754, n simpl! #i dubl! precizie, mpreun! cu propriul format de 80 de bi"i, numit formatul numerelor n precizie extins!, destinat uzului intern. n C, folosim directiva float, pentru numere n simpl! precizie #i double, pentru numere n dubl!

precizie, dar, a!a cum vom vedea n sec"iunile urm#toare, toate registrele interne ale unit#"ii de calcul n virgul# mobil# sunt de 80 de bi"i. Formatul numerelor n virgul# mobil# cu precizie extins# folose!te 64 de bi"i pentru mantis# !i 15 bi"i pentru exponent. Valoarea predefinit# este 16.383, genernd exponen"i ntre -16382 !i +16383, pentru un domeniu de valori cuprins ntre !!!"!!"!!"#$ !i !!!"!!"!"#$ .

8.2. Arhitectura unit!"ii n virgul! mobil!


Unitatea n virgul# mobil# con"ine registrele din Figura 8.1. Acestea sunt mp#r"ite n trei grupuri: registre de date, registre de control !i stare, registre indicator. Ultimul grup con"ine registrul indicator de instruc"iune !i registrul indicator de date !i ofer# informa"ii necesare n scrierea rutinelor de ntrerupere care trateaz# erorile ap#rute n timpul opera"iilor. Din moment ce acest subiect dep#!e!te obiectivele acestei c#r"i, nu intr#m n detalii.
79 0 1 2 3 4 5 6 7 S Exponent Mantis# Tag Figura 8.1 Registrele unit!"ii n virgul! mobil! 64 63 0 1 0 15 Control 15 Stare 0 0

8.2.1. Registre de date


Unitatea n virgul# mobil# dispune de 8 registre de date, de cte 80 de bi"i, organizate ca o stiv! de registre. De!i pot fi adresate individual pe baza numelui, deoarece sunt organizate ca stiv# de registre, aceste nume nu sunt atribuite static. Adresarea registrelor se face relativ la registrul din vrful stivei. ST0 nu se refer# la

un registru specific, ci la registrul aflat n acel moment n vrful stivei (TOS Top Of Stack). Registrul urm!tor este numit ST1 ".a.m.d., pn! la ultimul registru, ST7. Vrful curent al stivei este indicat de un cmp de trei bi#i aflat n registrul de stare, TOP (stack TOP). Opera#iile de nc!rcare decrementeaz! TOP "i introduc valoarea n noul vrf al stivei, opera#iile de stocare extrag valoarea din vrful curent al stivei "i incrementeaz! TOP. Fiecare registru de date reprezint! valoarea n precizie extins!. Aceste registre re#in de obicei rezultate intermediare "i utilizarea formatului extins mbun!t!#e"te acurate#ea rezultatului final. Starea "i con#inutul fiec!rui registru de date este indicat! printr-o etichet! de doi bi#i. Deoarece sunt 8 registre de date, avem nevoie de 16 bi#i. Ace"ti 16 bi#i sunt stoca#i n registrul de etichete (tag register).

8.2.2. Registre de control !i stare


Acest grup con#ine trei registre de cte 16 bi#i: registrul de control, registrul de stare registrul de etichete. Registrul de stare Acest registru de 16 bi#i p!streaz! informa#ii de stare cu privire la func#ionarea unit!#ii de calcul n virgul! mobil!.
15

0 C 3 TOP C 2 C 1 C 0 E S S F P E U E O E Z E D E I E

Figura 8.2 Structura registrului de stare FPU

Codurile de condi#ii C0 C3 indic! rezultate ale opera#iilor de compara#ie "i aritmetice n virgul! mobil!. Unii sunt similari anumitor indicatori de stare din registrul EFLAGS. Tabelul 8.3 arat! coresponden#a dintre ace"tia "i unii indicatorii de stare:
Tabelul 8.3 Coresponden!a indicatori FPU indicatori CPU

Indicator FPU C0 C2 C3

Indicator CPU CF PF ZF

Ei sunt utiliza!i pentru salturi condi!ionate, asemenea bi!ilor CPU echivalen!i. Pentru a-i putea testa trebuie mai nti copia!i n registrul EFLAGS. Copierea se face n dou" etape. Mai nt"i se ncarc" cuvntul de stare n registrul AX cu ajutorul instruc!iunii FSTSW, apoi copiem aceste valori n registrul EFLAGS cu instruc!iunea SAHF. Odat" nc"rca!i, putem folosi n mod obi#nuit instruc!iunile de salt condi!ionat. Acesta este considerat vechiul mecanism de efectuare a salturilor condi!ionate pentru valori n virgul" mobil", deoarece, ncepnd cu familia de procesoare P6, mecanismul salturilor condi!ionate pentru valori n virgul" mobil" a fost simplificat. Intel a pus la dispozi!ie o familie de instruc!iuni care compar" numerele n virgul" mobil" #i seteaz" direct indicatorii ZF, PF #i CF din EFLAGS. Astfel, o singur" instruc!iune a noului mecanism nlocuie#te trei instruc!iuni necesare vechiului mecanism. Cmpul TOP, de trei bi!i, indic" registrul din vrful stivei de registre. Valoarea 000 semnaleaz" stiva goal", valoarea 111 stiva plin". Primul element nc"rcat are indice 0. O nou" nc"rcare incrementeaz" indicii registrelor de date, o extragere decrementeaz" indicii. Pentru a permite adresarea circular" a celor 8 registre, rezultatul increment"rii/decrement"rii este trunchiat la trei bi!i (modulo 8). Excep!ii n virgul" mobil" n timpul efectu"rii unor opera!ii n virgul" mobil" pot ap"rea cteva tipuri de erori, ncepnd de la simple erori logaritmice pn" la erori provenite din limitele reprezent"rii. Erorile n virgul" mobil" se numesc excep!ii. Proiectan!ii au clasificat excep!iile n #ase clase. Bi!ii 0 5 din registrul de stare corespund acestor situa!ii deosebite. Opera!ie invalid" operandul este invalid pentru opera!ia care trebuie efectuat". De obicei sunt erori de algoritm: un rezultat nedefinit ca urmare a unei mp"r!iri zero la zero sau infinit la infinit. n acest caz, rezultatul este reprezentat printr-o secven!" QNaN. FPU seteaz" bitul IE (Invalid operation Exception). Tot din clasa excep!iilor de opera!ii invalide face parte #i dep"#irea superioar" sau inferioar" a stivei de registre. Dep"#irea superioar" nseamn" c" o instruc!iune ncearc" s" introduc" un operand din memorie ntr-un registru de date deja plin. Un registru plin este definit ca fiind registrul care con!ine o valoare de 0 (eticheta 01 din registrul de etichetare), o valoare valid" (eticheta 00) sau o valoare special" (eticheta 10). Dep"#irea inferioar" se refer" la cazul n care o instruc!iune folose#te ca operand surs" un registru de date gol (incluznd ncercarea scrierii n memorie a unui registru de date gol). Un registru gol (neutilizat) are o etichet" egal" cu 11. Atunci cnd apar condi!ii de dep"#ire, programul nu poate continua. A#adar, excep!ia de opera!ie invalid" poate ap"rea ca urmare a opera!iilor aritmetice sau a celor cu stiva. Bitul SF (Stack Fault) d" informa!ii cu privire la

cauza opera!iei invalide. Dac" acest bit este 1, opera!ia invalid" a fost rezultatul unei dep"#iri a stivei de registre; n caz contrar, o instruc!iune aritmetic" a ntlnit un operand invalid. Aten!ie, FPU seteaz" bitul SF la detec!ia unei condi!ii de dep"#ire, dar nu-l #terge cnd detecteaz" o condi!ie de operand invalid. Ca rezultat, dac" nu a fost #ters explicit de la ultima condi!ie de dep"#ire a stivei de registre, starea indicatorului SF poate fi 1 #i n cazul unei excep!ii aritmetice. n acest caz, natura erorii este indicat" de codul de condi!ie C1: dep"#ire superioar" (C1 = 1) sau dep"#ire inferioar" (C1 = 0). mp!r"ire cu zero demp"r!itul este un num"r finit nenul #i mp"r!itorul este zero; sau, mai general spus, cnd rezultatul unei opera!ii cu numere finite este infinit. Rezultatul este reprezentat corect, ca infinit cu semn. FPU seteaz" bitul ZE (Zero divide Exception). Dep!#ire superioar! rezultatul unei opera!ii este prea mare pentru a putea fi reprezentat (dep"#e#te marginea superioar" a domeniului de reprezentare). Rezultatul este reprezentat ca infinit. FPU seteaz" bitul OE (Overflow Exception). Dep!#ire inferioar! rezultatul unei opera!ii este prea mic pentru a putea fi reprezentat (dep"#e#te marginea inferioar" a domeniului de reprezentare). Rezultatul este reprezentat ca zero. FPU seteaz" bitul UE (Underflow Exception). Operand denormalizat unul din operanzi nu este normalizat sau rezultatul nu se poate reprezenta normalizat (de exemplu, rezultatul este att de mic nct este imposibil" normalizarea lui). FPU seteaz" bitul DE (Denormal Exception). Rezultat inexact rezultatul opera!iei este inexact din cauza unei rotunjiri. Aceast" excep!ie de precizie apare cnd FPU nu poate reprezenta exact rezultatul unei instruc!iuni n virgul" mobil". Cazuri de genul mp"r!irii 1/3, ce furnizeaz" un rezultat care se repet" la infinit (0.33..3), sau cnd un num"r real este convertit la un format cu o precizie mai mic" #i se pierd bi!i prin aceast" conversie. FPU seteaz" bitul PE (Precision Exception). De obicei, aceast" excep!ie este mascat" (n registrul de control) deoarece rotunjirea sau trunchierea rezultatului este satisf"c"toare. Bi!ii de excep!ie se p"streaz" pn" cnd programatorul ncarc" registrul de stare cu o valoare nou". Acest lucru permite programatorului s" scrie o secven!" de instruc!iuni #i s" plaseze un singur test de detec!ie al erorilor la sfr#itul acesteia, n loc s" scrie un test dup" fiecare instruc!iune.

Registrul de control Registrul de control permite programatorului s! controleze cteva op"iuni de prelucrare.
15 0

RC

PC

P U O Z D I M M M M M M

Figura 8.3 Structura registrului de control

Atunci cnd apare o excep"ie unitatea n virgul! mobil! are dou! posibilit!"i: s! genereze o ntrerupere sau s! o trateze intern. Modul intern de tratare a excep"iilor a fost deja specificat n sec"iunea anterioar!. ntreruperea este generat! ca urmare a unei op"iuni specificate de programator prin intermediul primilor #ase bi"i mai pu"in semnificativi din acest registru: PM (Precision Mask) ntrerupere pentru semnalarea rotunjirii. UM (Underflow Mask) ntrerupere pentru semnalarea dep!#irii inferioare. OM (Overflow Mask) ntrerupere pentru semnalarea dep!#irii superioare. ZM (Zero divide Mask) ntrerupere pentru semnalarea mp!r"irii cu zero. DM (Denormalized operand Mask) ntrerupere pentru semnalarea unui operand denormalizat. IM (Invalid operation Mask) ntrerupere pentru semnalarea opera"iei invalide. Dac! ace#ti bi"i nu sunt masca"i (valoare 1), se genereaz! ntreruperea corespunz!toare; altfel, nu se genereaz! excep"ia #i programul continu! cu execu"ia urm!toarei instruc"iuni. Metoda de rotunjire RC (Rounding Control) controleaz! modul de rotunjire a valorilor ce nu pot fi reprezentate exact: 00 rotunjire la cel mai apropiat num!r reprezentabil; 01 rotunjire inferioar! (c!tre -); 10 rotunjire superioar! (c!tre +); 11 trunchiere. Valoarea implicit! pentru acest cmp este 00.

Precizia de calcul PC (Precision Control) specific! formatul utilizat pentru reprezentarea rezultatului opera"iilor de +, -, #, / $i extragerea r!d!cinii p!trate: 00 simpl! precizie; 01 neutilizat; 10 dubl! precizie; 11 precizie extins!, utilizat! implicit. Registrul de etichete Acest registru con"ine 8 cmpuri de cte doi bi"i, fiecare cmp corespunznd unui registru de date. T0 este cmpul pentru registrul 0, nu pentru ST0, care, la un moment dat, poate fi oricare dintre cele 8 registre. Fiecare cmp ofer! informa"ii despre con"inutul registrelor respective: 00 registrul con"ine un num!r corect n virgul! mobil!; 01 registrul con"ine valoarea 0.0; 10 registrul con"ine valoarea infinit, un num!r denormalizat sau incorect; 11 registrul este gol (neutilizat). Registrul de etichete nu poate fi utilizat direct de c!tre programator, dar poate fi folosit depanatoare de exemplu, ca s! examineze $i s! interpreteze adecvat con"inutul registrelor de date.

8.3. Instruc!iuni n virgul" mobil"


FPU con"ine un set de instruc"iuni n virgul! mobil! pentru transferul de date, opera"ii aritmetice, opera"ii de comparare $i transcedentale. Pe lng! acestea sunt prezente instruc"iuni care ncarc! n stiv! constante uzuale precum % sau cuvinte de control.

8.3.1. Transferul datelor n virgul" mobil"


Setul instruc"iunilor de transfer con"ine instruc"iuni capabile s! transfere operanzi ntre registrele stivei $i ntre vrful curent al stivei $i memorie. Putem mp!r"i aceste instruc"iuni n dou! categori: de nc!rcare $i de memorare. Formatul general al instruc"iunilor de nc!rcare este:

fld surs! Aceast! instruc"iune ncarc! (depune) operandul surs! n registrul din vrful stivei. Acest lucru are loc prin decrementarea indicatorului stivei #i copierea con"inutului sursei n noul vrf al stivei. Operandul surs! poate fi un registru al stivei sau orice tip de num!r real din memorie. nainte de nc!rcarea n ST0, operanzii din memorie n simpl! sau dubl! precizie sunt converti"i automat la formatul temporar de 80 de bi"i. Instruc"iunea FLD ST0 va copia valoarea din vrful curent al stivei n noul vrf al stivei. Unele instruc"iuni de acest tip nu primesc niciun operand. Ele introduc n stiv! anumite constante uzuale. Instruc!iune FLDZ FLD1 FLDPI FLDL2T FLDL2E FLDLG2 FLDLN2 Descriere Introduce valoarea +0.0 n ST0 Introduce valoarea +1.0 n ST0 Introduce valoarea $ n ST0 Introduce valoarea !"#!"# n ST0 Introduce valoarea !"#!! n ST0 Introduce valoarea !"#!"# n ST0 Introduce valoarea ln 2 n ST0

Datorit! faptului c! reprezentarea acestora se face pe 10 octe"i, iar instruc"iunile se reprezint! numai pe doi octe"i, rezult! c!, pe lng! faptul c! simplific! programarea, acestea economisesc spa"iu de memorie #i mbun!t!"esc viteza de execu"ie. Programul floatDec.asm arat! cum putem definit n limbajul de asamblare valori n virgul! mobil!. ; ;floatDef.asm ; section .data fs1 dd 0.0 fs2 dd 1.0 fs3 dd 12.34 fd1 dq 3.333333333 fd2 dq 4.444444444 fd3 dq 5.0 fd4 dq 1.234567e20 ;dubl! precizie fd5 dq 1.e10 ;10.000.000.000 fd6 dq 1.e+10 ;sinonim cu 1.e10 fd7 dq 1.e-10 ;0.000 000 000 1

fd8 dq fd9 dq fd10 dq fe1 dt fe2 dt section .bss m32 resd m64 resq section .text global _start _start: nop finit fld dword fld dword fld qword fld qword fld qword fld qword fld tword fld tword fst dword fst qword mov eax,1 mov ebx,0 int 80h

12.34 3.14 3.141592653589793238462 3.141592653589793238462 ;pi 12.34 1 1

[fs3] [fs2] [fd1] [fd2] [fd3] [fd5] [fe1] [fe2] [m32] [m64]

YASM accept! constante n virgul! mobil! numai ca argumente pentru directivele DD, DQ "i DT. Ele sunt exprimate n forma tradi#ional!: digi#i, urma#i de punct, al#i digi#i op#ionali, apoi un E op#ional urmat de exponent. Punctul este obligatoriu, astfel nct asamblorul s! poat! diferen#ia ntre DD 1, care declar! un ntreg, de DD 1.0 care declar! un num!r n virgul! mobil!. n YASM, aproape orice instruc#iune care adreseaz! operanzi din memorie trebuie s! indice m!rimea corespunz!toare cu unul din prefixele DWORD, QWORD sau TWORD. n GDB, valorile zecimale pot fi afi"ate cu op#iunea f a comenzii x: (gdb) x /1wf &fs1 0x80490cc <fs1>: 0 (gdb) x /1wf &fs2 0x80490d0 <fs2>: 1

(gdb) x /1wf &fs3 0x80490d4 <fs3>: 12.3400002 Valorile fs1, fs2, fs3 sunt valori n simpl! precizie. Din ultima comand! se observ! c! erorile de rotunjire "i fac apari#ia chiar "i atunci cnd depanatorul ncearc! s! calculeze valorile. Ca s! afi"!m valori n dubl! precizie trebuie s! utiliz!m op#iunea g, destinat! valorilor de 8 octe#i. (gdb) x /1gf &fd1 0x80490d8 <fd1>: 3.3333333330000001 (gdb) x /1gf &fd2 0x80490e0 <fd2>: 4.4444444440000002 (gdb) x /1gf &fd3 0x80490e8 <fd3>: 5 (gdb) x /1gf &fd4 0x80490f0 <fd4>: 1.234567e+20 (gdb) x /1gf &fd5 0x80490f8 <fd5>: 10000000000 (gdb) x /1gf &fd6 0x8049100 <fd6>: 10000000000 (gdb) x /1gf &fd7 0x8049108 <fd7>: 1e-10 (gdb) x /1gf &fd8 0x8049110 <fd8>: 12.34 (gdb) x /1gf &fd9 0x8049118 <fd9>: 3.1400000000000001 (gdb) x /1gf &fd10 0x8049120 <fd10>: 3.1415926535897931 Obseva#i modul n care au fost rotunjite ultimele dou! valori ale lui $. Valorile n precizie extins! nu pot fi afi"ate direct. Instruc#iunea FINIT ini#ializeaz! unitatea n virgul! mobil!. FINIT seteaz! registrele de stare "i control la valorile implicite "i modific! cmpurile de etichete astfel nct s! indice faptul c! registrele de date FPU sunt goale. Dar, ntotdeauna este un dar, de"i modific! etichetele, instruc#iunea FINIT nu altereaz! datele deja existente n aceste registre. Este obliga#ia programatorului s! #in! eviden#a registrelor de date folosite de program "i dac! con#in date valide sau nu. Dup! execu#ia primei instruc#iuni, valoarea din registrul ST0 poate fi afi"at! cu comanda print $st0 sau info reg $st0.

(gdb) print $st0 $5 = 12.340000152587890625 (gdb) info reg $st0 st0 12.340000152587890625

(raw 0x4002c570a40000000000)

Valoarea loca!iei de memorie fs1 a fost plasat" n registrul ST0. A doua instruc!iune nlocuie#te con!inutul lui ST0 cu valoarea fs2 #i coboar" fs1 n registrul ST1. (gdb) p $st0 $6 = 1 (gdb) p $st1 $7 = 12.340000152587890625 Instruc!iunea fst dword [m32]stocheaz" n loca!ia de memorie de 32 de bi!i m32 valoarea aflat" n prezent n vrful stivei ST0. Acesta este #i formatul general al instruc!iunilor de memorare: fst destina!ie unde destina!ie poate fi un alt registru din stiv" sau o loca!ie de memorie de 32 sau 64 de bi!i (conversia de la precizia extins" se face automat). Dac" vrful stivei este etichetat special (adic" con!ine o valoare de tip infinit, NaN sau num"r denormalizat) atunci nu se face convesia nici pentru exponent, nici pentru mantis". Pentru a p"stra valoarea special", acestea sunt trunchiate la dreapta, la dimensiunea destina!iei. Un lucru foarte important de re!inut, demonstrat de urm"toarele comenzi, este c" aceast" instruc!iune nu extrage valoarea din stiv"; doar o copiaz". Dac" dore#ti s" copiezi #i s" extragi, adaugi sufixul p. (gdb) p $st0 $8 = 12.340000000000000000138777878078145 (gdb) x /1wf &m32 0x804913c <m32>: 12.3400002 (gdb) p $st0 $8 = 12.340000000000000000138777878078145 (gdb) p $st1 $9 = 3.1415926535897932380791280904119844 (gdb) n 35 mov eax,1

(gdb) x /1gf &m64 0x8049140 <m64>: 12.34 (gdb) p $st0 $10 = 12.340000000000000000138777878078145 n continuare prezent!m alte instruc"iuni de transfer. FILD surs! - converte#te operandul din memorie de la formatul ntreg binar la formatul real temporar #i depune rezultatul n stiv!. FBLD surs! converte#te operandul din memorie de la formatul zecimal mpachetat la formatul real temporar #i depune rezultatul n stiv!. FSTP destina"ie realizeaz! o opera"ie asem!n!toare cu FST, cu deosebirea c! extrage valoarea din stiva de registre. De asemenea, FSTP permite plasarea n memorie a unui num!r n precizie extins!, n timp ce FST nu accept! asta. Instruc"iunea FSTP ST0 realizeaz! extragerea din stiv! f!r! transfer n memorie. FIST destina"ie rotunje#te con"inutul registrului din vrful stivei la un ntreg (n conformitate cu bi"ii RC din registrul de control) #i transfer! rezultatul la destina"ie. Destina"ia poate fi de 32 sau 64 de bi"i. Zero negativ este memorat cu aceea#i codificare ca zero pozitiv. FISTP destina"ie instruc"iune similar! cu instruc"iunea anterioar!, dar n plus, gliseaz! o dat! stiva de registre. Destina"ia poate fi de orice tip ntreg. FBSTP destina"ie converte#te valoarea din vrful stivei la un ntreg zecimail mpachetat, depunde rezultatul n memorie #i gliseaz! stiva de registre. Conversia se face prin rotunjire ntreag!, prin adunarea valorii 0.5 #i apoi trunchierea rezultatului. FXCH destina"ie interschimb! destina"ia cu vrful stivei. Dac! destina"ia nu este specificat! explicit, se va utiliza implicit ST1. Instruc"iunea constituie un mijloc eficient de utilizare a instruc"iunilor n virgul! mobil! pe elementele existente n stiv!. De exemplu, secven"a urm!toare extrage r!d!cina p!trat! din al treilea registru din stiv!: FXCH ST3 FSQRT FXCH ST3 Urm!torul program demonstreaz! cum pot fi utilizate valorile constante prestabilite. ;

;fpuconsts.asm ; section .text global _start _start: nop fld1 fldz fldpi fldl2t fldl2e fldlg2 fldln2 mov eax,1 mov ebx,0 int 80h (gdb) info all st0 0.6931471805599453094286904741849753 st1 0.30102999566398119522564642835948945 st2 1.4426950408889634073876517827983434 st3 3.3219280948873623478083405569094566 st4 3.1415926535897932385128089594061862 st5 0 (raw 0x00000000000000000000) st6 1 (raw 0x3fff8000000000000000) st7 0 (raw 0x00000000000000000000) Valorile sunt plasate n ordinea invers! introducerii lor.

8.3.2. Opera!ii aritmetice n virgul" mobil"


A"a cum era de a"teptat, unitatea de calcul n virgul! mobil! pune la dispozi#ie "i instruc#iuni pentru realizarea func#iilor matematice de baz! cu valori n virgul! mobil!. Func#iile matematice de baz! sunt descrise n urm!torul tabel.
Tabelul 8.4 Opera!ii aritmetice n virgul" mobil"

Instruc!iune FADD FSUB FSUBR

Descriere Adunare n virgul! mobil! Sc!dere n virgul! mobil! Sc!dere invers! n virgul! mobil!

FMUL FDIV FDIVR

mnul!ire n virgul" mobil" mp"r!ire n virgul" mobil" mp"r!ire invers" n virgul" mobil"

Aceste instruc!iuni permit minimizarea referin!elor la memorie #i optimizeaz" utilizarea stivei de registre. Fiecare poate mbr"ca o varietate de forme. Adunarea Instruc!iunea FADD poate fi utilizat" n urm"toarele forme: FADD surs! adun" la registrul ST0 un operand n simpl" sau dubl" precizie aflat n memorie. Rezultatul r"mne n ST0. FADD ST(i),ST0 adun" ST0 la ST(i) #i stocheaz" rezultatul n ST(i). FADD ST0,ST(i) adun" ST(i) la ST0 #i stocheaz" rezultatul n ST0. FADDP ST(i),ST0 adun" ST0 la ST(i), stocheaz" rezultatul n ST(i) #i gliseaz" (pop) ST0. FADDP adun" ST0 cu ST1, stocheaz" rezultatul n ST1 #i gliseaz" stiva de registre. Rezultatul se va afla n ST0. Valoarea ini!ial" din ST1 este pierdut", valoarea din ST0 se va afla n ST7. FIADD ntreg adun" un ntreg de 16 sau 32 de bi!i la ST0 #i stocheaz" rezultatul n ST0. Urm"torul program demonstreaz" afirma!iile anterioare. ; ;fadd.asm ; section .data fa dd 2.5 fb dd 5.5 fc dd 8.0 fd dd 7.0 a dd 12 ;ntreg de 32 de bi!i section .text global _start _start: nop fld dword [fa] fld dword [fb] fld dword [fc]

fld dword [fd] faddp fadd dword [fc] faddp st2,st0 fadd st0,st2 faddp fiadd dword [a] mov eax,1 mov ebx,0 int 80h Executa!i primele patru instruc!iuni "i observa!i pozi!ia valorilor n stiva de registre. (gdb) info all st0 7 (raw 0x4001e000000000000000) st1 8 (raw 0x40028000000000000000) st2 5.5 (raw 0x4001b000000000000000) st3 2.5 (raw 0x4000a000000000000000) st4 0 (raw 0x00000000000000000000) Instruc!iunea FADDP adun# ST0 cu ST1 (7 + 8), p#streaz# rezultatul n ST1 (pierdem valoarea 8) "i gliseaz# ST0 (7). Registrul ST0 devine ST7 (7). ST1 (15) devine vrful stivei de registre "i "i modific# denumirea n ST0 (15). n urma acestor opera!ii stiva de registre arat# astfel: st0 st1 st2 st3 st3 st4 st5 st6 st7 5.5 2.5 0 0 0 0 0 15 (raw 0x4002f000000000000000) (raw 0x4001b000000000000000) (raw 0x4000a000000000000000) (raw 0x00000000000000000000) (raw 0x00000000000000000000) (raw 0x00000000000000000000) (raw 0x00000000000000000000) (raw 0x00000000000000000000) 7 (raw 0x4001e000000000000000)

Urm#toarea instruc!iune adun# la ST0 un operand din memorie. st0 st1 st2 5.5 2.5 23 (raw 0x4003b800000000000000) (raw 0x4001b000000000000000) (raw 0x4000a000000000000000)

st3

(raw 0x00000000000000000000)

Instruc!iunea FADDP ST2,ST0 adun" ST0 la ST2, rezultatul r"mne n ST2, #i gliseaz" ST0. A#adar, ST2 devine ST1, iar ST0 devine ST7. st0 st1 st2 st3 st4 st5 st6 st7 5.5 0 0 0 0 7 (raw 0x4001b000000000000000) 25.5 (raw 0x4003cc00000000000000) (raw 0x00000000000000000000) (raw 0x00000000000000000000) (raw 0x00000000000000000000) (raw 0x00000000000000000000) (raw 0x4001e000000000000000) 23 (raw 0x4003b800000000000000)

Instruc!iunea FADD ST0,ST2 adun" ST2 la ST0 #i p"streaz" rezultatul n ST0. Nu descarc" niciun registru. Ne d"m seama din faptul c" instruc!iunea nu este urmat" de sufixul P(OP). st0 st1 st2 -nan(0xc000000000000000) (raw 0xffffc000000000000000) 25.5 (raw 0x4003cc00000000000000) 0 (raw 0x00000000000000000000)

Dac" ne-am fi a#teptat s" rezulte o valoare de 5.5 ne-am n#elat. Registrul ST2 nu avea valoarea 0, ci era neutilizat (eticheta acestuia din registrul de etichete este 11). Opera!ia de adunare ntre o valoare #i un registru neutilizat a ntors o excep!ie de tip opera!ie invalid"; de aici rezult" valoarea NaN n registrul ST0. Urm"toarele dou" instruc!iuni, folosind NaN ca operand, au ca rezultat aceea#i valoare. Este foarte important s" !inem eviden!a st"rii registrelor de date. Fiecare variant" a instruc!iunilor aritmetice specific" registrul, rolul s"u n opera!ie #i dac" stiva de registre gliseaz" sau nu. Nu trebuie s" facem presupuneri, de cele mai multe ori sunt gre#ite. Sc!derea Instruc!iunea FSUB are un format similar cu instruc!iunea de adunare. Instruc!iunea de sc"dere fsub surs! execut" opera!ia ST0 = ST0 surs!

Numai c!, spre deosebire de adunare, sc!derea nu este comutativ! (ST0 surs! nu d! acela"i rezultat ca surs! ST0). Dac! avem nevoie de opera#ia invers!, surs! ST0, folosim instruc#iunea FSUBR (FSUB Reverse). fsubr surs! execut! opera#ia ST0 = surs! ST0

Similar instruc#iunii de adunare, FSUB are "i versiuni cu doi operanzi de tip registru, cu sau f!r! posibilitate de glisare a stivei de registre. FSUB ST(i),ST0 scade ST0 din ST(i) "i stocheaz! rezultatul n ST(i). FSUB ST0,ST(i) scade ST(i) din ST0 "i stocheaz! rezultatul n ST0. FSUBP scade ST0 din ST1, re#ine rezultatul n ST1 "i gliseaz! ST0. FSUBP ST(i),ST0 scade ST0 din ST(i), stocheaz! rezultatul n ST(i) "i gliseaz! ST0. FSUBRP ST(i),ST0 scade ST(i) din ST0, stocheaz! rezultatul n ST(i) "i gliseaz! ST0. Pentru a sc!dea un ntreg, putem folosi FISUB, pentru sc!derea standard, sau FISUBR, pentru cea invers!. ntregul de 16 sau 32 de bi#i trebuie s! fie n memorie. nmul!irea Instruc#iunea de nmul#ire are versiuni similare cu instruc#iunea de adunare: FMUL surs! nmul#e"te la registrul ST0 un operand n simpl! sau dubl! precizie aflat n memorie. Rezultatul r!mne n ST0. FMUL ST(i),ST0 nmul#e"te ST0 la ST(i) "i stocheaz! rezultatul n ST(i). FMUL ST0,ST(i) nmul#e"te ST(i) la ST0 "i stocheaz! rezultatul n ST0. FMULP ST(i),ST0 nmul#e"te ST0 la ST(i), stocheaz! rezultatul n ST(i) "i gliseaz! ST0. FMULP nmul#e"te ST0 cu ST1, stocheaz! rezultatul n ST1 "i gliseaz! ST0. FIMUL ntreg nmul#e"te un ntreg de 16 sau 32 de bi#i la ST0 "i stocheaz! rezultatul n ST0.

mp!r"irea Instruc!iunea de mp"r!ire are versiuni similare instruc!iunii de sc"dere. Cteva din acestea sunt: FDIV surs! mparte con!inutul registrului ST0 la surs! #i p"streaz" rezultatul n ST0 (ST0 = ST0/surs!). Operandul surs" poate fi o valoare n simpl" sau dubl" precizie aflat" n memorie. FDIVR surs! mparte con!inutul sursei la registrul ST0 #i p"streaz" rezultatul n ST0 (ST0 = surs!/ST0). FDIV ST(i),ST0 mparte ST(i) la ST0 #i stocheaz" rezultatul n ST(i). FDIV ST0,ST(i) mparte ST0 la ST(i) #i stocheaz" rezultatul n ST0. FDIVP mparte ST1 la ST0, re!ine rezultatul n ST1 #i gliseaz" ST0. FDIVRP mparte ST0 la ST1, re!ine rezultatul n ST1 #i gliseaz" ST0. FDIVP ST(i),ST0 mparte ST(i) la ST0, stocheaz" rezultatul n ST(i), #i gliseaz" ST0. FDIVRP ST(i),ST0 mparte ST0 din ST(i), stocheaz" rezultatul n ST(i) #i gliseaz" ST0. FIDIV ntreg mparte ST0 la un ntreg de 16 sau 32 de bi!i aflat n memorie.

8.3.3. Instruc!iuni transcedentale


Unitatea n virgul" mobil" pune la dispozi!ie mult mai multe func!ii matematice n virgul" mobil" dect simpla adunare, sc"dere, nmul!ire #i mp"r!ire. Grupul instruc!iunilor transcedentale realizeaz" calcule mari consumatoare de timp. Cuprinde toate func!iile trigonometrice, hiperbolice, inversele acestora, logaritmice #i exponen!iale. Toate aceste instruc!iuni opereaz" asupra primului sau primelor dou" elemente din vrful stivei #i returneaz" rezultatul lor n stiv". To!i operanzii trebuie s" fie normaliza!i, ceilal!i sunt considera!i invalizi. Dac" un operand este invalid, instruc!iunea va furniza un rezultat nedefinit, f"r" semnalarea unei excep!ii. Urm"torul tabel prezint" cteva din aceste func!ii avansate.
Tabelul 8.5 Instruc!iuni transcedentale

Instruc"iune Descriere FSIN Calculeaz" sinus din valoarea lui ST0 FCOS Calculeaz" cosinus din valoarea lui ST0

FSINCOS FABS FCHS FSCALE FSQRT FRNDINT F2XM1 FPATAN FPTAN FYL2X FYL2XP1

Calculeaz! att sin ct "i cos din valoarea lui ST0 Calculeaz! valoarea absolut! din valoarea lui ST0 Schimb! semnul valorii din ST0 Calculeaz! ST0 la puterea ST1 Calculeaz! r!d!cina p!trat! a valorii din ST0 Rotunje"te la cel mai apropiat ntreg valoarea lui ST0 Calculeaz! 2 la puterea ST0, minus 1 nlocuie"te ST1 cu arctan (ST1/ST0) "i descarc! ST0 nlocuie"te ST0 cu tangenta sa "i introduce 1 n stiva de registre Calculeaz! ST1 = ST1 * log2 ST0 "i descarc! (extrage) stiva Calculeaz! ST1 = ST1 * log2 (ST0+1.0)

8.3.4. Instruc!iuni de comparare


Din nefericire, compararea numerelor n virgul! mobil! nu este att de facil! precum aceea a numerelor ntregi. Cnd lucr!m cu ntregi "i dorim s! afl!m dac! o valoare este mai mare dect, egal! cu, sau mai mare dect, este u"or s! folosim instruc#iunea CMP "i s! evalu!m valorile din registrul de stare EFLAGS. n cazul numerelor n virgul! mobil! nu putem folosi instruc#iunea CMP. Unitatea FPU ofer! propriile instruc#iuni pentru compararea acestora. Una este fcom surs! Fcom compar! valoarea din ST0 cu sursa "i seteaz! indicatorii de stare FPU. Operandul surs! poate fi n memorie sau ntr-un registru. Dac! nu se d! niciun operand, instruc#iunea FCOM compar! registrul ST0 cu registrul ST1. Mai multe variante ale instruc#iunii sunt date n Tabelul 8.6.
Tabelul 8.6 Instruc!iuni de comparare n virgul" mobil"

Instruc!iune FCOM surs! FCOM FCOM ST(i) FCOMP FCOMP ST(i) FCOMP surs! FCOMPP FTST FICOM ntreg

Descriere Compar! ST0 cu o valoare de 32 sau 64 de bi#i din memorie Compar! registrul ST0 cu registrul ST1 Compar! registrul ST0 cu alt registrul de date Compar! ST0 cu ST1 "i gliseaz! stiva de registre Compar! ST0 cu alt registru de date "i gliseaz! stiva de registre Compar! ST0 cu o valoare din memorie "i gliseaz! stiva Compar! ST0 cu ST1 "i gliseaz! stiva de dou! ori Compar! registrul ST0 cu valoarea 0.0 Compar! ST0 un ntreg de 16 sau 32 de bi#i

Rezultatul compara#iei seteaz! bi#ii codurilor de condi#ii C0, C2 "i C3, din registrul

de stare. Condi!ie ST0 > surs! ST0 < surs! ST0 = surs! C3 0 0 1 C2 0 0 0 C0 0 1 0

A"a cum am men#ionat nainte, C1 indic! condi#ia de dep!"ire a stivei. Totu"i, acesta este utilizat de o instruc#iune din aceast! familie, instruc#iunea FXAM. Aceasta examineaz! num!rul din ST0 "i ncarc! bitul de semn n indicatorul C1 (0 pozitiv, 1 negativ). n plus, specific! tipul num!rului prin intermediul celorlal#i trei bi#i de condi#ie. Tip Neacceptat NaN Normalizat Infinit Zero Gol Denormalizat C3 0 0 0 0 1 1 1 C2 0 0 1 1 0 0 1 C0 0 1 0 1 0 1 1

Tipul neacceptat este un format care nu face parte din standardul IEEE 754. Celelalte tipuri au fost deja ntalnite pe parcurs. Pentru a determina starea bi#ilor de condi#ie (rezultatul compara#iei) trebuie s! copiem valoarea registrului de stare n registrul AX sau la o loca#ie de memorie cu instruc#iunea FSTSW, "i apoi s! o nc!rc!m n registrul EFLAGS cu instruc#iunea SAHF. ; ;fcom.asm ; section .data fs1 dd 1.923 fs2 dd 4.5532 section .text global _start _start: nop fld dword [fs1] fcom dword [fs2] fstsw AX

sahf ja greater jb lessthan mov eax,1 mov ebx,0 int 80h greater: mov eax,1 mov ebx,2 int 80h lessthan: mov eax,1 mov ebx,1 int 80h Instruc!iunea SAHF mut" bi!ii 0, 2, 4, 6 #i 7 din AH pe pozi!ia bi!ilor CF, PF, AF, ZF #i SF din registrul EFLAGS. Acest" mapare a bi!ilor din registrul de stare FPU la respectivii bi!i EFLAGS este una inten!ionat". A#adar, instruc!iunea FSTSW urmat" de SAHF are ca rezultat: mutarea bitului C0 pe pozi!ia CF mutarea bitului C2 pe pozi!ia PF mutarea bitului C3 pe pozi!ia ZF n acest moment putem determina rezultatul compara!iei prin acelea#i folosite pentru numerele ntregi, JA, JB #i JZ. Programul fcom.asm produce rezultate diferite n func!ie de valorile setate n memorie. Codul rezultat poate fi observat cu ajutorul comenzii echo: ./fcom echo $? 1 Rezultatul 1 indic" faptul c" prima valoare fs1 este mai mic" dect valoarea fs2. Pute!i modifica valorile din program astfel nct s" v" asigura!i c" acesta func!ioneaz" corect. ncepnd cu procesoarele Pentium P6, Intel a pus la dispozi!ie un nou mecanism de comparare: familia de instruc!iuni FCOMI. Instruc!iunea FCOMI #i variantele sale realizeaz" compara!ii n virgul" mobil" #i indic" rezultatul acestora direct prin bi!ii CF, PF #i ZF din registrul EFLAGS.

Tabelul 8.7 Instruc!iuni din familia FCOMI

Instruc!iune FCOMI FCOMIP FUCOMI FUCOMIP

Descriere Compar! registrul ST0 cu registrul ST(i) Compar! ST0 cu registrul ST(i) "i gliseaz! stiva de registre Verific! corectitudinea valorilor nainte de comparare Verific! corectitudinea valorilor nainte de comparare "i gliseaz! stiva

A"a cum reiese din Tabelul 8.7, o limitare a instruc#iunilor FCOMI este c! pot compara numai valori din registrele de date FPU, nu "i un registru de date cu o valoare din memorie. ns! ultimele dou! instruc#iuni ofer! un serviciu indisponibil instruc#iunilor din familia FCOM. FUCOMI "i FUCOMIP verific! faptul c! valorile ce vor fi comparate se reg!sesc ntr-un format valid (folosesc registrul de etichetare). Dac! este prezent! o valoare nenormalizat! se ntoarce o excep#ie. Rezultatul instruc#iunilor FCOMI asupra bi#ilor din registrul EFLAGS au urm!toarele semnifica#ii: Condi!ie ST0 > ST1 ST0 < ST1 ST0 = ST1 ; ;fcomi.asm ; section .data fs1 dd 1.4444 fs2 dd 4.5532 section .text global _start _start: nop fld dword [fs2] fld dword [fs1] fcomi st0,st1 ja greater jb lessthan mov eax,1 mov ebx,0 int 80h greater: ZF 0 0 1 PF 0 0 0 CF 0 1 0

mov eax,1 mov ebx,2 int 80h lessthan: mov eax,1 mov ebx,1 int 80h Deoarece instruc!iunea FCOMI compar" numai valori din registre FPU, valorile din memorie sunt nc"rcate n ordine invers", astfel nct, la momentul compar"rii, valoarea fs1 s" se afle n registrul ST0.

8.3.5. Instruc!iuni FPU de transfer condi!ionat


Similar instruc!iunilor de transfer condi!ionat pentru ntregi (CMOV), instruc!iunile FCMOV permit transferul valorilor n virgul" mobil" n func!ie de anumite condi!ii. Toate instruc!iunile din familia FCMOV mut" un registru ST(i) n registrul ST0 pe baza condi!iilor de adev"r prezente n registrul EFLAGS. Deoarece opera!ia se bazeaz" pe registrul EFLAGS, se obi#nuie#te ca instruc!iunea FCMOV s" fie precedat" de o instruc!iune FCOMI. Tabelul 8.8 prezint" instruc!iunile familiei FCMOV.
Tabelul 8.8 Instruc!iuni n virgul" mobil" de transfer condi!ionat

Instruc!iune FCMOVB FCMOVE FCMOVBE FCMOVU FCMOVNB FCMOVNE FCMOVNBE FCMOVNU

Descriere Mut" dac" ST0 este mai mic dect ST(i) (CF=1) Mut" dac" ST0 este egal cu ST(i) (ZF=1) Mut" dac" ST0 este mai mic sau egal cu ST(i) (CF=1 sau ZF=1) Mut" dac" ST0 este neordonat (PF=1) Mut" dac" ST0 nu este mai mic dect ST(i) (CF=0) Mut" dac" ST0 nu este egal cu ST(i) (ZF=0) Mut" dac" ST0 nu este mai mic sau egal cu ST(i) (CF=0 sau ZF=0) Mut" dac" ST0 nu este neordonat (PF=0)

Instruc!iuni de control Aceste instruc!iuni se folosesc pentru activit"!i de ini!ializare, gestionare a excep!iilor #i comutare de proces. Ele permit salvarea st"rii curente a unit"!ii de calcul n virgul" mobil" (contextul FPU) #i revenirea la aceasta dup" ncheierea altui proces. Una din aceste instuc!iuni este FSTENV, utilizat" pentru stocarea ntr-o

zon! de memorie a ntregului context FPU. Sunt salvate urm!toarele informa"ii: registrul de control, registrul de stare, registrul de etichete, valoarea indicatorului de instruc"iune FPU, valoarea indicatorului de date FPU, valoarea ultimului cod opera"ional FPU executat. Valorile sunt stocate ntr-un bloc de memorie de 28 de octe"i. Instruc"iunea FLDENV efectueaz! procesul invers, ncarc! valorile din blocul de memorie napoi n unitatea FPU. Urm!torul program demonstreaz! efectul acestor instruc"iuni. ; ;fpuenv.asm ; section .data fs1 dd 34.78 fs2 dd 78.34 fs3 dd 100.1 fs4 dd 200.1 w dw 0b7fH section .bss buffer resb 28 section .text global _start _start: nop finit fld dword [fs1] fld dword [fs2] fldcw [w] fstenv [buffer] finit fld dword [fs3] fld dword [fs4] fldenv [buffer] mov eax,1 mov ebx,0 int 80h Programul fpuenv.asm ini"ializeaz! unitatea FPU, ncarc! cteva valori n registrele

de date FPU, modific! cmpul bi"ilor de rotunjire din registrul de control #i stocheaz! contextul FPU n cei 28 de octe"i ai loca"iei de memorie buffer. nainte de instruc"iunea FSTENV registrele FPU arat! astfel: (gdb) info all st0 78.339996337890625 (raw 0x40059cae140000000000) st1 34.779998779296875 (raw 0x40048b1eb80000000000) st2 0 (raw 0x00000000000000000000) st3 0 (raw 0x00000000000000000000) st4 0 (raw 0x00000000000000000000) st5 0 (raw 0x00000000000000000000) st6 0 (raw 0x00000000000000000000) st7 0 (raw 0x00000000000000000000) fctrl 0xb7f 2943 fstat 0x3000 12288 ftag 0xfff 4095 Observa"i valorile registrelor de control, stare #i etichete. Acelea#i valori sunt prezente n buffer dup! execu"ia instruc"iunii FSTENV: (gdb) x /28xb &buffer 0x80490d4 <buffer>: 0x7f 0xff 0x80490dc <buffer+8>: 0xff 0x08 0x80490e4 <buffer+16>: 0x04 0x08 0x80490ec <buffer+24>: 0x0b 0xff 0x0f 0xff 0x00 0x00 0x00 0x00 0xff 0xff 0x05 0xff 0x00 0x30 0xff 0x8a 0x01 0xff 0x80 0xc4 0x04 0x90

Dup! salvarea st!rii curente, unitatea FPU este ini"ializat! #i se introduc din nou cteva valori de date. Privi"i valorile nregistrate de registrele FPU nainte #i dup! execu"ia instruc"iunii FLDENV. Observa"i c! n urma execu"iei FLDENV valorile registrelor de date ST0...ST7 nu au fost restaurate, dar registrele de control, stare #i etichete indic! valorile dinainte de instruc"iunea FSTENV. Instruc"iunea FSTENV stocheaz! contextul FPU, dar nu #i valorile registrelor de date. Salvarea context FPU plus date se face cu instruc"iunea FSAVE. Instruc"iunea FSAVE copiaz! ntr-o loca"ie de memorie de 108 octe"i toate registrele interne ale unit!"ii FPU (inclusiv registrele de date), dup! care o reini"ializeaz!. La restaurarea cu instruc"iunea FRSTOR, toate registrele sunt readuse la valoarea dinaintea execu"iei FSAVE. ;

;fpusave.asm ; section .data fs1 dd 34.78 fs2 dd 78.34 fs3 dd 100.1 fs4 dd 200.1 w dw 0b7fH section .bss buffer resb 108 section .text global _start _start: nop finit fld dword [fs1] fld dword [fs2] fldcw [w] fsave [buffer] fld dword [fs3] fld dword [fs4] frstor [buffer] mov eax,1 mov ebx,0 int 80h n urma execu!iei FSAVE, zona de memorie nu con!ine numai valorile din registrele de control, stare "i etichete, ci "i pe cele ale registrelor de date. De asemenea, FSAVE realizeaz# automat ini!ializarea unit#!ii FPU (de aceea acest program nu con!ine al doilea FINIT). Dup# execu!ia instruc!iunii FRSTOR pute!i observa c# toate registrele sunt readuse la starea dinaintea FSAVE. Alte instruc!iuni din aceast# categorie sunt prezentate pe scurt n Tabelul 8.9. Multe din instuc!iunile de control ale unit#!ii FPU au dou# forme: form# wait, prefixat# numai cu litera F, de exemplu FINIT. form# non-wait, prefixat# cu FN, de exemplu FNINIT. Termenii wait "i non-wait se refer# la modul n care instruc!iunile trateaz# excep!iile n virgul# mobil#. Excep!iile au fost discutate anterior n sec!iunea dedicat# registrului de stare. Instruc!iunile n virgul# mobil# pot genera "ase tipuri

de excep!ii. De obicei, acestea semnalizeaz" apari!ia unei erori aritmetice. Majoritatea instruc!iunilor a#teapt" (sunt ntrziate) s" verifice dac" nu cumva instruc!iunea anterioar" returneaz" o excep!ie. Dac" este prezent" o excep!ie, aceasta trebuie tratat" nainte de execu!ia urm"toarei instruc!iuni. Alternativ, unele instruc!iuni au versiuni non-wait, care nu a#teapt" s" verifice apari!ia unei excep!ii n virgul" mobil". Aceste instruc!iuni permit programului s" salveze sau s" reseteze starea curent a unit"!ii FPU f"r" a trata excep!ii.
Tabelul 8.9 Instruc!iuni de control FPU

Instruc!iune FINIT/FNINIT FCLEX/FNCLEX FSAVE/FNSAVE FRSTOR FSTENV/FNSTENV FLDENV FSTCW/FNSTCW FSTSW/FNSTSW FLDCW FDECSTP FINCSTP FFREE ST(i) FNOP

Descriere Ini!ializeaz" unitatea FPU $terge to!i indicatorii de excep!ie din cuvntul de stare Salveaz" n memorie contextul complet al unit"!ii FPU ncarc" din memorie contextul complet al unit"!ii FPU Salveaz" n memorie contextul FPU ncarc" contextul FPU din memorie Salveaz" n memorie cuvntul de stare curent Salveaz" cuvntul de stare curent n AX sau ntr-o loca!ie de memorie ncarc" cuvntul de stare din memorie Decrementeaz" cmpul TOP din cuvntul de stare. Dac" TOP este 0, prin decrementare devine 7. Incrementeaz" cmpult TOP. Dac" TOP este 7, devine 0. Marcheaz" ST(i) ca neutilizat Echivalentul NOP de la numere ntregi

8.4. Exerci!ii
8.1. Converti!i manual urm"toarele numere n format IEEE 754 de 32 de bi!i. a) b) c) d) 1.1 -0.1 2005.0 0.0039 e) -2015.3125 f) 0.33 g) -0.67 h) 3.14

8.2. Converti!i manual n numere zecimale urm"toarele valori date n format IEEE 754 simpl" precizie. a) 4000 0000 e) c180 4000

b) bf80 0000 c) 3d80 0000 d) c259 48b4

f) 42f6 e666 g) 3f99 999a h) 42c8 1000

8.3. Urm!torul program calculeaz! r!d!cinile unei ecua"ii de gradul al II-lea, ! ! ! ! !" ! ! ! !. Cele dou! r!d!cini sunt definite astfel: !! ! ! ! ! !!" ! !! !! ! ! ! ! !!" !! ! ! !! !! ! R!d!cinile sunt reale dac! ! ! ! !!" , n caz contrar, r!d!cinile sunt imaginare. Rula"i programul #i observa"i efectul fiec!rei instruc"iuni. Modifica"i valorile coeficien"ilor #i, pentru fiecare caz, la finalul programului, afi#a"i r!d!cinile cu ajutorul comenzii x /1gf &r1, respectiv &r2. section .data a dq 2.0 b dq -3.0 c dq 1.0 section .bss r1 resq 1 r2 resq 1 real resb 1 section .text global _start _start: nop finit fld qword [a] fadd ST0 fld qword [a] fld qword [c] fmulp ST1 fadd ST0 fadd ST0 fchs

fld qword [b] fld qword [b] fmulp ST1 faddp ST1 ftst fstsw AX sahf jb no_real_roots fsqrt fld qword [b] fchs fadd ST1 fdiv ST2 fstp qword [r1] fchs fld qword [b] fsubp ST1 fdivrp ST1 fstp qword [r2] mov al,1 mov [real],al jmp sfarsit no_real_roots: mov al,0 mov [real],al sfarsit: mov eax,1 mov ebx,0 int 80h

9. FUNC!II

Programele prezentate pn! acum au fost alc!tuite dintr-un singur modul (prin modul n"elegnd o singur! unitate logic! de prelucrare). Acest lucru a fost posibil deoarece problemele au fost simple. Numai problemele simple pot fi rezolvate ntr-o singur! secven#! de cod. De obicei, pentru rezolvarea unor aplica#ii complexe, trebuie s! descompunem problema n subprobleme mai simple, relativ independente, scriind module de program distincte pentru fiecare din acestea. De asemenea, dac! o aplica#ie necesit! rularea repetat! a unei secven#e de instruc#iuni, n loc s! scriem de mai multe ori acela$i cod este indicat s! introducem secven#a respectiv! ntr-un modul separat ce poate fi apelat de oriunde din program. Modulele prelucrez! valori de intrare primite din program (numit program principal) %i returneaz! rezultate. Acest capitol prezint! posibilit!#ile de care dispune un programator n limbaj de asamblare pentru a crea module dedicate unor procese simple, regulile pe care trebuie s! le respecte n elaborarea acestora, precum %i modul de interac"iune a modulelor cu programul principal.

9.1. Modularizarea programelor


n matematic!, putem ob"ine func"ii orict de complexe prin compunerea unor func"ii elementare (func"ia polinomial!, func"ia de ridicare la putere sau de extragere radical, etc.). n programare, putem construi programe orict de complexe prin tehnica de modularizare, adic! prin nl!n"uirea logic! a unor unit!"i elementare de program: citirea datelor de intrare (modulul de citire a datelor), prelucrarea lor (modulul de prelucrare), afi#area rezultatelor ob"inute n urma prelucr!rii (modulul de afi#are a rezultatelor). Mul"imea valorilor care constituie datele de intrare #i datele de ie#ire ale subprogramului formeaz! lista parametrilor de intrare, respectiv de ie#ire. Din acest punct de vedere, n programare ntlnim dou! categorii de subprograme: proceduri subprograme care primesc ca date de intrare oricte valori #i returneaz! ca rezultat o singur! valoare, mai multe valori, sau niciuna (poate efectua o prelucrare care s! nu aib! ca efect ob"inerea unei valori); func"ii subprograme care primesc ca date de intrare oricte valori, dar returneaz! ca rezultat o valoare #i numai una.

Teoretic, o func!ie returneaz" ntotdeauna o valoare. Cu toate acestea, unele limbaje de programare, cum ar fi C, dispun #i de func!ii f"r" tip, care nu returneaz" nicio valoare. n aceste condi!ii, diferen!ele dintre proceduri #i func!ii ncep s" devin" discutabile. n continuare, pentru consisten!a cu limbajul C, vom folosi no!iunea de func!ie, singura admis" de acesta. Pute!i considera procedura ca fiind un termen generic pentru func!ie.

9.2. Apelarea func!iilor


n C, nsu#i programul principal este o func!ie cu nume rezervat (main). Deoarece nu numai programul principal admite func$ii, ci %i o func$ie oarecare poate avea, la rndul s"u, alte func$ii, orice program care apeleaz" o func$ie se nume%te program apelant. Prin apelarea unei func$ii de c"tre un program apelant n$elegem o comand" pe care programul apelant o trimite func$iei, comand" prin care i cere acesteia s" execute opera$iile din blocul s"u de instruc$iuni. O func$ie poate fi apelat" ori de cte ori este nevoie %i con$ine tot codul necesar realiz"rii complete a unui proces. Nu necesit" asisten$" din partea programului apelant. Parametrii (datele de intrare) cu care lucreaz" func$ia pot fi diferi$i de la apel la apel %i sunt furniza$i acesteia din interiorul programului apelant. _start:

call <nume_func$ie>

exit <nume_func$ie>:

ret
Figura 9.1 Apelarea func!iilor

La apelul unei func!ii, execu!ia programului sare la prima instruc!iune a acesteia. Procesorul execut" instruc!iunile func!iei pn" cnd ntlne#te instruc!iunea RET. RET red" controlul programului apelant din locul n care a fost apelat" func!ia.

9.3. Definirea func!iilor


Crearea unei func!ii n limbajul de asamblare presupune trei etape: definirea valorilor de intrare necesare acesteia, definirea opera!iilor care trebuie efectuate asupra valorilor de intrare, definirea modului de ob$inere %i transmitere c"tre programul apelant a valorilor de ie#ire. Modul n care se define#te o func!ie depinde de asamblor. n YASM, trebuie numai s" d"m un nume secven!ei de instruc!iuni respective. Odat" creat", rutina poate fi accesat" de oriunde din programul principal prin instruc!iunea CALL. Instruc!iunea CALL are un singur operand, numele func!iei. Urm"torul program folose#te o func!ie pentru a interschimba valorile din dou" registre. ; ;functie1.asm ; section .data temp dd 0 section .text global _start _start: nop mov eax,3 mov ebx,4 call _functie mov mov int _functie: mov mov mov ret eax,1 ebx,0 080h [temp],ebx ebx,eax eax,[temp]

9.4. Transferul controlului


n programul anterior, codul func!iei a fost plasat la sfr"itul programului principal. Textul func!iei poate fi pozi!ionat la fel de bine "i la nceput, imediat dup# directiva section .text. Cnd am discutat despre rolul etichetei _start am precizat c# editorul de leg#turi folose"te aceast# etichet# pentru aflarea instruc!iunii de nceput a programului (instruc!iunea cu care trebuie s# nceap# execu!ia programului). nainte de _start putem avea orice num#r de func!ii f#r# ca execu!ia programului s# fie afectat# n vreun fel. n plus, spre deosebire de unele limbaje de nivel nalt, n asamblare, func!iile nu trebuie definite nainte de apelare. Tot ceea ce caut# instruc!iunea CALL este eticheta care specific# adresa de nceput a func!iei, adres# ce va fi nc#rcat# n registrul indicator de instruc!iune. Func!ia din programul urm#tor calculeaz# complementul fa!# de doi pentru valorile 3 "i 5, rezultatul reg#sindu-se n registrul EDX. Complementul fa!# de doi se ob!ine cu instruc!iunea NEG inverseaz# bi!ii "i adun# 1. Dac# vrem s# ob!inem complementul fa!# de unu, folosim instruc!iunea NOT, actualmente comentat#. ; ;func!ie2.asm ; section .bss mem resd 1 rez resd 1 section .text functie: ; not dword [mem] neg dword [mem] mov edx,[mem] ret global _start _start: nop mov dword [mem],3 call functie mov dword [mem],5 call functie mov eax,1 mov ebx,0 ;complementul fa!# de unu ;complementul fa!# de doi

int 080h Instruc!iunea CALL, la apelare, salveaz" n stiv" con!inutul registrului EIP #i l ini!ializeaz" cu adresa de nceput a func!iei. Numele acesteia este nlocuit de asamblor cu deplasamentul calculat ntre loca!ia lui CALL $i loca!ia func!iei. A#adar, n programul anterior, numele functie este un deplasament. Acest deplasament, dup" salvarea con!inutului registrului EIP n stiv", este adunat la valoarea EIP. Se ajunge astfel la nceputul func!iei. Evident, valoarea deplasamentului poate fi negativ" sau pozitiv", n func!ie de pozi%ia func!iei n program. Instruc!iunea RET restabile#te n EIP adresa salvat" de instruc!iunea CALL.

9.5. Metode de transfer al parametrilor


De obicei, func%iile au nevoie de parametri de intrare. O func%ie poate primi parametri de intrare din programul apelant prin trei metode: Prin intermediul registrelor; Prin intermediul variabilelor globale; Prin intermediul stivei.

9.5.1. Prin registre


A#a cum reiese din nume, metoda transferului prin registre presupune folosirea unor registre de uz general. nainte de apelul func!iei, programul principal introduce to!i parametrii necesari acesteia n anumite registre. ; ;regTr.asm ; section .data d1 dd 3 d2 dd 5 section .bss temp resd 1 section .text ;definim functiile global _functie _functie: mov [temp],ebx

mov ebx,eax mov eax,[temp] ;revenire din func!ie n programul principal ret ;nceputul programului principal global _start _start: nop mov eax,[d1] mov ebx,[d2] ;intrare n func!ie call _functie ;revenire din func!ie mov [d1],eax mov [d2],ebx mov eax,1 mov ebx,0 int 080h Se observ" cum func!ia prime#te parametri de intrare de la programul principal prin registrele EAX #i EBX. Rezultatul este returnat programului prin acelea#i registre. Aceast" metod" este rapid", toate argumentele se g"sesc n registre. ns", dac" folosim registre #i n corpul func!iei, nu exist" nicio garan!ie c" valoarea acestora va fi identic" cu cea de la intrarea n func!ie. Altfel spus, e posibil ca valorile registrelor de la ie#irea din func!ie s" difere de cele de pn" la intrarea n func!ie. Din acest motiv este indicat s" urm"rim registrele folosite de func!ie pentru procesul ei intern. Att registrele ct #i loca!iile de memorie folosite n interiorul func!iei pot avea alt" valoare la rentoarcerea n program. Dac" o func!ie modific" registrele folosite de programul principal este crucial s" salv"m con!inutul lor nainte de apelul func!iei. Salvarea se poate face cu instruc!iunile PUSH, PUSHA. Restaurarea cu POP, POPA. De asemenea, trebuie s" fim aten!i care sunt registrele folosite de func$ie pentru returnarea rezultatului. Dac" acestea sunt suprascrise, func!ia a fost efectuat" inutil. Din moment ce procesorul nu dispune de foarte multe registre de uz general, un dezavantaj implicit al metodei este num"rul mic de argumente care poate fi furnizat func!iei. Dezavantajele modalit"!ii de transmitere a parametrilor prin intermediul registrelor: neconvenabil" - dac" se transmite un num"r mare de parametrii,

num!rul registrelor poate fi insuficient; neeconomic! sub aspectul timpului de execu"ie - necesit! salv!ri #i restaur!ri frecvente de registre.

9.5.2. Prin variabile globale


n aceast! metod!, parametrii de intrare sunt transmi#i func"iei prin intermediul unor variabile ce pot fi accesate att de programul principal ct #i de func"ie. Toate func"iile au acces la loca"iile de memorie definite n programul principal. Deoarece aceste loca"ii sunt accesibile tuturor func"iilor, ele se numesc variabile globale. Func"iile pot folosi variabilele globale n orice scop, incluznd transferul datelor ntre program #i func"ii. ; ;memTr.asm ; section .bss mem resd 1 rez resd 1 section .text functie: ; not dword [mem] neg dword [mem] mov edx,[mem] ret global _start _start: nop mov dword [mem],3 call functie mov dword [mem],5 call functie mov eax,1 mov ebx,0 int 080h Programul memTr.asm demonstreaz! cum pot fi interschimbate date ntre func"ie #i programul principal prin intermediul variabilei globale mem. Transmiterea parametrilor prin variabile globale presupune rezervarea de memorie pentru fiecare din ace$tia, a#adar poate fi neeconomic! din punct de

vedere al spa!iului de memorie ocupat (n special dac" se folosesc structuri mari de date necesare numai temporar).

9.5.3. Prin stiv!


Stiva este accesibil" programului principal, dar #i tuturor func!iilor folosite n acel program, permi!nd schimbul facil de date ntre programul apelant #i func!ii. Prin folosirea stivei ca mijloc de tranfer al parametrilor sunt evitate problemele ridicate de transferul datelor prin registre sau memorie. Aceasta este #i modalitatea de transfer a parametrilor preferat" de toate func!iile limbajului C. Din acest motiv, metoda se mai nume#te apelul func!iei n stilul C (C style function calling). Dac" este folosit" stiva, metoda obi#nuit" de returnare a rezultatelor n programul apelant se face prin: registrul EAX pentru rezultate de 32 de bi!i; al"turarea registrelor EDX:EAX pentru rezultate de 64 de bi!i; FPU ST(0) pentru valori n virgul" mobil" (floating point). Ne amintim c! stiva este alc!tuit! din loca"ii de memorie rezervate la sfr#itul spa"iului de memorie alocat programului. Datele pot fi introduse sau extrase numai de la vrful stivei. Vrful stivei este indicat de registrul ESP. n mod obi#nuit, datele sunt introduse n stiv" cu instruc!iunea PUSH #i extrase cu instruc!iunea POP. PUSH plaseaz" elementul de date la adresa indicat" de registrul ESP #i totodat" decrementeaz" automat valoarea acestuia astfel nct s" indice urm"toarea loca!ie liber". POP extrage din stiv" elementul de date (ntr-un registru sau loca!ie de memorie) #i incrementeaz" valoarea registrului ESP astfel nct acesta s" indice valoarea precedent". Rula!i urm"torul program. ; ;cStyleCall.asm ; section .bss rez1 resd 1 rez2 resd 1 section .text global _start _start: nop Afi#"m valoarea registrului ESP: (gdb) print /x $esp $1 = 0xbfc65cd0 (gdb) n 9 call functie (gdb) print /x $esp $2 = 0xbfc65ccc Afi#"m con!inutul stivei: (gdb) x /1bd 0xbfc65ccc

push 5 call functie mov [rez1],eax push 10 call functie mov [rez2],eax mov eax,1 mov ebx,0 int 080h functie: pop eax neg eax ret

0xbfc65ccc: 5 (gdb) n 20 pop eax (gdb) print /x $esp $3 = 0xbfc65cc8 (gdb) x /xw 0xbfc65cc8 0xbfc65cc8: 0x0804808b (gdb) x /2xw 0xbfc65cc8 0xbfc65cc8: 0x0804808b 0x00000005 (gdb) n 21 neg eax (gdb) print /x $esp $4 = 0xbfc65ccc (gdb) print /x $eax $5 = 0x804808b (gdb) n 23 ret (gdb) print /x $eax $6 = 0xf7fb7f75 (gdb) n 0x00000005 in ?? ()

Teoretic, programul cSyleCall.asm ar fi trebuit s! func"ioneze corect. Programul introduce paramentrul 5 n stiv! #i apeleaz! func"ia. Func"ia extrage paramentrul din stiv!, i calculeaz! complementul fa"! de doi #i returneaz! rezultatul n registrul EAX. Dac! nu a"i f!cut-o deja, rula"i programul pas cu pas, privind n stiv!. ntr-adev!r, programul principal introduce num!rul 5 n stiv! (de unde ar trebui preluat de func"ie cu ajutorul instruc"iunii POP). Dar am uitat c! la apelare, instruc"iunea CALL introduce automat n stiv! adresa de revenire n programul apelant. A#adar, ceea ce extrage POP-ul func"iei este adresa de revenire, c!reia i calculeaz! complementul fa"! de doi. Pentru c! adresa a fost extras! din stiv!, instruc"iunea RET furnizeaz! programului ca adres! de revenire valoarea 5. Programul nu mai poate continua. Am pierdut valoarea adresei de revenire. Aspectul stivei la apelul func"iei poate fi reprezentat astfel:

Stiv!

Paramentrul func"iei Adresa de revenire


31 0

ESP

Recapitul!m pa#ii care apar n cazul furniz!rii parametrilor func"iei prin intermediul stivei. 1. nainte de apelul func"iei (prin instruc"iunea CALL), programul apelant plaseaz! la vrful stivei paramentrii de intrare necesari acesteia. Dac! func"ia trebuie s! primeasc! mai mul"i parametrii, standardul C stabile$te ca ace#tia s! fie introdu#i n stiv! n ordinea invers! extragerii lor de c!tre func"ie (lucru normal din moment ce nu putem extrage din stiv! dect n ordinea invers! introducerii). 2. Cnd este executat!, instruc"iunea CALL plaseaz! adresa de revenire n programul apelant tot la vrful stivei, astfel nct func"ia s! #tie de unde s! redea controlul acestuia. n urma acestor pa#i, reprezentarea stivei arat! astfel: Stiv!

Paramentru 3 func"ie Parametru 2 func"ie Paramentru 1 func"ie Adresa de revenire


31 0

ESP

Registrul ESP indic! loca"ia adresei de revenire n program. To"i parametrii de intrare ai func"iei se g!sesc deasupra adresei de revenire n program. Dac!

extragem parametrii de intrare cu instruc!iunea POP, adresa de revenire s-ar putea pierde (a"a cum s-a ntamplat n programul nostru anterior). A"adar trebuie s# recurgem la o metod# diferit# de extragere a parametrilor din stiv#. ntr-un capitol anterior am prezentat adresarea bazat# a memoriei. Adresarea bazat# pune la dispozi!ie o metod# de acces la loca!ii de memorie pe baza unei adrese aflate ntr-un registru. Deoarece ESP indic# vrful stivei, pentru a accesa parametrii de intrare f#r# a fi nevoie de extragerea lor cu POP, func!ia poate folosi adresarea bazat# cu registrul ESP drept registru de baz#. Fiecare paramentru de intrare poate fi accesat indirect printr-un deplasament adunat la adresa din registrul ESP (Aten!ie, n figur#, fiecare c#su!# reprezint# 4 octe!i). Stiv#

Paramentru 3 func!ie Parametru 2 func!ie Paramentru 1 func!ie Adresa de revenire


31 0

ESP + 12 ESP + 8 ESP + 4 ESP

Lund n considerare modul n care arat# stiva, putem schimba func!ia programului nostru astfel: functie: mov eax,[esp+4] neg eax ret Rul#m programul "i vedem c# de aceast# dat# adresa de revenire este p#strat# "i totul func!ioneaz# corect. Totu"i, nu am sc#pat complet de nepl#ceri. Problem! I: Este posibil ca, n timpul rul#rii func!iei, aceasta s# introduc# date n stiv#. Dac# se ntmpl# acest lucru, valoarea lui ESP se modific# "i adresarea bazat# nu d# rezultatul scontat. Presupunem c# func!ia trebuie s# introduc# n stiv# con!inutul registrului EBX. Se ruleaz# programul schimbnd secven!a de cod a func!iei astfel:

functie: push ebx mov eax,[esp+4] neg eax pop ebx ret Prin introducerea lui EBX n stiv!, ESP + 4 indic! adresa de revenire. Iar!"i extragem adresa de revenire "i i calcul!m complementul fa#! de doi. De aceast! dat! ns!, din moment ce nu am extras-o cu POP, ci numai am adresat-o indirect, nu pierdem valoarea adresei de revenire n program. ns! rezultatul func#iei este eronat - am calculat complementul fa$! de doi al adresei de revenire, nu al parametrului de intrare. Rezolvare I: Prima instruc$iune a func$iei trebuie s! salveze vrful ini$ial al stivei. Se copiaz! astfel valoarea registrului ESP n registrul EBP. Acest mecanism garanteaz! c! exist! ntotdeauna un registru care indic! corect vrful ini#ial al stivei (existent la momentul apel!rii func#iei). Datele introduse de func#ie nu afecteaz! EBP, doar ESP. functie: mov ebp,esp push ebx mov eax,[ebp+4] neg eax pop ebx mov esp,ebp ret Problem! II: Registrul EBP poate fi folosit de programul principal. Salvarea adresei de nceput a stivei n EBP i suprascrie acestuia valoarea anterioar! "i poate deregla execu#ia corect! a programului apelant. Rezolvare II: nainte de copierea valorii din ESP n EBP, salv!m registrul EBP n stiv!. De acum, codul de nceput %i sfr%it al func#iei seam!n! cu un prolog, respectiv un

epilog. functie: push ebp mov ebp,esp <corpul func!iei> mov esp,ebp pop ebp ret Stiv" epilog

prolog

Paramentru 3 func!ie Parametru 2 func!ie Paramentru 1 func!ie Adresa de revenire ESP


31

EBP + 16 EBP + 12 EBP + 8 EBP + 4 EBP


0

Vechiul EBP

Datele locale func!iei Ultima reprezentare a stivei rezist" pn" cnd func!ia ns"#i are nevoie s" foloseasc" stiva pentru stocarea variabilelor locale (variabilele din interiorul func!iei). Func!ia ar putea folosi registre pentru stocarea propriilor variabile, dar acestea pun la dispozi!ie un spa!iu limitat de manevr", sau ar putea folosi variabile globale, ceea ce ar nsemna s" le cre"m noi n programul principal (s" punem la dispozi!ie elemente de date dedicate func!iei). A#adar, tot stiva r"mne cea mai bun" solu!ie. S" ne amintim: o dat" ce am fixat EBP la vrful stivei, orice variabil" folosit" n func!ie (variabil" local") poate fi plasat" n stiv" dup" acel punct f"r" s" afecteze modul de acces la paramentrii de intrare. Ele pot fi adresate u#or prin

intermediul registrul EBP. De exemplu, presupunnd valori de 4 octe!i, prima variabil" local" poate fi adresat" cu [EBP - 4], a doua cu [EBP - 8], etc..Func!ia care calculeaz" complementul fa!" de doi #i adun" doi, devine: functie: push ebp mov ebp,esp

prolog

push ebx mov eax,[ebp+4] mov [ebp-4],2 ;variabil" local" 1 mov [ebp-8],6 ;variabil" local" 2 mov [ebp-12],7 ;variabil" local" 3 neg eax add eax,[ebp-4] pop ebx mov esp,ebp pop ebp ret Stiv" epilog

Paramentru 3 func!ie Parametru 2 func!ie Paramentru 1 func!ie Adresa de revenire ESP Vechiul EBP Variabil" local" 1 Variabil" local" 2 Variabil" local" 3
31 0

EBP + 16 EBP + 12 EBP + 8 EBP + 4 EBP EBP - 4 EBP - 8 EBP - 12

Problem! III: A!a cum reiese din ultima figur", ESP nc" indic" vechea adres" a EBP. Dac" func#ia plaseaz" n stiv" variabile locale (ca n exemplul anterior Variabila local" 1,2,3), dar n corpul ei mai con#ine $i instruc#iuni PUSH, acestea, folosind ESP, suprascriu valorile variabilelor locale. Pierdem variabilele func#iei. functie: push ebp mov ebp,esp push ebx mov eax,[ebp+4] mov [ebp-4],2 mov [ebp-8],6 mov [ebp-12],7 push 20 push 60 push 70 neg eax add eax,[ebp-4] pop ebx mov esp,ebp pop ebp ret Rezolvare III: La nceputul func#iei, imediat dup" secven#a de intrare n func#ie (dup" prolog), rezerv"m n stiv" un anumit spa#iu pentru variabilele locale, sc"znd din ESP valoarea dorit". Astfel, dac" vor fi introduse n stiv" date suplimentare, acestea vor fi plasate sub variabilele locale. n aceste condi#ii, registrul ESP poate fi folosit n mod obi$nuit, cu instruc#iunea PUSH, f"r" s" afecteze variabilele func#iei. La sfr!itul func"iei, registrul ESP este rescris cu valoarea sa de nceput (n epilog) !i variabilele func"iei vor fi pierdute din stiv# de aici !i denumirea de variabile locale. Func#ia programului nostru devine:

Prolog (intrarea n func%ie)

;variabil" local" 1 ;variabil" local" 2 ;variabil" local" 3 Suprascriu variabilele locale

Epilog (ie!irea din func%ie)

functie: push ebp prolog mov ebp,esp sub esp,12 ;rezerv! 12 octe"i pentru variabilele locale push ebx mov eax,[ebp+4] mov [ebp-4],2 ;variabila local! 1 mov [ebp-8],6 ;variabila local! 2 mov [ebp-12],7 ;variabila local! 3 push 20 push 60 variabilele locale nu sunt suprascrise push 70 neg eax add eax,[ebp-4] pop ebx mov esp,ebp pop ebp ret epilog

9.5.4. Structura func!iei


Structura de ansamblu a func"iei, cu noul prolog, este: functie: push ebp mov ebp,esp sub esp,12

Prolog (intrarea n func%ie)

Corpul func%iei mov esp,ebp pop ebp ret

Epilog (ie$irea din func%ie)

Aspectul final al stivei este ar!tat n Figura 9.2. Informa"ia stocat! n stiv! parametrii de intrare, adresa de revenire n programul principal, vechea adres! EBP #i variabilele locale formeaz! ceea ce poart! numele de cadru de stiv! (stack

frame). Valoarea curent! a registrului EBP se nume"te indicator de cadru (frame pointer). Odat! cunoscut!, toate elementele cadrului de stiv! pot fi accesate prin intermediul ei. Stiv!

Paramentru 3 func#ie Parametru 2 func#ie Paramentru 1 func#ie Adresa de revenire Vechiul EBP Variabil! local! 1 -12 ESP
31 Figura 9.2 Aspectul stivei

EBP + 16 EBP + 12 EBP + 8 EBP + 4 EBP EBP - 4 EBP - 8 EBP - 12


0

Variabil! local! 2 Variabil! local! 3

Procesoarele Pentium au introdus dou! instruc#iuni care faciliteaz! alocarea "i eliberarea cadrelor de stiv!. Instruc#iunea ENTER se utilizeaz! pentru alocarea cadrului de stiv! la intrarea n func#ie. Formatul este enter octe!i,nivel unde octe!i specific! num!rul de octe#i dorit pentru stocarea variabilelor locale, iar nivel precizeaz! nivelul de imbricare al func#iei. Dac! specific!m un nivel diferit de zero, instruc#iunea copiaz! n noul cadru de stiv! nivel indicatori de cadru, plecnd de la nceputul cadrului de stiv! precedent. Asfel, instruc#iunea enter <octe!i>, 0 este echivalent! cu secven#a de instruc#iuni push ebp mov ebp,esp

sub esp, <octe!i> Instruc!iunea LEAVE elibereaz" cadrul de stiv" alocat cu instruc!iunea ENTER. Nu prime#te niciun operand. Instruc!iunea LEAVE se traduce prin mov esp,ebp pop ebp Instruc!iunea LEAVE trebuie s" apar" ntotdeauna naintea lui instruc!iunii RET. Eliberarea stivei Am v"zut c" programul principal plaseaz" parametrii de intrare ai func!iei n stiv" nainte de apelul acesteia. Cnd se iese din func!ie, ace#ti parametrii sunt tot n stiv", deoarece func!ia i-a accesat prin adresarea indirect", nu prin instruc!iunea POP. Stiv"

Parametru 3 func!ie Paramentru 2 func!ie Parametru 1 func!ie


31 0

ESP

POP extrage din stiv!, elementul extras cu POP nu mai r!mne n stiv!. Adresarea bazat! l copiaz!, elementul r!mne n stiv!. Totu#i, dac" programul principal folose#te stiva #i n alte scopuri este de preferat ca acesta s" reg"seasc" stiva exact n stadiul n care se afla nainte de apelul func!iei (eliberat" de parametrii de intrare ai unei func!ii care s-a sfr#it). Procesul de eliberare a stivei de parametrii nedori!i poate fi realizat de c"tre: func!ia apelat"; programul apelant (programul principal). Dac" func!iile primesc un num"r fix de parametri, se prefer" prima metod".

n acest caz, codul de ndep!rtare a parametrilor este scris o singur! dat!, n corpul func"iei, chiar dac! func"ia este apelat! de mai multe ori. Ave"i n vedere c! nu pute"i folosi o metod! de genul functie: <corpul_func!iei> leave add esp,12 ret deoarece la execu"ia lui RET, ESP trebuie s! indice c!tre adresa de revenire n programul principal. Solu"ia este reprezentat! de operandul op"ional care poate fi specificat imediat dup! RET. ret operand care rezult! n urm!toarea secven"! de instruc"iuni: EIP # SS:ESP ESP # ESP + 4 + operand Operandul trebuie s! fie un imediat de 16 bi"i. Din moment ce scopul acestei valori op"ionale este s! descarce parametrii introdu$i n stiv!, operandul are ntotdeauna o valoare pozitiv!. Totu$i, dac! o func"ie prime$te un num!r variabil de parametri, trebuie s! folosim a doua metod!. Aceasta este $i metoda utilizat! de compilatoarele C. Din programul principal, parametrii de intrare pot fi extra$i cu instruc"iunea POP, dar cel mai indicat este s! reini"ializ!m registrul ESP cu adresa anterioar! apelului func"iei. Pentru aceasta se adun! la ESP m!rimea parametrilor de intrare introdu$i n stiv!. De exemplu, dac! introducem n stiv!, ca parametri de intrare pentru o func"ie, trei ntregi a cte 4 octe"i fiecare, pentru ndep!rtarea acestora din stiv!, la sfr$itul textului func"iei din programul principal, imediat dup! instruc"iunea de apel, trebuie s! adun!m valoarea din ESP cu 12.
Tabelul 9.1 Exemple de eliberare a stivei din interiorul programului principal

push eax push ebx push ecx call functie add esp,12

push eax push ebx call functie add esp,8

push eax call functie add esp,4

9.6. Mecanisme de transfer al parametrilor


Partea cea mai important! din procesul de apelare a func"iilor este reprezentat! de transferul parametrilor la apel. Exist! dou! mecanisme de transfer al parametrilor: transfer prin valoare (call-by-value) transfer prin referin"! (call-by-reference).

9.6.1. Transfer prin valoare


Mecanismul de transfer al parametrilor prin valoare furnizeaz! func"iei apelate numai valoarea curent! a parametrului de care are nevoie. Din aceast! cauz!, programatorul trebuie s! aloce dou! loca"ii de memorie: una accesibil! programului definit! n segmentul de date - pe care func"ia nu o poate modifica, #i una accesibil! func"iei definit! pe un nivel de stiv! pe care func"ia o poate modifica. n acest caz, spunem c! transmitem acel parametru prin valoare, #i valoarea nu poate fi modificat! de func"ia apelat!. Urm!torul program exemplific! transferul parametrilor prin valoare. Func"ia nmul"e#te dou! valori primite prin stiv! #i tot ea elibereaz! stiva la final. Rezultatul este returnat conform standardului de apel C, n perechea de registre EDX:EAX (fiind valoare de 64 de bi"i). ; ;callByValue.asm ; section .data val1 dd 150 val2 dd 10 section .text global _start _start: nop push dword [val1] push dword [val2] call multiply mov eax,1 mov ebx,0 int 80h multiply: enter 0,0 mov eax,[ebp+8]

mul dword [ebp+12] leave ret 8 Rul!m programul prin intermediul depanatorului. Imediat dup! comanda de rulare afi"!m con#inutul registrului ESP (vrful stivei). Apoi introducem valorile n stiv!. (gdb) i r esp esp 0xffffd7d0 0xffffd7d0 (gdb) n 13 push dword [val2] (gdb) 14 call multiply (gdb) i r esp esp 0xffffd7c8 0xffffd7c8 Dac! sc!de#i adresa curent! a ESP din adresa ini#ial! rezult! c! au fost introdu"i n stiv! 8 octe#i. Nu intra#i nc! n func#ie. Studia#i con#inutul cadrului de stiv! curent cu ajutorul comenzilor backtrace "i info frame. Acesta este cadrul de stiv! al programului principal. Intra#i n func#ie cu instruc#iunea nexti. (gdb) ni 0x080480a2 in multiply () at sum.asm:19 19 enter 0,0 Instruc#iunea ENTER a fost deja executat!. Pute#i afi"a cadrele de stiv! prezente "i detalia cadrul de stiv! al func#iei. (gdb) bt #0 0x080480a2 in multiply () at sum.asm:19 #1 0x08048092 in _start () at sum.asm:14 (gdb) info frame Stack level 0, frame at 0xffffd7c8: eip = 0x80480a2 in multiply (sum.asm:19); saved eip 0x8048092 called by frame at 0xffffd7cc source language unknown. Arglist at 0xffffd7c0, args: Locals at 0xffffd7c0, Previous frame's sp is 0xffffd7c8 Saved registers: eip at 0xffffd7c4

(gdb) i r ebp ebp 0xffffd7c0 (gdb) i r esp esp 0xffffd7c0

0xffffd7c0 0xffffd7c0

nainte de intrarea n func!ie, adresa registrului ESP era 0xffffd7c8. Dup" parcurgerea prologului, adresa din registrul ESP este 0xffffd7c0. O diferen!" de 8 octe!i 4 octe!i ocupa!i cu adresa de revenire n program (introdus" automat de instruc!iunea CALL) #i 4 octe!i ocupa!i de valoarea registrului EBP, salvat n stiv" n cadrul prologului (PUSH EBP). Registrul EBP are aceea#i valoare cu registrul ESP deoarece a fost executat" instruc!iunea MOV EBP,ESP. A#adar, indicatorul de cadru EBP are valoarea 0xffffd7c0. Din acest motiv, n descrierea cadrului de stiv" se specific" faptul c" lista argumentelor #i a variabilelor locale ncepe de la aceast" adres". (gdb) x /4wx $ebp 0xffffd7c0: 0x00000000 0x08048092 0x0000000a 0x00000096

Am afi#at patru cuvinte de 32 de bi!i ncepnd de la adresa EBP. Prima valoare din stnga, 0x00000000, reprezint" adresa anterioar" a registrului EBP, a doua, 0x08048092, reprezint" adresa de revenire n programul apelant (adresa care va fi nc"rcat" n registrul EIP de instruc!iunea RET), a treia #i a patra valoare sunt datele de intrare n func!ie - 10, respectiv 150, n hexazecimal. Urm"toarele dou" instruc!iuni efectueaz" nmul!irea. Prima copiaz" n registrul EAX un parametru din stiv" prin adresare bazat". Rezultatul r"mne n combina!ia de registre EDX:EAX. Deoarece valoarea este mic", registrul EDX r"mne 0. (gdb) si 0x080480a5 20 (gdb) i r eax eax 0xa 10 (gdb) si 0x080480a8 21 (gdb) i r eax eax 0x5dc 1500 (gdb) i r edx edx 0x0 0 mov eax,[ebp+8]

mul dword [ebp+12]

La ie#irea din func!ie, instruc!iunea RET repozi!ioneaz" indicatorul de stiv" la adresa acestuia dinaintea introducerii parametrilor.

(gdb) i r esp esp 0xffffd7d0

0xffffd7d0

9.6.2. Transfer prin referin!"


Mecanismul de transfer al parametrilor prin referin!" furnizeaz" func!iei apelate adresa parametrului de care are nevoie. n acest caz se folose#te o singur" loca!ie de memorie, dar zona de memorie respectiv" trebuie s" fie vizibil" func!iei apelate. Func!ia poate modifica con!inutul parametrului #i aceste modific"ri sunt vizibile din programul apelant prin manipulearea direct" a valorii sale. n acest caz, spunem c" transmitem acel parametru prin adres". Urm"torul program exemplific" transferul parametrilor prin adres". Deoarece este echivalentul programului anterior, n continuare ne m"rginim s" specific"m numai diferen!ele. ; ;callByRef.asm ; section .data val1 dd 150 val2 dd 10 section .text global _start _start: nop push dword val1 push dword val2 call multiply mov eax,1 mov ebx,0 int 80h multiply: enter 0,0 push ebx mov ebx,[ebp+8] mov eax,[ebx] mov ebx,[ebp+12] mul dword [ebx] pop ebx leave ret 8

Adresa ini!ial" a indicatorului de stiv" este tot 0xffffd7d0. (gdb) i r esp esp 0xffffd7d0 0xffffd7d0 (gdb) n 9 push dword val2 (gdb) 10 call multiply (gdb) x /2wx $esp 0xffffd7c8: 0x080490b4 0x080490b0 Observa!i c" n stiv" sunt introduse adresele parametrilor, nu valorile acestora. Valorile sunt g"site prin intermediul acestor adrese. (gdb) x /1wd 0x080490b4 0x80490b4 <val2>: 10 (gdb) x /1wd 0x080490b0 0x80490b0 <val1>: 150 Dup" executarea instruc!iunii ENTER, indicatorul de cadru poate reprezenta adres" de baz" pentru (gdb) x /4wx $ebp 0xffffd7c0: 0x00000000 0x08048090 0x080490b4 0x080490b0

vechea valoare a registrului EBP, adresa de revenire n program, #i adresele parametrilor (nu valorile parametrilor ca n programul precedent). (gdb) si 0x080480a4 17 mov ebx,[ebp+8] (gdb) i r ebx ebx 0x80490b4 134516916 (gdb) i r eax eax 0x0 0 (gdb) si 18 mov eax,[ebx] (gdb) i r eax eax 0xa 10 Valoarea celui de al doilea parametru este nc"rcat" n registrul EAX prin adresare

indirect! cu registrul EBX. Cel!lalt parametru se acceseaz! tot prin adresare indirect!. De aici pn! la final, comportamentul programului este cunoscut.

9.7. Conservarea st!rii registrelor


Totu"i, n func#ie se petrece un lucru foarte important. nainte de utilizarea registrului EBX n adresarea indirect!, instruc#iunea push ebx salveaz! con#inutul acestuia n stiv!. Exist! posibilitatea ca registrul EBX s! fie folosit de programul apelant "i func#ia se asigur! c! opera#iile sale nu modific! con#inutul acestuia. Conservarea st!rii registrelor de-a lungul execu#iei unei func#ii este un concept foarte important. Func#ia apelat! trebuie s! salveze toate registrele pe care le folose"te "i s! le refac! nainte de a reda controlul programului apelant. Acesta este un principiu important al program!rii modulare. Pentru a evita selec#ia individual! a registrelor ce trebuie salvate, am putea salva toate registrele la nceputul func#iei apelate "i le-am putea restaura la sfr"it. De exemplu, am putea utiliza instruc#iunile PUSHAD "i POPAD. Instruc#iunea PUSHAD este util! n anumite situa#ii, dar nu n toate. n primul rnd, unele registre salvate de PUSHAD sunt folosite la returnarea valorilor de ie"ire (EAX pentru rezultate ntregi de 32 de bi#i, sau EDX - n cazul unor rezultate ntregi de 64 de bi#i). Instruc#iunea POPAD distruge rezultatele returnate de func#ia apelat!. n al doilea rnd, PUSHAD consum! cinci cicluri de tact, n timp ce o singur! instruc#iune PUSH consum! numai unul. Instruc#iunea PUSHAD devine eficient! numai dac! sunt salvate mai mult de cinci registre. n plus, nu uita#i c! o instruc#iune PUSHAD modific! semnificativ deplasamentul la care pot fi g!si#i n stiv! parametrii de intrare ai func#iilor apelate.

9.8. Scrierea func"iilor n fi#iere separate


Scrierea func#iilor conform standardului C (folosirea stivei) mai prezint! un avantaj: func#ia "i este suficient! sie"i, n sensul c! nu este nevoie s! definim loca#ii globale de memorie pentru accesul la date (variabile globale). Altfel spus, nu avem nevoie de directive section .data sau .bss n func#ii (vezi

variabile locale). Acest fapt aduce la rndul s!u "i alt beneficiu: nu este imperios necesar ca func#ia s! se afle n acela"i fi"ier cu programul principal. n continuare ar!t!m cum putem crea fi"iere separate pentru func#ii, cum trebuie s! le asambl!m "i cum trebuie s! le leg!m de fi"ierul programului principal. Structura func#iei scrise ntr-un fi"ier separat este similar! structurii unui program obi"nuit, numai c!, n loc de directiva _start, trebuie s! declar!m ca etichet! global! numele func#iei. section .text global _functie _functie: De asemenea, n fi"ierul programului principal trebuie s! folosim directiva extern <nume_func!ie>. Din perspectiva procesului de asamblare, fiecare fi$ier .asm separat este considerat un modul, indiferent dac! con%ine o etichet! _start (caz n care este considerat program principal) sau dac! reprezint! o simpl! func%ie. Fiecare modul con%ine cod $i, posibil, cteva defini%ii de date. Directiva extern indic! asamblorului c! func%ia respectiv! se afl! ntr-un alt modul. Directiva global aten%ioneaz! asamblorul c! func%ia respectiv! poate fi adresat! din exteriorul modului. Conven%ia extern global se aplic! $i declara%iilor de date. Putem declara orice etichet! de date ca global $i ea poate fi utilizat! de orice modul n care numele etichetei respective apare declarat ca extern. Mai mult, fi$ierele de func%ii pot partaja ntre ele date $i func%ii, n orice combina%ie, att timp ct toate declara%iile globale $i externe sunt realizate corect. Un modul care con%ine func%ii sau date declarate global se spune c! export! acele elemente. Similar, un modul care utilizeaz! func%ii sau date externe se spune c! import! acele elemente. Modulele asamblate separat au structur! similar! cu programele normale, cu o excep%ie important!: modulele externe nu con%in un program principal, deci nu au adres! de nceput. Acest lucru nseamn! c! nu exist! o etichet! _start care s! indice editorului de leg!turi punctul de la care trebuie s! nceap! execu%ia programului. Modulele de func%ii nu sunt destinate s! ruleze singure, astfel nct prezenta etichetei _start este inutil!. Editorul de leg!turi va genera o eroare ori de cte ori ntlne$te mai mult de o etichet! _start n modulele pe care le proceseaz! la un moment dat. Dac! toate declara%iile sunt corecte, modulele pot comunica unul cu altul prin intermediul apelurilor de func%ie, $i orice func%ie poate adresa orice defini%ie de date din oricare din fi$ierele legate de editorul de leg!turi. Scriem codul func#iei care calculeaz! complementul fa#! de doi ntr-un fi"ier separat de cel al programului principal. Vor rezulta dou! fi"iere: functie.asm, pentru corpul func#iei, "i main.asm, pentru programul principal.

; ;functie.asm ; section .bss mem resd 1 section .text global _functie _functie: push ebp mov ebp,esp sub esp,8 mov eax,[ebp+8] neg eax leave ret

; ;main.asm ; section .bss rez1 resd 1 rez2 resd 1 section .text extern _functie global _start _start: nop push 5 call _functie add esp,4 mov [rez1],eax push 10 call _functie add esp,4 mov [rez2],eax mov eax,1 mov ebx,0 int 080h

Nu exist! o limit! cu privire la num!rul de directive extern prezent ntrun modul. Un modul (program sau func"ie) poate primi oricte directive extern, corespunz!tor num!rului de func"ii externe apelate. Pentru un aspect compact, func"iile pot fi declarate #i pe o singur! linie, separate prin virgul!. extern f1, f2, f3 Totu$i, declara"iile care trec de limita liniei nu sunt recunoscute. Directivele globale trebuie declarate naintea definirii lor n codul surs!. n practic!, acest lucru nseamn! c! directivele global apar n codul surs! la nceputul sec"iunii TEXT, naintea oric!rei func"ii. Similar, toate elementele de date globale sunt declarate ca atare n segmentul DATA naintea definirii lor. Elementele care nu sunt declarate global sunt private, n sensul c! nu pot fi accesate dect din interiorul modulului care le con"ine. Asambl!m cu urm!toarele comenzi:

yasm -f elf -g stabs yasm -f elf -g stabs ld -o program main.o gdb program

main.asm functie.asm functie.o melf_i386

Ordinea modulele n linia editorului de leg!turi este foarte important!. Vom discuta acest fapt ntr-un capitol viitor. Reasambl!m programul folosind modulul functie2.asm. Vedem c! func"ia folose#te stiva, dar totul func"ioneaz! corect din moment ce am rezervat un spa"iu de 8 octe"i cu instruc"iunea SUB ESP,8. ; ;func!ie2.asm ; section .bss mem resd 1 ;variabila mem se g!se#te n memorie la adresa imediat urm!toare variabilelor ;rez1 #i rez2 definite n fi#ierul programului principal section .text global _functie _functie: push ebp mov ebp,esp sub esp,8 mov eax,[ebp+8] mov [mem],eax add eax,1 push eax neg dword [mem] mov eax,[mem] pop eax leave ret Presupunem c! func"ia folose#te variabile locale, adresate cu [ebp-4], [ebp-8]: ; ;functie3.asm ; section .bss mem resd 1

section .text global _functie _functie: push ebp mov ebp,esp sub esp,8 mov eax,[ebp+8] mov [mem],eax mov eax,0ffffffffh mov ebx,0aaaaaaaah mov ecx,022222222h push eax push ebx mov [ebp-4],ecx mov dword [ebp-4],033333333h neg dword [mem] mov eax,[mem] pop eax leave ret Rula!i programul pas cu pas "i observa!i cum se modific# con!inutul stivei. Poate a!i observat c# n aceste ultime func!ii nu am folosit instruc!iunea ENTER, ci am preferat secven!a clasic# de intrare n func!ie. Majoritatea compilatoarelor au aceea"i preferin!#. Acest lucru se explic# prin faptul c# instruc!iunea ENTER are probleme de performan!#. Procesoarele moderne decodeaz# ENTER n 10 pn# la 20 de microopera!ii, n timp ce secven!a de trei instruc!iuni este decodat# n 4 pn# la 6, n func!ie de arhitectur#. Diferen!a de vitez# este destul de mare. n plus, secven!a de trei instruc!iuni poate fi optimizat# de asamblor.

9.9. Exerci!ii
9.1. Scrie!i urm#toarea func!ie C: /* f.c */ int f(void) { return 0;

} Afi!a"i echivalentul ei n asamblare cu comanda: gcc -S f.c -o - -m32 -masm=intel Compara"i rezultatul cu cel al urm#toarelor dou# func"ii: int g(void) { } 9.2. Scrie"i urm#torul program C: #include <stdio.h> int main(){ int x = 1; double y,z; y = 1.23; z = (double)x +y; return 0; } Folosi"i comanda prezentat# la exerci"iul anterior pentru afi!area echivalentului s#u n limbaj de asamblare. Identifica"i secven"a de instruc"iuni n limbaj de asamblare care realizeaz# adunarea z = (double)x +y. Descrie"i opera"iile efectuate. 9.3. Scrie"i n fi!iere separate urm#toarele dou# programe !i studia"i echivalentul acestora n limbaj de asamblare. #include <stdio.h> void swap( int num1, int num2 ) ; int a = 256; int b = 128; void main( ) { swap( a, b ) ; #include <stdio.h> void swap( int *num1, int *num2 ) ; int a = 256; int b = 128; void main( ) { swap( &a, &b ) ; int h(void) { return 56; } -O0

} void swap( int num1 , int num2 ) { int temp ; temp = num2 ; num2 = num1 ; num1 = temp ; } Genera!i executabilele cu comanda:

} void swap( int *num1 , int *num2 ) { int temp ; temp = *num2 ; *num2 = *num1 ; *num1 = temp ; }

gcc -g f.c -o - -m32 -masm=intel

-O0 -o f

"i depana!ile cu GDB. Care sunt valorile variabilelor a "i b la sfr"itul celor dou# programe? Descrie!i opera!iile care au loc n fiecare caz n parte.

10. INTERFA!A CU SISTEMUL DE OPERARE

Odat! lansat n execu"ie, niciun program ntlnit n capitolele precedente nu interac"ioneaz! n vreun fel cu utilizatorul. Programele interactive, care accept! date de la tastatur! sau afi#eaz! informa"ii la monitor, folosesc servicii puse la dispozi"ie de sistemul de operare. $tim deja c! sistemul de operare gestioneaz! #i controleaz! de o maniera strict! toate elementele hardware ale ma#inii de calcul: discurile, imprimanta, tastatura, diferite porturi (USB, Ethernet, etc..), monitorul. Accesul unui program la aceste componente se face numai prin intermediul func"iilor puse la dispozi"ie de sistemul de operare. Modul prin care atragem aten"ia sistemului de operare c! avem nevoie de suportul s!u n realizarea unei opera"ii se realizeaz! prin apeluri de sistem (o categorie special! de ntreruperi software). n acest capitol studiem toate aspectele legate de modul n care sistemul de operare ne permite s! interac"ion!m cu sistemul de calcul.

10.1. ntreruperi software


No!iunea de ntrerupere o lu"m ca atare, n sensul de a suspenda temporar cursul, desf"#urarea unei ac!iuni, a unei activit"!i. n cazul de fa!", cel care efectueaz" activitatea (de ex., rularea unui program) este procesorul, iar ntreruperea poate fi declan#at" de o component" hardware care are nevoie de aten!ia sa. n acest caz, procesorul suspend" procesul curent #i ruleaz" secven!a de cod (rutina) specific" acelei componente. De exemplu, dac" semnalul de ntrerupere provine de la controlerul portului serial, procesorul permite acestuia s" transfere un caracter. Deoarece ntreruperea a fost ini!iat" de o component" hardware, se nume#te ntrerupere hardware, iar secven!a de instruc!iuni ma#in" centrat" pe o anumit" sarcin" poart" numele de rutin" de tratare a ntreruperii (ISR Interrupt Service Routine). Fiecare secven!" de acest gen, specific" fiec"rui sistem de operare, realizeaz" ceva util cite#te un fi#ier, scrie un fi#ier, extrage timpul curent, cite#te un port de re!ea, #.a.m.d.. Sistemul de operare folose#te secven!ele de ntrerupere n scop propriu, dar le poate pune #i la dispozi!ia programatorului. ns" programatorul nu le poate apela direct, #i asta din dou" motive ntemeiate. n primul rnd, accesul nerestric!ionat al programelor din spa!iul utilizator la componentele intime ale sistemului de operare

este periculos. Persoane r!u inten"ionate le-ar putea modifica sau folosi n scopuri improprii. n al doilea rnd, aceste secven"e se modific! odat! cu mbun!t!"irea #i evolu"ia sistemului de operare. Evolu"ia presupune ad!ugarea, modificarea sau #tergerea unor instruc"iuni ma#in! din motive de securitate sau de optimizare. Din aceste motive, apelul func"iilor de sistem se face prin ceea ce n limbaj de specialitate se nume#te poart! de apel (call gate) #i anume, o poart! de acces aflat! ntre spa"iul utilizator, acolo unde ruleaz! programele obi#nuite, #i spa"iul kernel, acolo unde #i desf!#oar! activitatea componenta sistemului de operare care gestioneaz! resursele hardware ale sistemului. Poarta de apel este implementat! printr-o ntrerupere software. n sistemele x86, chiar la nceputul memoriei RAM, la adresa 0, se afl! un tabel special format din 256 de intr!ri. Fiecare intrare reprezint! o adres! de memorie de 4 octe"i. Astfel, primii 1024 de octe"i de memorie sunt rezerva"i acestui tabel. Fiecare intrare (adres!) din tabel se nume#te vector de ntrerupere. Din acest motiv, tabelul este denumit tabelul vectorilor de ntrerupere. n func"ie de pozi"ia sa n tabel, fiecare vector are un num!r de identificare cuprins ntre 0 #i 255. La ini"ializarea calculatorului, BIOS-ul #i sistemul de operare20 ncarc! loca"iile din tabel cu adresele rutinelor de ntrerupere specifice lor. O actualizare a sistemului de operare poate modifica att rutinele ct #i adresele prezente n tabelul vectorilor de ntrerupere, n schimb num!rul (indexul) ntreruperii care con"ine respectiva adres! r!mne nemodificat. Cu alte cuvinte, rolul loca"iilor din tabelul vectorilor de ntrerupere este standard, secven"a de ntrerupere #i adresa ei n memorie se poate modifica (de ex., ad!ugarea unor noi instruc"iuni la o rutin! de ntrerupere cre#te dimensiunea acesteia #i trebuie nc!rcat! la alt! adres! de memorie), dar ntotdeauna va fi apelat! de la vectorul cu acela#i num!r. Din aceast! cauz!, nc! de la prima apari"ie a sistemului Linux #i pn! n prezent, num!rul de ntrerupere 80H a indicat ntotdeauna c!tre un dispecer de apel (servicii), un fel de manager al tuturor func"iilor de sistem puse la dispozi"ie de kernelul Linux. Adresa dispecerului difer! de la distribu"ie la distribu"ie sau chiar de la o versiune de Linux la alta, dar indiferent de acest lucru, programele l pot apela prin intermediul loca"iei 80H din tabelul vectorilor de ntrerupere. Din motive de securitate, tabelul vectorilor de ntrerupere apar"ine sistemului de operare #i programatorul nu are acces direct la adresele sale. Totu#i, programatorul dispune de o instruc"iune ce poate interoga respectivul tabel - instruc"iunea INT (INTerrupt). Singura diferen"! real! ntre ntreruperile hardware #i ntreruperile software const! n evenimentul care declan#eaz! saltul procesorului la tabela vectorilor de ntrerupere. n cazul unei ntreruperi hardware, evenimentul declan#ator este un semnal electric aplicat pe un pin al procesorului. Dup! ce recunoa#te semnalul electric, procesorul introduce n stiv! adresa de revenire n program #i execut! rutina de tratare a respectivei ntreruperi. Pentru ntreruperile software, evenimentul declan#ator este
20

De fapt, sistemele de operare folosesc o adres! specific! pentru vectorul de ntreruperi.

intruc!iunea INT. Cnd este executat" instruc!iunea INT 80H, procesorul extrage adresa g"sit" la loca!ia 80H a tabelei vectorilor de ntrerupere #i execut" secven!a de instruc!iuni indicat" de acea adres". n acest mod se efectueaz" #i se controleaz" tranzi!ia din spa!iul utilizator n spa!iul kernel. Procesul este ilustrat n Figura 10.1.
Prima dat!, instruc"iunea INT 80H introduce n stiv! adresa urm!toarei instruc"iuni Stiva Adresa de revenire

Codul programului INT 80h (Urm!toarea instruc"iune) SPA#IUL UTILIZATOR SPA#IUL KERNEL Linux

... apoi sare la adresa stocat! n vectorul 80h

Dispecer de apel

Tabela vectorilor de ntrerupere Vector 80h

Figura 10.1 Apelul vectorului de ntrerupere 80h

Instruc!iunea INT 80H introduce n stiv" adresa urm"toarei instruc!iuni din program (adresa care urmeaz" imediat instruc!iunii INT 80H) #i apoi sare n spa!iul kernel la adresa vectorului 80H. De aici, dispecerul de apel controleaz" accesul la aproximativ 200 de rutine de sistem individuale. Ca s" #tie pe care din ele s" o execute dispecerul caut" n registrul EAX un identificator de apel. nainte de apelul dispecerului (cu INT 80H), programatorul trebuie s" specifice n EAX un identificator de apel. Pe lng" acesta, programatorul trebuie s" specifice #i alte informa!ii, furnizate aproape ntotdeauna tot prin intermediul unor registre. Dup" finalizarea secven!ei de ntrerupere, instruc!iunea IRET folose#te adresa salvat"

anterior n stiv! pentru a reveni n program. Acest proces seam!n! cu cel prin care func"iile studiate n capitolul precedent folosesc perechea de instruc"iuni CALL #i RET. CALL introducea n stiv! adresa urm!toarei instruc"iuni #i s!rea la func"ie, instruc"iunea RET de la sfr#itul func"iei extr!gea adresa din stiv! #i permitea continuarea execu"iei programului de la prima instruc"iune sub CALL. Este timpul s! n"elegem rolul ultimelor trei instruc"iuni din toate programele studiate n aceast! carte pn! n prezent. ; ;ntrerupe execu!ia programului "i red# controlul sistemului de operare ; mov eax,1 ;specific! func"ia de sistem Exit mov ebx,0 ;cod de ntoarcere zero (SUCCESS) int 80h ;efectueaz! apel de sistem n vederea ntreruperii execu"iei Programatorul, pentru a ntrerupe execu"ia programului, trebuie s! plaseze identificatorul de apel sys_exit, 1, n registrul EAX #i un cod de ntoarcere n EBX, apoi specific! instruc"iunea INT 80H. Codul de ntoarcere este o valoare numeric! aflat! la discre"ia sa. Tehnic, nu sunt restric"ii (trebuie numai s! ncap! ntr-un registru de 32 de bi"i) dar, prin conven"ie, o valoare de ntoarcere 0 nseamn! c! opera"ia s-a finalizat cu succes (procesul a fost ntrerupt normal). O valoare diferit! de 0 indic! o eroare (ntmpinat! de kernel n procesul de ntrerupere): fi#ierul nu poate fi g!sit, discul este la capacitate maxim!, etc.. Fiecare program trebuie ntrerupt n acest mod. Chiar dac! un program nu implementeaz! func"ia sys_exit, pn! la urm! va fi ntrerupt, dar sistemul de operare va afi#a o eroare tip Segmentation fault #i nu putem #tii cum a fost finalizat procesul de ntrerupere.

10.2. Formatul apelurilor de sistem


Utilizarea func"iilor de sistem n programele scrise n limbaj de asamblare poate fi complicat!. Spre deosebire de func"iile C, unde valorile de intrare erau plasate n stiv!, apelurile de sistem necesit! ca valorile de intrare s! se afle n registre. Locul acestora n registre este prestabilit. Plasarea unei valori de intrare ntr-un registru gre#it produce rezultate nea#teptate sau poate duce la ntreruperea prematur! a programului. Deja a"i aflat c! registrul EAX trebuie s! con"in! identificatorul de apel. Cum registrele EIP, EBP #i ESP nu pot memora valori de intrare, deoarece ar afecta operarea normal! a programului, r!mn disponibile numai cinci registre. A#a

cum am men!ionat, ordinea n care valorile de intrare sunt plasate n registre este foarte important". Dispecerul de apel a#teapt" datele de intrare n ordinea urm"toare: EBX, primul parametru; ECX, al doilea parametru; EDX, al treilea parametru; ESI, al patrulea parametru; EDI, al cincilea parametru. Func!iile de sistem care necesit" mai mult de #ase parametrii de intrare folosesc o metod" diferit" de preluare a acestora: dispecerul adreseaz" #i cite#te parametrii prin intermediul registrului EBX. n acest caz, registrul EBX con!ine adresa unei loca!ii de memorie de la care parametrii sunt stoca!i n ordine secven!ial". O alt" problem" const" n stabilirea corect" a num"rului de parametrii #i a registrului corespunz"tor unui anumit parametru. Semnifica!ia parametrilor, la fel ca #i num"rul acestora, difer" de la func!ie la func!ie. Asemenea oric"rei comenzi Linux, odat" ce ai aflat numele func!iei de sistem po!i g"si defini!ia acesteia n paginile manual. Sec!iunea 2 a paginilor de manual con!ine defini!iile tuturor func!iilor de sistem disponibile. Accesul la defini!ia unei func!ii de sistem se face cu ajutorul comenzii man urmat" de num"rul 2: man 2 exit Num"rul 2 specific" sec!iunea paginilor de manual. Deoarece unele func!ii de sistem au acela#i nume cu unele comenzi listate n sec!iunea 1, implicit" pentru paginile de manual, nu uita!i s" include!i 2 explicit. Altfel, n loc s" ob!ine!i defini!ia func!iei de sistem, vor fi afi#ate op!iuni de comand". Pagina de manual con!ine patru p"r!i: Nume: arat" numele func!iei de sistem; Rezumat: arat" modul n care putem utiliza func!ia de sistem respectiv"; Descriere: o scurt" descriere a func!iei de sistem; Valoarea returnat": valoarea returnat" la sfr#itul func!iei de sistem. Rezumatul este scris pentru programatori de C, dar pot beneficia de aceste informa!ii #i cei care programeaz" n limbaj de asamblare. Rezumatul func!iei de sistem EXIT arat" c" aceasta prime#te un singur parametru de intrare (valoarea ntre paranteze) #i nu returneaz" nicio valoare. Func!ia de sistem WRITE este utilizat" la scrierea datelor ntr-un descriptor de fi#ier. Dac" afi#"m pagina sa de manual, rezumatul se prezint" astfel:

SYNOPSIS #include <unistd.h> ssize_t write(int fd, const void *buf, size_t count); Parametrii sunt men!iona!i de la stnga la dreapta, a"a cum apar n rezumat. Primul parametru (fd) este un ntreg care reprezint# descriptorul de fi"ier pentru dispozitivul de ie"ire, un identificator de fi"ier. Al doilea parametru (buf) este adresa (pointer) de la care ncepe "irul ce trebuie scris la dispozitiv. Al treilea parametru (count) reprezint# dimensiunea n octe!i a "irului care trebuie scris. Utiliznd aceast# conven!ie, valorile de intrare sunt atribuite urm#toarelor registre: EBX, descriptorul de fi"ier; ECX, adresa de memorie a "irului (pointer-ul); EDX, num#rul de octe!i care trebuie scris din memorie n fi"ier. Un exemplu de utilizare a acestei func!ii de sistem este dat n programul hello.asm. ; ;afi!eaz" la monitor mesajul Hello, World! ; section .data mesaj db Hello, World, 0xa ;0xA = ASCII newline lungime equ $ - mesaj section .text global _start _start: nop ;pentru a putea seta punctul de ntrerupere n depanator mov eax,4 ;EAX = identificatorul func!iei de sistem write mov ebx,1 ;EBX = descriptorul de fi"ier 1 (STDOUT) mov ecx,mesaj ;ECX = adresa de nceput a "irului care va fi trimis la STDOUT mov edx,lungime ;EDX = num#rul de octe!i trimi"i la STDOUT int 80h ;specific# kernelului s# execute func!ia indicat# n EAX ;WRITE returneaz# n EAX num#rul de caractere scris la monitor mov eax,1 ;EAX = identificatorul func!iei de sistem EXIT mov ebx,0 ;EBX = codul de ntoarcere din SO n caz de succes int 80h ;specific# kernelului s# execute func!ia indicat# n EAX Probabil v# este cunoscut cam tot ce se ntmpl# n programul hello.asm. Identificatorul de apel pentru func!ia de sistem WRITE (4) este plasat n registrul

EAX. Valorile de intrare necesare sunt plasate n registrele predefinite. ns! pentru a n"elege ce reprezint! valoarea plasat! n registrul EBX trebuie s! vorbim despre fi#iere standard n Linux. Fi!iere standard Principiul fundamental de proiectare a sistemelor Unix #i nrudite este everything is a file. Sintagma orice este un fi#ier trebuie n"eleas! ca: orice este reprezentat ca fi#ier. Un fi#ier poate fi o colec"ie de date pe disc dar, ntr-un sens mai general, un fi#ier este punctul final al unui traseu parcus de date. Cnd scrii ntr-un fi#ier, trimi"i date de-a lungul unui traseu ntr-un punct final. Cnd cite#ti un fi#ier, preiei date dintr-un punct final. n cazul unui transfer ntre fi#iere, calea parcurs! de date se poate afla n totalitate n interiorul unui calculator sau poate traversa o re"ea de calculatoare, datele pot suferi modific!ri de-a lungul traseului sau nu, #.a.m.d.. Ceea ce trebuie s! n"elegem este c!, n sistemele Unix, totul este reprezentat ca fi#ier #i toate fi#ierele, indiferent de natura lor, sunt tratate de c!tre mecanismele interne ale sistemului de operare mai mult sau mai pu"in identic. n acest sens, fi#ierele nu sunt reprezentate numai de colec"iile de date stocate pe disc, ci de toate componentele hardware care pot juca rol de surs! sau destina"ie pentru date. Tastatura este un fi#ier: un punct final care genereaz! date #i le trimite undeva. Monitorul este un fi#ier: un punct final care prime#te date de undeva #i le afi#eaz!. Fi#ierele Unix nu sunt neap!rat fi#iere text. Fi#ierele binare au parte de acela#i tratament. Tabelul 2.5 prezint! cele trei fi#iere standard definite de sistemele Unix sau nrudite, cum este Linux. Aceste fi#iere sunt deschise #i disponibile ntotdeauna n timpul rul!rii programelor.
Tabelul 10.1 Cele trei fi!iere standard n Unix

Fi!ier Standard Input Standard Output Standard Error

Identificator C STDIN STDOUT STDERR

Descriptor de fi!ier 0 1 2

Hardware Tastatur! Monitor Monitor

Pentru sistemul de operare, un fi#ier este reprezentat printr-un descriptor de fi!ier. Descriptorul de fi#ier este un num!r ntreg folosit ca identificator pentru acel fi#ier. Primele trei numere apar"in celor trei fi#iere standard. Dac! un program deschide un fi#ier existent sau creaz! unul nou, sistemul Linux va returna un descriptor de fi#ier unic. Programul va gestiona fi#ierul folosind descriptorul de fi#ier respectiv. Tabelul 2.5 prezint! #i numele de identificare specifice limbajului de programare C. De obicei, cnd cineva spune STDOUT n"elegem c! se refer! la descriptorul de fi#ier 1, adic! la monitor. Pe de alt! parte, STDERR semnific! destina"ia la care programele trimit mesajele de eroare. Descriptorii de fi#ier 1 #i 2 au aceea#i destina"ie, monitorul, #i mesajele standard #i cele de eroare vor fi afi#ate

n acela!i mod. Totu!i, n sistemele Unix putem separa ie!irile standard ale programului de mesajele de eroare (sau alte mesaje specifice modului n care se comport" programul) printr-un mecanism numit redirec#ionare I/O. Programul hello.asm folose!te descriptorul de fi!ier STDOUT ca s" afi!eze un text pe ecranul terminalului. Urm"toarea valoare de intrare specific" adresa de la care ncepe !irul care trebuie afi!at. Observa#i c" specificarea loca#iei de memorie se face prin adresare direct". Aceasta presupune ca n registrul ECX s" se afle adresa explicit" a loca#iei de memorie de la care ncepe textul mesajului. Ultimul parametru de intrare specific" lungimea !irului care trebuie afi!at. n loc s" specifice n clar num"rul de octe#i ai mesajului, programul determin" lungimea acestuia printr-un mic artificiu prezentat deja n capitolul dedicat structurilor de date. A!a cum reiese din pagina de manual a func#iei de sistem WRITE, valoarea returnat" reprezint" num"rul de octe#i scri!i sau o valoare negativ" (-1) - dac" apelul s-a ncheiat cu o eroare. Valoarea returnat" este plasat" n registrul EAX. Programatorul trebuie s" verifice acest" valoare, n special de posibilitatea apari#iei vreunei erori. ntotdeauna trebuie s" #inem cont de tipul de date al valorii returnate. Unele func#ii de sistem folosesc tipuri de date exotice. Acesta este !i cazul nostru: func#ia WRITE returneaz" o valoare de tip ssize_t. Tipul de date ssize_t nu este unul din cele ntlnite n limbajul de asamblare. De fapt, nu #ine de limbajul de programare, ci este un sinonim pentru o valoare de tip ntreg folosit de sistemul de operare Linux. Reprezint" num"rul de caractere scris la un descriptor de fi!ier sau valoarea -1 dac" apare vreo eroare. Urm"torul program demonstreaz" modul n care putem gestiona valorile returnate de o func#ie de sistem. ; ;CallReturn.asm ; section .bss pid resb 4 uid resb 4 gid resb 4 section .text global _start _start: nop mov eax,20 int 80h mov [pid],eax mov eax,24 int 80h

mov [uid],eax mov eax,47 int 80h mov [gid],eax end: mov eax,1 mov ebx,0 int 80h Programul CallReturn.asm folose!te trei apeluri de sistem separate: Indicatorul de apel Func!ia de sistem 20 24 47 getpid getuid getgid Descriere Specific" identificatorul programului care ruleaz" Specific" identificatorul persoanei care ruleaz" programul Specific" identificatorul de grup al persoanei care ruleaz" programul

n urma plas"rii identificatorilor de apel n registrul EAX !i al execu#iei instruc#iunii INT pentru fiecare apel n parte, valoarea returnat" n registrul EAX este introdus" ntr-o loca#ie de memorie cu nume sugestiv. Eticheta end ofer" un punct de ntrerupere u!or de accesat, astfel nct s" putem afi!a valorile de ie!ire grupat. (gdb) b *end Breakpoint 1 at 0x80480a5: file return.asm, line 19. (gdb) r Starting program: /home/stefan/return Breakpoint 1, end () at return.asm:19 (gdb) x /d &pid 0x80490b4 <pid>: 3975 (gdb) x /d &uid 0x80490b8 <uid>: 1000 (gdb) x /d &gid 0x80490bc <gid>: 1000 Identificatorul de proces este unic programului care ruleaz". Ceilal#i doi identificatori se pot afla prin comanda Linux id.

id uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu) Urm!torul program permite introducerea datelor de la tastatur! prin func"ia de sistem READ. ; ;readInput.asm ; section .data lung_nume dd 0 ;;bufferul este zona de memorie n care vom stoca numele introdus, 40 de caractere ASCII 0x2d buffer db "--------------------------------------" msg_cerere db Introduce!i numele: ,0xa msg_cerere_lung equ $ - msg_cerere msg_salut db "Salut, " msg_salut_lung equ $ - msg_salut_lung ;;dac! dori"i s! folosi"i pentru buffer memorie neini"ializat!, comenta"i linia buffer din .data #i activa"i urm!toarele dou! linii. ;section .bss ; buffer resb 40 section .text global _start _start: nop mov mov mov mov int eax,4 ebx,1 ecx,msg_cerere edx,msg_cerere_lung 80h

mov eax,3 mov ebx,0 mov ecx,buffer mov edx,40 int 80h ;read returneaz! n EAX num!rul de caractere introduse de la tastatur!

mov [lungime_nume],eax mov mov mov mov int mov mov mov mov int eax,4 ebx,1 ecx,msg_salut edx,msg_salut_lung 80h eax,4 ebx,1 ecx,buffer edx,[lungime_nume] 80h

mov eax,1 mov ebx,0 int 80h Func!ia de sistem READ este identificat" prin cifra 3. Are nevoie ca descriptorul de fi#ier s" fie specificat n registrul EBX, iar adresa #i dimensiunea zonei de memorie la care vor fi stocate datele trebuie introdus" n registrul ECX, respectiv n EDX. Va returna num"rul de caractere citit din fi#ier sau, n cazul n care opera!iunea nu s-a putut desf"#ura (de ex., nu exist" fi#ierul), un cod de eroare. Codurile de eroare sunt ntodeauna reprezentate prin numere negative (-1). Observa!i c" func!ia de sistem pentru scriere necesit" aceea#i parametrii ca func!ia de sistem pentru citire, cu excep!ia faptului c" datele care vor fi scrise trebuie s" se afle deja n zona de memorie tampon (buffer).

10.2.1.

Alocarea static! a bufferelor

n programul readInput.asm am folosit o variabil" buffer f"r" s" explic"m ce reprezint". Un buffer este un bloc continuu de octe!i folosit la transferul datelor. La apari!ia unei cereri de citire fi#ier, sistemul de operare trebuie s" aib" la dispozi!ie o zon" de memorie n care s" stocheze datele citite. Aceast" zon" de memorie se nume#te buffer. De obicei, bufferele sunt utilizate numai pentru stocarea temporar" a datelor, date care ulterior sunt citite #i convertite n diferite formate necesare. De exemplu, n programul anterior am citit o linie de text de la STDIN f"r" s" #tim exact lungimea acesteia. Am presupus c" aceasta va avea maxim 40 de caractere, de aceea am setat lungimea bufferului la 40 de caractere. Dac" textul ar fi dep"#it 40 de caractere, surplusul de caractere ar fi fost ignorat. Bufferele au m"rime fix", setat" de programator.

Buffer-ul este creat prin rezervarea static! sau dinamic! a unui spa"iu de memorie. Rezervarea dinamic! nu face obiectul acestei c!r"i. n program am folosit dou! modalit!"i statice de rezervare a spa"iului. O prim! modalitate a fost declararea acestuia n zona datelor ini"ializate (prin directive standard DB, DW, DD, DQ, DT). Totu#i, pe lng! faptul c! este destul de incomod s! ini"ializezi cu o valoare num!rul respectiv de octe"i, o astfel de declara"ie cre#te num!rul de octe"i ai executabilului. n exemplul anterior, m!rimea este infim!, dar presupunnd c! avem nevoie de un buffer de 1025 de octe"i, ambele probleme devin semnificative. Solu"ia a fost deja dezv!luit!: rezervarea unui spa"iu temporar de stocare n zona datelor neini"ializate. Solu"ia este foarte util! deoarece nu trebuie s! ini"ializ!m zona respectiv! cu o valoare #i nici nu cre#tem suplimentar m!rimea executabilului. Directiva buffer resb 40

rezerv! 40 de octe"i pe care i putem folosi ca buffer.

10.2.2.

Macroinstruc!iuni

Observ!m c! programele care folosesc multe apeluri de sistem tind s! devin! foarte lungi. Pentru fiecare apel de sistem n parte folosim un num!r considerabil de instruc"iuni. n capitolul precedent am v!zut c! putem mp!r"i programul n mai multe module prin intermediul func"iilor. Mecanismul de apelare #i de revenire din func"ii este implementat la nivelul procesorului #i este independent de asamblor. Dar asambloarele ofer! #i alt! modalitate de management a complexit!"ii: macroinstruc"iunile. Programele scrise n limbaj de asamblare con!in trei tipuri de propozi!ii: instruc!iuni, directive de asamblare "i macroinstruc!iuni. Macroinstruc!iunile dau posibilitatea substituirii unei secven!e de program cu un nume generic. n timp ce func"iile folosesc instruc"iuni CALL #i RET, macroinstruc"iunile reprezint! un artificiu pus la dispozi"ie de asamblor #i nu depind de o anumit! instruc"iune sau de un anumit set de instruc"iuni. O macroinstruc"iune este o etichet!, un nume sub care se ascunde un bloc de text. Aceste linii de text pot reprezenta, de#i nu este neap!rat necesar, o secven"! de instruc"iuni. Cnd asamblorul ntlne#te n fi#ierul surs! o astfel de etichet!, substituie numele cu secven"a de text asociat!, proces numit extinderea macroinstruc"iunii. Macroinstruc"iunile sunt definite cu directivele %macro #i %endmacro, sintaxa fiind urm!toarea:

%macro <nume_macro> <nr_parametri> bloc de text %endmacro Nume_macro reprezint! numele macroinstruc"iunii, iar nr_parametri specific! num!rul de parametrii utiliza"i de aceasta. Apelul macroinstruc"iunii se face prin specificarea numelui #i valorii parametrilor. Pentru o macroinstruc"iune f!r! parametrii, nr_parametri poate fi 0 sau poate lipsi. De exemplu, urm!toarea macroinstruc"iune f!r! parametrii ntrerupe execu"ia programului: %macro Exit mov eax,1 mov ebx,0 int 80h %endmacro O macroinstruc"iune cu parametrii poate transfera date dintr-o loca"ie de memorie n alt! loca"ie de memorie. $tim c! transferul de date ntre loca"ii de memorie nu este permis. De aceea, recurgem la un registru intermediar. %macro mxchg 2 xchg eax, %1 xchg eax, %2 xchg %1, eax %endmacro Aceast! macroinstruc"iune se invoc! mxchg valoare1, valoare2 #i interschimb! valorile f!r! modificarea registrului EAX. Parametrii macroinstruc"iunii sunt reprezenta"i prin numere precedate de semnul % (procent). Astfel, %1 indic! primul parametru, %2 indic! al doilea parametru. Valorile propriu-zise primite de parametrii se numesc argumente. Nu confunda"i parametrii cu valorile efective ale acestora. Parametrii sunt etichetele care urmeaz! numelui n linia n care este definit! macroinstruc"iunea. Argumentele sunt valorile specificate n linia care invoc! macroinstruc"iunea. Urm!torul program cere de la tastatur! numele utilizatorului #i afi#eaz! un mesaj de salut. ; ;salutMacro.asm

; %macro Write 2 mov eax,4 mov ebx,1 mov ecx, %1 mov edx, %2 int 80h %endmacro %macro Read 2 mov eax,3 mov ebx,0 mov ecx,%1 mov edx,%2 int 80h %endmacro %macro Exit 0 mov eax,1 mov ebx,0 int 80h %endmacro section .data cerere_nume db "Introduceti numele: " cerere_size equ $-cerere_nume salut db "Salut, " salut_size equ $-salut buffer db "01234567890123456789" lungime dd 0 nr_caractere db 20 section .text global _start _start: nop Write cerere_nume,cerere_size Read buffer,[nr_caractere] mov [lungime],eax Write salut,salut_size Write buffer,[lungime] Exit Macroinstruc!iunile din programul salutMacro.asm sunt simple "i u"or de interpretat. Niciuna nu con!ine intruc!iuni de salt. Dar codul din macroinstruc!iune, la fel ca orice func!ie, poate utiliza salturi condi!ionate sau necondi!ionate. Aici

apare ns! o problem! important!: etichetele din programele de asamblare trebuie s! fie unice "i, cum un macro este reintrodus n codul surs! o dat! cu fiecare invocare, la asamblare vor ap!rea erori care semnalizeaz! reutilizarea etichetelor. Din aceast! cauz!, asamblorul YASM permite tratarea etichetelor din interiorul macroinstruc#iunilor ca etichete locale. Etichetele locale nu au semnifica#ie dect n cadrul macroinstruc#iunii care le-a definit. Faptul c! etichetele locale unui macro nu sunt vizibile din exteriorul s!u nseamn! c! ele nu pot fi adresate dect din interiorul grani#elor %macro ... %endmacro. Toate etichetele definite n cadrul unui macro sunt considerate locale "i interpretate special de asamblor. Urm!torul program cite"te de la tastatur! caractere scrise cu liter! mic! "i le converte"te n majuscule. ; ;majuscule.asm ; %macro Majuscule 2 mov edx,%1 ;%1 = Adresa buffer-ului mov ecx,%2 ;%2 = Num!rul de caractere din buffer %%LC: cmp byte [edx+ecx-1],'a' ;Sub 'a'? jb %%Next cmp byte [edx+ecx-1],'z' ;Deasupra lui 'z'? ja %%Next sub byte [edx+ecx-1],20h ;Transform! octetul din buffer n majuscul! %%Next: dec ecx jnz %%LC %endmacro %macro Write 2 mov eax,4 mov ebx,1 mov ecx, %1 mov edx, %2 int 80h %endmacro %macro Read 2 mov eax,3 mov ebx,0 mov ecx,%1 mov edx,%2 int 80h %endmacro %macro Exit 0 mov eax,1

mov ebx,0 int 80h %endmacro section .bss BUFLEN equ 1024 buffer resb BUFLEN section .text global _start _start: nop ;citim un buffer de la stdin citeste: Read buffer,BUFLEN mov esi,eax cmp eax,0 je sfarsit Majuscule buffer,eax Write buffer,esi jmp citeste sfarsit: ;ntrerupem execu!ia programului Exit Eticheta din interiorul unei macroinstruc!iuni precedat" de dou" simboluri procent %% devine local". Dac" eticheta marcheaz" o anumit" pozi!ie din macroinstruc!iune trebuie urmat" de dou" puncte. Dac" este folosit" ca operand pentru instruc!iuni de apel sau de salt (precum JA, JB #i JNZ n programul anterior), nu trebuie urmat" de dou" puncte. Este foarte important s" n!elegem c", dac" etichetele Next #i LC nu erau marcate ca locale prin ad"ugarea prefixului %%, n cadrul programului ar fi existat mai multe instan!e de asemenea etichete (presupunnd c" macroinstruc!iunea ar fi fost invocat" de mai multe ori) #i asamblorul ar fi generat o nou" eroare de etichet" duplicat ncepnd cu a doua apari!ie. Modul n care asamblorul trateaz" macroinstruc!iunile #i etichetele locale acestora se poate observa din fi#ierul majuscule.lst. 1 %line 31+1 majuscule.asm 2 3 [section .bss] 4 BUFLEN equ 1024 5 00000000 <gap> buffer resb BUFLEN 6 [section .text]

7 8 9 00000000 90 10 11 12 00000001 B803000000 13 14 00000006 BB00000000 15 0000000B B9[00000000] 16 00000010 BA00040000 17 00000015 CD80 18 19 00000017 89C6 20 00000019 83F800 21 0000001C 7430 22 23 0000001E BA[00000000] 24 25 00000023 89C1 26 00000025 807C0AFF61 27 0000002A 720A 28 0000002C 807C0AFF7A 29 00000031 7703 30 00000033 806C0AFF20 31 00000038 49 32 00000039 75E8 33 34 35 0000003B B804000000 36 37 00000040 BB01000000 38 00000045 B9[00000000] 39 0000004A 89F2 40 0000004C CD80 41 42 0000004E EBAF 43 44 00000050 B801000000 45 46 00000055 BB00000000 47 0000005A CD80

[global _start] _start: nop citeste: mov eax,3 %line 41+0 majuscule.asm mov ebx,0 mov ecx,buffer mov edx,BUFLEN int 80 %line 42+1 majuscule.asm mov esi,eax cmp eax,0 je sfarsit mov edx,buffer %line 46+0 majuscule.asm mov ecx,eax ..@4.LC: cmp byte [edx+ecx-1],'a' jb ..@4.Next cmp byte [edx+ecx-1],'z' ja ..@4.Next sub byte [edx+ecx-1],20 ..@4.Next: dec ecx jnz ..@4.LC %line 47+1 majuscule.asm mov eax,4 %line 48+0 majuscule.asm mov ebx,1 mov ecx, buffer mov edx, esi int 80 %line 49+1 majuscule.asm jmp citeste sfarsit: mov eax,1 %line 51+0 majuscule.asm mov ebx,0 int 80

Deoarece etichetele trebuie s! fie unice, YASM transform! eticheta local! marcat! cu %% ntr-o etichet! unic! prin prefixarea acesteia cu ..@ plus un num!r de patru digi"i #i numele etichetei. De exemplu, etichetele locale %%LC #i %%Next au devenit ..@4.LC, respectiv ..@4.Next. La o nou! invocare a macroinstruc"iunii, YASM ar fi modificat num!rul #i ar fi generat un nou sinonim unic pentru fiecare etichet! local!. La fel ca n cazul func"iilor, macroinstruc"iunile pot fi grupate n biblioteci externe programului. O bibliotec! de macroinstruc"iuni nu este altceva dect un fi#ier text ce con"ine codul surs! al macroinstruc"iunilor. Spre deosebire de func"iile adunate ntr-un modul, bibliotecile de macroinstruc"iuni sunt asamblate separat #i trebuie parcurse la fiecare proces de asamblare a programului. Bibliotecile de macroinstruc"iuni sunt introduse n program cu ajutorul directivei %include. %include biblioteca.mac Teoretic, aceast! propozi"ie se poate afla oriunde n codul surs!, att timp ct defini"iile macroinstruc"iunilor se g!sesc naintea adres!rii lor. Dar tocmai din acest motiv cel mai indicat este s! includem directiva foarte aproape de nceputul fi#ierului surs!. Dac! biblioteca de macroinstruc"iuni nu se afl! n directorul curent, n cadrul directivei putem specifica calea absolut! sau relativ!. %include ../libs/biblioteca.mac Dac! asamblorul nu poate localiza fi#ierul cu macroinstruc"iuni va genera un mesaj de eroare. Tot din listingul majuscule.lst am v!zut c! de fiecare dat! cnd este invocat! macroinstruc"iunea toate instruc"iunile acesteia sunt reintroduse n program. Dimensiunea programului va cre#te sim"itor pentru un num!r semnificativ de apeluri. Odat! cu dimensiunea cre#te #i memoria ocupat! de proces. n programul salutMacro.asm cele trei apeluri ale macroinstruc"iunii Write genereaz! un total de cincisprezece instruc"iuni. Dac! secven"a de instruc"iuni ar fi fost asamblat! ca func"ie, ar fi fost necesare numai cinci instruc"iuni, plus un RET #i trei instruc"iuni CALL. Dar atunci cnd programul trebuie s! fie ct mai rapid cu putin"!, macroinstruc"iunile au avantajul c! elimin! nc!rcarea suplimentar! generat! de apelurile #i revenirile din func"ii. Viteza este marele avantaj al macroinstruc"iunilor.

10.2.3. Func!ii de lucru cu transferuri de intrare/ie"ire


Macroinstruc!iunile "i func!iile pot fi combinate. n acest moment de!inem destule cuno"tin!e pentru a putea scrie cteva func!ii care mijlocesc interac!iunea noastr# cu sistemul: citirea unui "ir de caractere de la tastur#, afi"area unui "ir de caractere la monitor, etc.. Scriem urm#toarele linii ntr-un fi"ier numit io.inc "i salv#m. extern f_ReadStr f_WriteStr extern f_nwln %macro ReadStr push push mov mov call pop pop %endmacro %macro 1-2 101 ESI EDI EDI,%1 ESI,%2 f_ReadStr EDI ESI

WriteStr 1 push ECX mov ECX,%1 call f_WriteStr pop ECX %endmacro %macro nwln call %endmacro 0 f_nwln 1

%macro WriteChar mov eax,4 mov ebx,1 mov ecx,%1 mov edx,1 int 80h %endmacro %macro ReadChar 1

mov eax,3 mov ebx,0 mov ecx,%1 mov edx,1 int 80h %endmacro %macro Exit mov eax,1 mov ebx,0 int 80h %endmacro 0

Eticheta 1-2 din linia macroinstruc!iunii ReadStr nseamn" c" al doilea parametru al acesteia poate lipsi. Dac" lipse#te (nu este specificat), valoarea implicit" este 101. ReadStr nu este dect o interfa!" pentru func!ia f_ReadStr. Dar vom vedea c" folosirea unui astfel de mecanism aduce avantaje. Func!ia f_ReadStr cite#te un #ir de caractere de la tastatur" #i l stocheaz" ntr-un buffer. Prime#te doi parametri: numele bufferului #i num"rul de caractere ce trebuie citit. Acesta din urm" poate lipsi, macroinstruc!iunea are grij" s" l seteze la o valoare implicit". ; ;func!ia f_ReadStr ; section .bss temp_str resb 256 section .text global f_ReadStr f_ReadStr: pushad pushf mov eax,3 ;func!ia de sistem READ mov ebx,0 ;STDIN mov ecx,temp_str ;buffer temporar mov edx,0x100 ;count = 256 de caractere int 80h ;;n ESI se afl" num"rul de caractere - parametrul %2 din macro. mov ecx,esi dec ecx ;se scade un caracter (spa!iu pentru NULL) ;;n EDI se afl" adresa bufferului DESTINATIE dat n macro.

mov ebx,edi mov esi,temp_str ;adresa de nceput pt. buffer-ul intern func!iei .bucla: mov al,byte [esi] ;ncarc" n AL primul caracter din #irul introdus cmp al,0xa ;verifica dac" utilizatorul a tastat ENTER je .sfarsit ;ENTER nseamn" sfr#itul #irului mov byte [ebx],al ;copiaz" caracterul n DESTINATIE inc ebx ;urm"torul octet din DESTINATIE inc esi ;urmatorul caracter din buffer-ul intern loop .bucla ;repet" pn" cnd #irul s-a sfr#it .sfarsit: mov byte [ebx],0x0 ;adaug" caracterul NULL popf popad ret Func!ia f_ReadStr cite#te de la tastatur" un #ir de caracterele pe care l ncheie cu un caracter NULL. Func!ia f_WriteStr efectueaz" opera!ia invers": scrie la monitor un #ir de caractere terminat n NULL. Prime#te un singur parametru: adresa de la care ncepe #irul de afi#at. Declararea func!iei f_WriteStr se face tot n fi#ierul io.inc. ; ;func!ia f_WriteStr ; section .text global f_WriteStr f_WriteStr: pushad pushf mov ebx,1 ;STDOUT mov edx,1 ;count = 1 caracter .repeta: mov eax,4 ;func!ia de sistem WRITE ;;n ECX este adresa sirului surs". Parametrul %1 din macro. cmp byte [ecx],0x0 ;verific" dac" este caracterul NULL je .sfarsit ;dac" este NULL, #irul s-a sfr#it int 80h ;afi#eaz" caracterul

inc ecx jmp .repeta .sfarsit: popf popad ret

;urm!torul caracter ;se iese din bucl! numai cnd ECX = 0

Obseva"i c! etichetele din cadrul func"iilor ncep cu punct. Acest punct marcheaz! eticheta ca fiind local! (similar celor dou! simboluri procent din macroinstruc"iuni). n programe, eticheta local! permite utilizarea aceluia#i cuvnt n zone de cod diferite. Etichetele cu punct sunt locale fa"! de prima etichet! global! (etichetele care nu ncep cu punct) care le precede. Din acest motiv, o etichet! local! este vizibil! numai dup! eticheta global! c!reia i apar"ine. n consecin"!, eticheta local! nu poate fi adresat! de instruc"iuni aflate naintea etichetei globale corespunz!toare (#i care, repet!m, este prima etichet! global! aflat! naintea etichetei locale). n cazul nostru, deoarece le folosim n corpul func"iilor, pare c! etichetele locale nu sunt precedate de nicio etichet! global!. Dar, ntr-un program, numele func!iilor nu reprezint" altceva dect etichete globale. Etichetele locale din cadrul func"iilor sunt cel pu"in locale func"iilor n care sunt definite. Fire#te, putem folosi etichete globale #i n corpul func"iilor, lucru care limiteaz! #i mai mult vizibilitatea etichetei locale. Func"ia f_nwln trimite la monitor caracterul \n. ; ;func!ia f_nwln ; section .data new_line db 0xa section .text global f_nwln f_nwln: pushad mov eax,4 ;sys_write mov ebx,1 mov ecx,new_line mov edx,1 int 80h popad ret

Nume

Operand Descriere Afi!eaz" un !ir terminat n NULL adresat de WriteStr surs! m eticheta surs!. Cite!te Nr. de caractere de la tastatur" !i le ReadStr dest[,Nr.] m stocheaz" n dest ca !ir terminat n NULL. nwln Afi!eaz" caracterul de linie nou".

Urm"torul program cite!te un caracter de la tastatur" !i afi!eaz" codul ASCII n hexazecimal. ; ;hex.asm ; %include "io.inc" section .data prompt db "Introduceti un caracter: ",0 mesaj1 db "Codul ASCII pentru '",0 mesaj2 db "'in hexa este ",0 mesaj3 db "Introduceti un nou caracter? (y/n)",0 hexTable db "0123456789ABCDEF" section .bss caracter resb 1 section .text global _start _start: nop citeste: WriteStr prompt ReadChar caracter WriteStr mesaj1 WriteChar caracter WriteStr mesaj2 mov al,[caracter] mov ah,al mov ebx,hexTable shr al,4 xlatb mov [caracter],al ;pushad WriteChar caracter ;popad mov al,ah

and al,0x0f xlatb mov [caracter],al WriteChar caracter nwln Exit Instruc!iunea XLATB nlocuie"te caracterul din registrul AL cu un octet din tabela hexTable. Adresa de nceput a tabelei se ncarc#, n prealabil, n EBX. Con!inutul registrului AL este tratat ca index n aceast# tabel# de conversie (transla!ie). Valoarea octetului corespunz#tor indexului nlocuie"te valoarea index din AL. Instruc!iunea se utilizeaz# ndeosebi pentru conversii de cod. Observa!i c" programul ncepe cu directiva %include io.inc. Aceasta for!eaz" asamblorul s" includ" n codul surs" con!inutul fi#ierului io.inc din directorul curent. Efectul se poate observa n fi#ierul .lst. Aduce!i-v" aminte c" YASM diferen!iaz" caracterele mici de cele mari. Pentru a genera executabilul trebuie s" asambl"m pe rnd func!iile #i programul principal, apoi s" edit"m leg"turile: yasm -f elf -g stabs f_ReadStr.asm yasm -f elf -g stabs f_WriteStr.asm yasm -f elf -g stabs f_nwln yasm -f elf -g stabs hex.asm ld -o hex hex.o f_WriteStr.o f_nwln.o f_ReadStr.o melf_i386 Programul nu func!ioneaz" corect. Dac" depana!i programul cu GDB devine evident c" problema este legat" de rescrierea registrului AH n corpul celei de a doua macroinstruc!iuni WriteChar. Pierdem caracterul introdus de la tastatur". Macroinstruc!iunile sunt simple secven!e de cod introduse n program de fiecare dat" cnd scriem numele acestora. Cu ct programele sunt mai complexe #i folosesc mai multe registre, cu att cre#te posibilitatea s" gre#im. n cazul acestui program putem salva con!inutul registrelor nainte de intrarea n macroinstruc!iune cu PUSHAD. Avem #i alte posibilit"!i, putem salva numai con!inutul registrului EDX sau putem include instruc!iunile de salvare #i recuperare a registrelor chiar n corpul macroinstruc!iunii. Dar, o solu!ie mai elegant" este s" folosim func!ii. Modific"m nregistr"rile corespunz"toare macroinstruc!iunilor ReadChar #i WriteChar din io.inc astfel: %macro WriteChar 1

push EAX mov AL,byte [%1] call f_WriteChar pop EAX %endmacro %macro ReadChar 1 push EAX call f_ReadChar mov byte [%1],AL pop EAX %endmacro Cre!m dou! fi"iere f_ReadChar.asm "i f_WriteChar.asm n care introducem instruc#iunile func#iilor de citire, respectiv afi"are, caracter. section .bss temp_char resb 256 section .text global f_ReadChar f_ReadChar: pushf mov eax,3 mov ebx,0 mov ecx,temp_char mov edx,1 int 80h mov al,byte [temp_char] popf ret section .bss temp_char resb 256 section .text global f_WriteChar f_WriteChar: pushad pushf mov byte mov mov mov mov int [temp_char],al eax,4 ebx,1 ecx,temp_char edx,1 80h

popf popad ret

Nume WriteChar surs! ReadChar dest

Operand Descriere Afi"eaz! un caracter din surs!. m Cite"te un caracter n dest. m

Relua#i procesul de asamblare. Nu uita#i s! introduce#i n linia editorului de leg!turi

fi!ierele obiect corespunz"toare acestor ultime dou" func#ii. Listingul programului este tot hex.asm, varianta f"r" instruc#iuni PUSHAD !i POPAD.

10.2.4.

Opera!ii cu fi"iere

Am v"zut c" func#iile de sistem WRITE !i READ pot scrie informa#ii la monitor sau pot citi date de la tastatur" pentru c" aceste dispozitive sunt fi!iere deschise implicit pentru orice program care ruleaz". STDIN este un fi!ier asupra c"ruia avem numai drepturi de citire (reprezint" tastatura), STDOUT este un fi!ier asupra c"ruia avem numai drept de scriere (reprezint" monitorul). nseamn" c" putem folosi aceste apeluri de sistem pentru orice tip de fi!ier, chiar !i pentru un fi!ier n#eles n sensul clasic (date salvate pe disc). De exemplu, programul majuscule.asm poate converti caracterele unor fi!iere aflate pe disc prin mecanismul de redirec#ionare I/O. ./majuscule < fisier.txt > FISIER.txt Numai c", spre deosebire de cele trei fi!iere standard, deschise ntodeauna de sistemul de operare la nceputul rul"rii unui program, fi!ierele aflate pe disc sunt nchise. Pentru a putea citi sau scrie date n ele, programul trebuie s" le deschid". Evident, acest lucru se face printr-o func#ie de sistem. Func#ia OPEN prime!te ca argumente: numele fi!ierului, un num"r ce reprezint" modul de operare asupra fi!ierului deschis (citire, scriere, citire !i scriere, dac" nu exist" trebuie creat, etc..) !i un set de permisiuni (reamintim c" permisiunile se refer" la cine are dreptul s" acceseze respectivul fi!ier - utilizatorul, grupul din care face parte utilizatorul sau acces universal-, !i pot fi verificate cu comanda ls). n programele care urmeaz" vom gestiona fi!ierele n modul urm"tor: Specific"m sistemului de operare numele fi!ierului pe care dorim s" l deschidem !i modul de operare asupra lui. Realiz"m acest lucru cu apelul de sistem OPEN,care are ca identificator (n registrul EAX) num"rul 5. Adresa primului caracter din fi!ier trebuie stocat" n EBX. Inten#ia de citire/scriere, reprezentat" ca num"r, trebuie stocat" n registrul ECX. Deocamdat" folosim 0 pentru fi!ierele din care dorim s" citim, al#i indicatori sunt prezenta#i n Tabelul 10.1 (dac" se dore!te combinarea acestora se efectueaz" un SAU logic ntre valorile lor). n final, setul de permisiuni trebuie trecut n registrul EDX. Sistemul de operare va returna n registrul EAX un descriptor de fi!ier. Ne amintim c" descriptorul de fi!ier este un num"r folosit n program ca referin#" pentru acel fi!ier, un identificator (ca !i cnd ne-am referi la o persoan" folosind CNP-ul !i nu numele).

Citim !i/sau scriem fi!ierul, specificnd de fiecare dat" descriptorul dorit. La finalul opera#iilor, fi!ierele sunt nchise cu func#ia de sistem CLOSE, apelul de sistem 6. Singurul parametru necesar este descriptorul de fi!ier; plasat n registrul EBX. Dup" CLOSE, descriptorul de fi!ier nu mai este valid.

Programul urm"tor ilustreaz" citirea unui fi!ier, stocarea con#inutului ntrun buffer !i afi!area acestuia pe ecran. Observa#i faptul c" pentru a stoca datele fi!ierului avem nevoie de un buffer. De asemenea, la citirea unui fi!ier trebuie specificat" cantitatea de informa#ie pe care dorim s" o citim, iar aceast" cantitate nu poate dep"!i m"rimea buffer-ului. Num"rul de octe#i citit din fi!ier (returnat de func#ia de sistem) este salvat ntr-o variabil" (nrCitit). Fi!ierul este creat nainte de rularea programului cu comanda: echo Acesta este un fisier text > fisier.txt ; ;citireFisier.asm ; section .data numeFisier db fisier.txt,0 descriptor dd 0 nrCitit dd 0 msgErr db Nu am putut deschide fi!ierul,0xa msgErr_lung equ $ - msgErr section .bss MAXBUF equ 100000 buffer resb MAXBUF section .text global _start _start: nop mov eax,5 ;identificatorul open mov ebx,numeFisier mov ecx,0 ;O_RDONLY mov edx,0644q int 80h ;open returneaz" -1 n eax n caz de probleme test eax,eax jns readFile ;dac" sunt probleme, TEST EAX,EAX seteaz" SF, afi!"m mesaj de eroare !i

exit mov mov mov mov int mov mov int eax,4 ebx,1 ecx,msgErr edx,msgErr_lung 80h eax,1 ebx,0 80h

readFile: ;salv!m descriptorul de fi"ier mov [descriptor],eax ;citim fi"ierul mov eax,3 mov ebx,[descriptor] mov ecx,buffer mov edx,MAXBUF int 80h ;salveaz! num!rul de octe#i citi#i mov [nrCitit],eax ;afi"!m buffer-ul mov eax,4 mov ebx,1 mov ecx,buffer mov edx,[nrCitit] int 80h ;nchidem fi"ierul mov eax,6 mov ebx,descriptor int 80h ;ncheiem execu#ia programului mov eax,1 mov ebx,0 int 80h
Tabelul 10.2 Moduri de operare asupra fi!ierelor de c"tre func#ia de sistem OPEN

Indicator Nr. n octal O_RDONLY 00000 O_WRONLY 00001 O_RDWR 00002

Descriere Deschide fi"ierul numai n modul citire. Deschide fi"ierul numai n modul scriere. Deschide fi"ierul att pentru citire ct "i pentru

O_CREAT O_TRUNC O_APPEND ; ;creareFisier.asm ; section .data


msgErr

00100 01000 02000

scriere. Dac! nc! nu exist!, creaz! fi"ierul. Dac! fi"ierul exist!, "terge con#inutul acestuia. Adaug! con#inut. Scrie la sfr"itul fi"ierului, nu la nceput.

db Nu am putut crea fi!ierul,0xa

msgErr_lung equ $ - msgErr numeFisier db date.txt descriptor dd 0 buffer db What do you think about that?,0xa db I think you're alive...,0xa buffer_lung equ $ - buffer section .text global _start _start: nop ;creaz! fi"ierul mov eax,8 ;identificatorul func#iei de sistem create mov ebx,numeFisier mov ecx,0644q ;permisiunile fi"ierului creat int 80h test eax,eax jns createFile ;afi"eaz! mesaj de eroare n caz c! nu a putut fi creat mov eax,4 mov ebx,1 mov ecx,msgErr mov edx,msgErr_lung int 80h mov eax,1 mov ebx,0 int 80h ;n caz de succes salveaz! descriptorul ntors de create n registrul EAX createFile: mov [descriptor],eax ;scrie n fi"ier

mov eax,4 mov ebx,[descriptor] mov ecx,buffer mov edx,buffer_lung int 80h ;nchide fi!ierul mov eax,6 mov ebx,[descriptor] int 80h ;ie!ire din program mov eax,1 mov ebx,0 int 80h

10.2.5.

Argumente n linia de comand!

n capitolul anterior am studiat modul n care func"iile primesc parametri de intrare din partea programului principal. Dar !i programul principal poate primi parametri de intrare de la utilizator. Am v#zut c# aproape toate comenzile Linux primesc op"iuni n linie de comand#. Modalitatea de transfer a parametrilor de intrare c#tre programe difer# de la un sistem de operare la altul. nainte s# explic#m metoda utilizat# de Linux trebuie s# ne amintim cum este structurat# memoria principal# din perspectiva unui proces. Cnd un program este lansat n execu"ie, sistemul de operare creaz# pentru acesta o zon# de memorie cu aspectul dat n Figura 10.1. Stiva programului, destinat# stoc#rii variabilelor locale !i a parametrilor pentru func"ii, este reprezentat# de blocul superior de memorie. De!i am putea crede c# la nceputul procesului stiva este liber# (spa"iu gol), acest lucru nu este adev#rat. nainte s# ncarce programul n memorie, sistemul de operare plaseaz# n stiv# urm#toarele informa"ii: num#rul de parametrii din linia de comand#; numele !i calea absolut# a programului, a!a cum a fost el executat din linia de comand#; fiecare parametru (argument) introdus de utilizator n linia de comand# la execu"ia programului; toate variabilele contextului de lucru la nceputul rul#rii programului. Toate sunt plasate n memorie conform planului prezentat n Figura 10.2. Numele programului, argumentele din linia de comand# !i variabilele de mediu sunt !iruri de lungime variabil# terminate n caracterul NULL (nume care denot# 32 de bi"i de 0). Linux nu numai c# ncarc# !irurile n stiv#, dar ncarc# !i adresele (pointeri) acestora.

4 GB KERNEL SPACE 3 GB Stiv! program Memoria virtual! a kernelului (cod, date, heap, stiv!)

0FFFFFFFFH

0BFFFFFFFH Bloc superior

ESP

Biblioteci partajate 040000000H USER SPACE Heap section .bss Bloc inferior

nc"rcate din fi#ierul executabil

section .data section .text

08048000H 00000000H 0

Figura 10.2 Structura unui process n Linux

La nceputul execu!iei, registrul ESP indic" vrful stivei. Deasupra adresei din ESP se g"sesc toate elementele introduse de sistemul de operare, urmnd ca variabilele locale #i parametrii func!iilor (cadrele de stiv") s" fie dispuse la adrese mai mici dect cea din ESP. ncepnd cu indicatorul de stiv" (ESP), urmeaz" num"rul parametrilor din linia de comand" sub forma unui ntreg f"r" semn de 4 octe!i, adresa loca!iei la care se afl" numele programului, adresele fiec"rui parametru din linia de comand" (fiecare cte 4 octe!i). Lista argumentelor se termin" cu un indicator NULL. De la acesta n sus ncepe o list" lung" de adrese pe 32 de bi!i, fiecare indic" un #ir, terminat tot n NULL, c"tre variabilele mediului de

lucru. Num!rul acestora difer! de la sistem la sistem, dar poate fi aproape de 200. La finalul listei de adrese pentru variabilele de mediu este nc! un indicator. Acesta marcheaz! sfr"itul directorului de stiv!. La primele sisteme Linux adresa de nceput a stivei era ntotdeauna 0BFFFFFFFH. n prezent, din considerente de securitate, sistemele Linux schimb! pu#in baza stivei odat! cu fiecare rulare a programelor. De aceea, adresele de nceput ale stivei pot diferi de la rulare la rulare, de obicei cu cteva milioane de octe#i. n plus, ntre sfr"itul listei de adrese "i nceputul "irurilor de elemente se afl! o zon! variabil! de memorie neutilizat!. Structura stivei poate fi observat! cu ajutorul depanatorului. Rul!m programul prezentat n sec#iunea anterioar!: gdb program. Am v!zut c! programul nu este lansat imediat n execu#ie, ci este #inut n memorie pn! cnd
0x00000000 Calea absolut! a executabilului Variabilele mediu propriu-zise (fiecare reprezentat! ca "ir de caractere terminat cu NULL) Argumentele din linia de comand! propriu-zise (fiecare reprezentat ca "ir de caractere terminat cu NULL) Numele programului Variabile de sistem "i spa#iu liber 0x00000000 Adresa variabilei de mediu 3 Adresa variabilei de mediu 2 Adresa variabilei de mediu 1 0x00000000 Adresa argumentului 3 Adresa argumentului 2 Adresa argumentului 1 Adresa numelui de progam Num!r de argumente 0 31

ESP

Figura 10.3 Stiva programului la momentul lans!rii n execu"ie

d!m comanda de rulare run. Acest lucru ne d! posibilitatea s! specific!m punctele de ntrerupere. Totodat!, ne d! posibilitatea s! specific!m argumentele din linia de comand! cu ajutorul comenzii set args. (gdb) set args 10 20 (gdb) show args

Argument list to give program being debugged when it is started is "10 20". n acest caz am introdus dou! argumente: numerele 10 "i 20. Chiar dac! programul nu folose"te argumente din linie de comand!, putem simula introducere lor n stiv!. Verificarea argumentelor introduse se face cu show args. O alt! posibilitate este s! le specific!m imediat dup! "inia de rulare. Nu uita#i ca n prealabil s! seta#i punctul de oprire. (gdb) b *_start+1 Breakpoint 1 at 0x8048081: file main.asm, line 9. (gdb) r 10 20 Starting program: /home/stefan/program 10 20 Breakpoint 1, _start () at main.asm:9 9 push 5 (gdb) p $esp $1 = (void *) 0xffffd400 Observa#i c! linia Starting program indic! prezen#a argumentelor din linia de comand!. Indicatorul de stiv! ESP con#ine adresa vrfului stivei, 0xffffd400. Afi"!m primele 20 de cuvinte ncepnd cu aceast! adres!, n format hexazecimal. (gdb) x /20xw 0xffffd400 0xffffd400: 0x00000003 0xffffd580 0xffffd410: 0x00000000 0xffffd59b 0xffffd420: 0xffffd5f3 0xffffd603 0xffffd430: 0xffffd670 0xffffd69a 0xffffd440: 0xffffdbb6 0xffffdbdc 0xffffd595 0xffffd5bd 0xffffd60e 0xffffd6ba 0xffffdc0e 0xffffd598 0xffffd5d0 0xffffd65e 0xffffd6c6 0xffffdc1e

Prima valoare, 0x00000003, specific! num!rul de argumente din linia de comand!, incluznd "i numele programului. Urm!toarele dou! loca#ii con#in indicatori c!tre numele programului "i "irurile de parametrii din linia de comand!. Putem vedea valoarea acestor "iruri tot prin intermediul comenzii x, urmat! de adresele respective. (gdb) x /s 0xffffd580 0xffffd580: "/home/stefan/program" (gdb) x /s 0xffffd595 0xffffd595: "10" (gdb) x /s 0xffffd598 0xffffd598: "20"

Aten!ie, este important s" re!inem c" toate argumentele din linia de comand! sunt specificate ca "iruri, chiar dac! arat! ca numere. Argumentele din linia de comand" sunt urmate de un indicator NULL care separ" adresele argumentelor de adresele variabilelor de mediu. List"m cteva variabile de mediu pe baza adreselor lor. (gdb) x /s 0xffffd59b: (gdb) x /s 0xffffd5bd: (gdb) x /s 0xffffd5d0: (gdb) x /s 0xffffd5f3: (gdb) x /s 0xffffd603: (gdb) x /s 0xffffd65e: 0xffffd59b "ORBIT_SOCKETDIR=/tmp/orbit-stefan" 0xffffd5bd "SSH_AGENT_PID=1188" 0xffffd5d0 "GIO_LAUNCHED_DESKTOP_FILE_PID=4500" 0xffffd5f3 "SHELL=/bin/bash" 0xffffd603 "TERM=xterm" 0xffffd65e "WINDOWID=73400324"

La rndul lor, acestea se vor sfr#i cu un indicator NULL. Num"rul lor depinde de aplica!iile prezente n sistem.

10.3. Opera!ii aritmetice n reprezent"ri ASCII #i BCD


A#a cum reiese din paragrafele precedente, argumentele din linia de comand" sunt dispuse n stiv" sub forma unor #iruri de caractere. Dac" dorim s" le utiliz"m ca numere trebuie s" le convertim. Conversia caracterelor la valori ntregi sau n virgul" mobil" se poate face n mai multe moduri. Pentru opera!ii simple (de ex., o singur" adunare), Intel a pus la dispozi!ie instruc!iuni ce mijlocesc efectuarea calculelor direct n format ASCII sau ntr-un format asem"n"tor celui zecimal, numit BCD (Binary Coded Decimal). Formatul BCD este destinat s" simplifice lucrul cu dispozitivele care utilizeaz" numere zecimale (dispozitive care trebuie s" afi#eze numere, precum ceasuri sau num"r"toare). BCD permite procesorului s" efectueze calcule dup" un algoritm asem"n"tor celui zecimal. n prezent, instruc!iunile BCD sunt folosite rar, dar cunoa#terea lor #i a modului n care sunt folosite de procesor poate fi util".

10.3.1.

Formatul BCD

Formatul Zecimal Codat Binar realizeaz! exact ce i denot! numele: codific! numerele zecimale n format binar. n func"ie de num!rul de bi"i necesar reprezent!rii unei cifre zecimale, 4, respectiv 8 bi"i, are dou! variante, compactat #i necompactat. Fiecare valoare BCD este un ntreg de 4 sau 8 bi"i, cu o valoare ntre 0 #i 9. Valorile mai mari de 9 sunt considerate invalide. n esen"!, regulile sunt: fiecare cifr! zecimal! este nlocuit! de 4 sau 8 bi"i; se utilizeaz! cifrele zecimale 0,1,2,3,4,5,6,7,8,9; valorile binare superioare lui 9 sunt interzise.
Tabelul 10.3 Formatul BCD

Zecimal 0 1 2 3 4 5 6 7 8 9

Binar 0 1 10 11 100 101 110 111 1000 1001

BCD compactat 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001

BCD necompactat 00000000 00000001 00000010 00000011 00000100 00000101 00000110 00000111 00001000 00001001

Regula prin care se formeaz! un num!r n BCD este regula zecimal!, de aici #i numele de zecimal codat binar cifrele sunt reprezentate n binar, dar regulile sunt zecimale. Pur #i simplu, ca s! ob"inem num!rul 11 n BCD, al!tur!m reprezent!rile binare ale celor dou! cifre: 0001 0001. Zecimal 15 100 99 BCD compactat 0001 0101 0001 0000 0000 1001 1001 BCD necompactat 00000001 00000101 00000001 00000000 00000000 00001001 00001001

10.3.2.

Erori !i corec"ii n ASCII

Presupunem c! trebuie s! scriem un mic program de calcul aritmetic. Acesta prime#te ca argumente n linie de comand! dou! cifre #i un semn +, -, *, /.

Ordinea de introducere a argumentelor este cea conven!ionl": 5 + 3, 9 - 7, etc.. Pentru moment prezent"m numai modulul de adunare #i sc"dere (pentru un listing mai scurt). Structura programului poate fi gandit" astfel: ; ;calc.asm ; section .data nwln db 0ah section .bss rez resw 1 section .text global _start _start: nop mov esi,[esp+8] ;nc"rc"m n ESI adresa primei cifre mov edi,[esp+16] ;nc"rc"m n EDI adresa celei de a doua cifre mov ecx,[esp+12] ;adresa semnului aritmetic mov dl,'+' cmp dl,byte [ecx] ;comparam semnul aritmetic cu + jne .L1 ;; modulul de adunare mov al,[esi] add al,[edi] jmp .end .L1: mov cl,'-' ;compar"m semnul aritmetic cu cmp cl,byte [esp+12] jne .L2 ;; modulul de sc"dere jmp .end .end: ;; afi#are rezultat mov eax,4 mov ebx,1 mov ecx,rez mov edx,2 int 80h ;; new line mov eax,4 mov ebx,1 mov ecx,nwln

mov edx,1 int 80h ;; exit mov eax,1 mov ebx,0 int 80h La final, din motive pur estetice, func!ia de afi"are a rezultatului este urmat# de func!ia de trecere la linie nou#. Executabilul prime"te argumente din linie de comand# astfel: ./calc 3 + 5 Fiecare argument este desp#r!it prin spa!iu. Cnd rul#m programul prin intermediul depanatorului, pentru specificarea argumentelor folosim comanda set args 3 + 5. Primele trei instruc!iuni ale programului ncarc# adresele argumentelor n trei registre de uz general (n vederea adres#rii lor prin metoda indirect#). (gdb) p /x $esi $1 = 0xffffd598 (gdb) x /s $esi 0xffffd598: "3" (gdb) x /s $edi 0xffffd59c: "5" (gdb) x /s $ecx 0xffffd59a: "+" Pe baza semnului se alege modulul aritmetic corespunz#tor. n consecin!#, argumentul de semn este comparat pe rnd cu fiecare semn n parte. Codul semnului putea fi introdus n instruc!iune direct ca num#r hexazecimal, dar am ales formatul caracter ASCII, deoarece acesta este subiectul acestei sec!iuni. (gdb) p /x $dl $5 = 0x2b (gdb) p /c $dl $6 = 43 '+' Adunarea ASCII Problemele ncep imediat dup# instruc!iunea de adunare.

(gdb) n 17 mov al,[esi] (gdb) n 18 adc al,[edi] (gdb) n 19 jmp .end (gdb) p /x $eax $7 = 0x68 A!a cum reiese din exemplul de mai jos, instruc"iunea adun# corect caracterele ASCII 3 (33H) !i 5 (35H). 33H = 0011 0011 + 35H = 0011 0101 68H = 0110 1000 ns# 68H reprezint# caracterul ASCII 'h', nu caracterul '8' (38H). Pe de alt# parte, valorile 33H !i 35H, privite din perspectiva formatului BCD compactat, sunt valori valide pentru cifrele 3 !i 5. La fel !i 68H reprezentare valid# pentru cifra 8. Digitul inferior reprezint# valoarea cifrei (3, 5, respectiv 8), iar digitul superior este ignorat (l putem considera 0, !i atunci avem 03 + 05 = 08). De fapt, deoarece cei 4 bi"i inferiori con"in valoarea BCD, to"i digi"ii ASCII de la '0' la '9' pot fi considera"i digi"i BCD valizi. n consecin"#, n BCD compactat, adunarea 33H + 35H = 68H este corect#. Rezultatul poate fi afi!at cu u!urin"# dac# set#m digitul superior la valoarea 3. Totu!i, acest mecanism nu poate fi aplicat n cazurile n care digitul rezultat este mai mare ca 9. S# consider#m adunarea '7' + '5'. 37H = 0011 0111 + 35H = 0011 0101 6CH = 0110 1100 Chiar dac# ignor#m digitul superior (6), suma tot trebuia s# fie de forma 01 02H. Iat# un prim caz de eroare n BCD. Adunarea a dou# cifre valide are ca rezultat o combina"ie invalid# (necunoscut#). n acest caz, 1100 (C). Principiul corec"iei n BCD sus"ine ca, n astfel de cazuri, digitul cu combina"ie inexistent# trebuie adunat cu 0110 (6 n zecimal). 6 este diferen"a ntre baza hexazecimal# !i cea zecimal#. 0000 1100 + 0000 0110 0001 0010

A!adar, dac" am avea posibilitatea s" adun"m n BCD, adunarea '7' + '5' ar da ntradev"r '12', deoarece '7' !i '5' pot fi tratate ca valori BCD legale. Ei bine, Intel pune la dispozi#ie o astfel de instruc#iune: instruc#iunea AAA (ASCII Adjust after Addition). Instruc#iunea AAA se folose!te dup" o adunare efectuat" cu instruc#iunea ADD sau ADC. Suma rezultat" n registrul AL este convertit" n reprezentare BCD n doi pa!i: dac" digitul inferior din registrul AL este mai mare ca 9, sau dac" este setat indicatorul de condi#ii AF din registrul EFLAGS, adun" 6 la AL !i 1 la AH (n urma opera#iei, indicatorii de condi#ii AF !i CF sunt seta#i). n toate cazurile, digitul superior este trecut n zero. n aceste condi#ii, modulul de adunare din programul calc.asm poate fi scris astfel: ;; modulul de adunare mov al,[esi] adc al,[edi] aaa or ax,3030h cmp ah,30h jne L0_1 mov [rez],al jmp .end L0_1: xchg ah,al mov [rez],ax jmp .end Pentru a putea afi!a rezultatul, instruc#iunea OR AX,3030H seteaz" pentru fiecare cifr" BCD digitul superior la 3. Se ob#ine un !ir de dou" caractere ASCII. n cazul adun"rii '7' + '5' !irul ASCII din AX este 3132H. Compararea lui AH cu 30H are urm"toarele dou" scopuri: dac" rezultatul poate fi reprezentat cu un singur caracter, nu includem n fa#a acetuia caracterul 0 (pentru 4 + 4 afi!"m 8, nu 08); dac" rezultatul este reprezentat pe dou" caractere, trebuie s" #inem cont de ordinea corect" a octe#ilor. Octetul superior (AH) este trecut n memorie la adres" superioar", octetul inferior (AL) este trecut n memorie la adres" inferioar". Primul afi!at va fi AL. Dac" dorim s" adun"m un num"r cu mai mul#i digi#i, trebuie s" folosim o

bucl! ce adun! digit cu digit, ncepnd cu primul din dreapta. Sc!derea ASCII Corec"ia rezultatului ob"inut n urma unei opera"ii de sc!dere se face cu instruc"iunea AAS (ASCII Adjust after Substraction). Ac"iunile sale sunt: dac! digitul inferior din AL este mai mare ca 9, sau indicatorul de condi"ii AF este setat, scade 6 din AL #i 1 din AH (n urma opera"iei, indicatorii de condi"ii AF #i CF sunt seta"i). n toate cazurile, digitul superior este ini"ializat cu zero. Este evident c! ajustarea este necesar! numai n cazul unui rezultat negativ. Dac! rezultatul este pozitiv, con"inutul registrului AL nu este afectat de instruc"iunea AAS. Sc!dere ASCII cu rezultat pozitiv: xor ah,ah mov al,'8' sub al,'3' aas or al,30h ;#terge registrul AH ;AL = 38H ;AL = 38H 33H = 05H ;AX = 0005H ;AL = 35H

Sc!dere ASCII cu rezultat negativ: xor ah,ah mov al,'3' sub al,'8' aas or AL,30H ;!terge registrul AH ;AL = 33H ;AL = 33H 38H = FBH ;AX = FF05H ;AX = FF35H

n acest ultim caz, rezultatul din AL indic! magnitudinea. Instruc"iunea AAS seteaz! indicatorul CF pentru a indica faptul c! a fost generat un mprumut. Dac! privim n contextul sc!derii numerelor cu mai mul"i digi"i, rezultatul final, FF35H, este util #i corect. De exemplu, dac! sc!dem 28 din 43 (de ex., 43 28), prima itera"ie a buclei scade 3 8; ob"inem n AL rezultatul 5 #i avem CF setat. Urm!toarea itera"ie, 4 2, folose#te instruc"iunea SBB, care include n opera"ie #i mprumutul generat de sc!derea precedent!; ob"inem 1. A#adar, dup! opera"ia SAU vom avea 31 35H, valoare care reprezint! r!spunsul corect (35). Modulul de sc!dere al programului nostru arat! astfel: ;; modulul de sc!dere mov al,[esi]

sub al,[edi] aas or al,30h mov [rez],al jmp .end Aten!ie, deoarece ar fi complicat programul, modulul de sc"dere nu ia n considerare rezultatul negativ. Scopul nostru este s" n!elegem instruc!iunea AAS. nmul!irea ASCII Instruc!iunea de corec!ie a rezultatului unei opera!ii de nmul!ire este AAM (ASCII Adjust after Multiplication). Foarte important, spre deosebire de adunare #i sc"dere, nmul!irea nu trebuie efectuat" cu caractere ASCII, ci cu numere n format BCD necompactat. Instruc!iunea AAM mparte valoarea din AL cu 10 #i p"streaz" ctul n AH #i restul n AL. mov al,3 mov bl,8 mul bl aam or ax,3030H ;operand n format BCD necompactat (8 bi!i) ;operand n format BCD necompactat (8 bi!i) ;AX = 0018H (24 n zecimal) ;AX = 0204H ;AX = 3234H

Observa!i c" opera!ia de nmul!ire folose#te numere n format BCD necompactat (nu numere ASCII). Dac" digi!ii din AL #i BL sunt n format ASCII, trebuie s" masc"m digitul superior. De aceea, codul modulului de nmul!ire pentru programul calc.asm arat" astfel: .L2: mov dl,'*' cmp dl,byte [ecx] jne .L3 ;; modulul de inmultire mov al,[esi] mov bl,[edi] and al,0fh and bl,0fh mul bl aam or ax,3030h cmp ah,30h jne .L2_1

mov [rez],al jmp .end .L2_1: xchg ah,al mov [rez],ax jmp .end Deoarece pentru interpretorul de comenzi bash semnul stelu!" este caracter special, cnd efectua!i o nmul!ire, argumentul de semn din linia de comand" trebuie precedat de caracterul \ (ESCAPE), asfel: ./calc 3 \* 5 mp!r"irea ASCII Instruc!iunea AAD (ASCII Adjust before Division) corecteaz" valoarea demp"r!itului din acumulator naintea mp"r!irii a dou" numere n format BCD necompactat. Instruc!iunea AAD nmul!e#te AH cu 10, l adun" la AL (ace#ti doi pa#i convertesc num"rul din BCD necompactat n binar) #i apoi l ini!ializeaz" cu zero. De exemplu: mov ax,0205H mov bl,08H aad div bl ;demp"r!itul n format BCD necompactat ;mp"r!itorul n format BCD necompactat ;AX = 0019H ;AX = 0103H

Instruc!iunea AAD converte#te num"rul stocat AX din BCD necompactat n format binar, astfel nct s" poat" fi folosit" instruc!iunea DIV. DIV genereaz" ctul n registrul AL #i restul n registrul AH . Modulul de mp"r!ire prezentat mai jos exemplific" strictul necesar: conversia din ASCII n BCD necompactat, #i efectul instruc!iunii AAD. mparte o cifr" mai mare la una mai mic" #i afi#eaz" rezultatul n form" brut" (con!inutul registrului AX). .L3: mov dl,'/' cmp dl,byte [ecx] jne .end ;; modulul de impartire mov al,[esi] sub al,30h mov bl,[edi]

sub bl,30h aad div bl or ax,3030h mov [rez],ax jmp .end La fel ca la nmul!ire, cnd specific"m argumentul de semn trebuie s" folosim caracterul ESCAPE.

10.3.3.

Erori !i corec"ii n BCD compactat

Numerele n format BCD compactat pot fi adunate sau sc"zute cu ajutorul a dou" instruc!iuni dedicate: DAA (Decimal Adjust after Addition) DAS (Decimal Adjust after Substraction) Nu exist" suport pentru nmul!ire sau mp"r!ire. Pentru aceste opera!ii, numerele trebuie convertite n format BCD necompactat. Instruc!iunile DAA #i DAS corecteaz" rezultatul unei opera!ii de adunare, respectiv de sc"dere, n conformitate cu formatul BCD compactat. Pentru a n!elege tipurile de corec!ii necesare, studiem urm"toarele exemple: 29H = 0010 10001 + 49H = 0100 10001 72H = 0111 0010 17H = 0001 0111+ 24H = 0010 0100 3BH = 0011 1011 42H = 0100 0010 + 71H = 0111 0001 B3H = 1011 0011

n primul caz, rezultatul 72 nu este corect. Rezultatul corect, 78, se ob!ine prin adunarea cu 6 a rezultatului ob!inut. Eroarea const" n propagarea unui bit de transport de la digitul inferior spre cel superior. Eroare semnalizat" de indicatorul AF. n al doilea exemplu, rezultatul trebuia s" fie 41. Deoarece digitul inferior este mai mare ca 9, rezultatul corect se ob!ine prin adunare cu 6. n ultimul exemplu, eroarea const" n dep"#irea capacit"!ii digitului superior. Solu!ia este s" adun"m la rezultat valoarea 60H. mpreun" cu bitul de transport generat (CF) rezultatul efectiv este 113. Un exemplu legat de opera!iile de sc"dere este urm"torul: 52H = 0101 0010 24H = 0010 0100

2EH = 0010 1110 n concluzie, rezultatele opera!iilor de adunare sau sc"dere care folosesc numere n format BCD compactat pot fi afectate de erori. Acestea sunt indicate de prezen!a codurilor inexistente n BCD, de setarea indicatorului de transport (CF) sau de setarea indicatorului de transport la jum"tate (AF). n func!ie de caz, corec!ia se face prin adunarea sau sc"derea rezultatului ob!inut cu unul din numerele 06H, 60H sau 66H. Instruc!iunea DAA efectueaz" acest tip de corec!ii asupra rezultatului opera!iilor de adunare. Mai exact, DAA efectueaz" urm"toarele ac!iuni: dac" digitul inferior din AL este mai mare ca 9, sau indicatorul de transport la jum"tate este setat, adun" 6 la AL #i seteaz" AF; dac" digitul superior din AL este mai mare ca 9, sau indicatorul de transport este setat, adun" 60H la AL #i seteaz" CF. Instruc!iunea DAS corecteaz" rezultatul opera!iilor de sc"dere. Mai exact: dac" digitul inferior din AL este mai mare ca 9, sau indicatorul de transport la jum"tate este setat, scade 6 din AL #i seteaz" AF; dac" digitul superior din AL este mai mare ca 9, sau indicatorul de transport este setat, scade 60H din AL #i seteaz" CF. n acest moment cunoa#tem trei reprezent"ri care pot fi folosite n opera!iile aritmetice: binar, ASCII #i BCD. Utilizarea unei reprezent"ri n detrimentul alteia depinde n mare m"sur" de tipul aplica!iei. Procesarea numeric" n ASCII este indicat" n cazul opera!iilor simple, efectuate de aplica!ii interactive, care preiau date de la utilizator #i/sau afi#eaz" rezultate pe ecran. A#a cum #tim, sistemul de calcul schimb" informa!ii cu utilizatorul numai n format ASCII. Conversia datelor de intrare n format binar consum" resurse suplimentare #i cre#te timpul de execu!ie. Procesarea numeric" n BCD este mai lent" dect procesarea numeric" n ASCII, dar, n schimb, este mai flexibil" - a#a cum a reie#it #i din paginile anterioare. n plus, conversia ntre ASCII #i BCD este foarte simpl". Formatul BCD compactat este mai eficient dect ASCII din moment ce fiecare octet poate stoca doi digi!i zecimali. Dar cam aici se ncheie lista avantajelor. n mod normal, datele numerice sunt reprezentate n binar. Este limbajul nativ al calculatorului. Intern, acesta efectueaz" toate opera!iile aritmetice #i logice numai cu date reprezentate n binar. Procesarea numeric" n binar este mult mai eficient" n compara!ie cu celelalte reprezent"ri. Cnd aplica!iile folosesc prelucr"ri numerice semnificative, versiunea binar" e singura op!iune viabil". Pe de alt" parte, tot ce introducem de la tastatur" sau afi#"m la monitor este n format text. Iar formatul text nseamn" ASCII. De aceea se impune un proces de conversie. Datele primite de la tastatur" sunt convertite n binar, prelucrate intern, apoi reconvertite

n ASCII !i afi!ate la ecran. Aceste translat"ri necesit" un efort suplimentar din partea programatorului, dar numerele sunt procesate mult mai eficient n form" binar" !i, n final, se ajunge la un c!tig de performan#".

10.3.4.

Conversia ASCII binar

Urm"torul program cere dou" numere de la tastatur", calculeaz" suma !i afi!eaz" rezultatul. ; ;suma.asm ; %include io.inc section .data msg_numar1 db "Introduceti primul numar: ",0 msg_numar2 db "Introduceti al doilea numar: ",0 msg_rez db "Suma este: ",0 msg_eroare db "A aparut transport!",0 section .bss numar1 resd 1 ;stocheaza primul numar numar2 resd 1 ;stocheaza al doilea numar rez resd 1 ;stocheaza rezultatul section .text global _start _start: nop WriteStr msg_numar1 ReadInt [numar1] WriteStr msg_numar2 ReadInt [numar2] ;; calculeaza suma mov eax,[numar1] add eax,[numar2] mov [rez],eax ;; verifica daca a aparut transport jno fara_transport WriteStr msg_eroare nwln jmp sfarsit

;; afiseaza rezultatul fara_transport: WriteStr msg_rez WriteInt [rez] nwln sfarsit: Exit Pe lng! func"iile declarate n io.inc, programul mai folose#te dou!: f_ReadInt #i f_WriteInt. Prima cite#te de la tastatur! un #ir de caractere, l converte#te n num!r, #i ntoarce rezultatul n registrul EAX. A doua preia un num!r din registrul EAX, l converte#te n #ir de caractere, #i afi#eaz! rezultatul la monitor. Pentru citirea de la tastatur! #i afi#area la monitor sunt folosite procedurile cunoscute f_ReadStr #i f_WriteStr. A#adar, n paragrafele urm!toare ne vom concentra aten"ia asupra conversiei caracter - valoare binar!. Dar, mai nti s! introducem n io.inc macroinstruc"iunile care le corespund: extern f_ReadInt extern f_WriteInt %macro WriteInt 1 push EAX mov EAX,%1 call f_WriteInt pop EAX %endmacro %macro ReadInt 1 %ifnidni %1,EAX push EAX call f_ReadInt mov %1,EAX pop EAX %else call f_ReadLInt %endif %endmacro %ifidn (if identity) este o directiv! a asamblorului YASM care testeaz! dac! textul introdus este identic cu cel declarat. Construc"ia %ifidn text1,text2 va determina asamblarea codului ce o urmeaz! numai #i numai dac! text1 #i

text2, dup! expandarea liniei respective, sunt buc!"i identice de text. Spa"iile albe nu sunt luate n considerare. %ifidni (if identity insensitive) este similar! lui %ifdni numai c! nu este sensibil! la litere mari sau mici. %ifnidn (if not identity) este forma negativ! a lui %ifidn. Evident, exist! #i varianta %ifnidni. Toate fac parte din familia directivelor de asamblare condi"ionat! (directive folosite de preprocesorul YASM). Directivele de asamblare condi"ionat! permit asamblarea unor sec"iuni numai n cazurile n care sunt ndeplinite anumite condi"ii. Sintaxa general! este: %if <condi!ie1> ;intruc"iuni asamblate numai n cazul ndeplinirii <condi"ie1> %elif <condi!ie2> ;instruc"iuni asamblate numai n cazul nendeplinirii <condi"ie1> #i ndeplinirii <condi"ie2> %else ;instruc"iuni asamblate dac! nu este ndeplinit! nicio condi"ie anterioar! %endif A#a se explic! #i apari"ia %else #i %endif din macroinstruc"iunea noastr!. Similar, sunt posibile #i expresiile %elifidn, %elifnidn, %elifidni #i %elifnidni. Preprocesorul YASM implementeaz! o gam! larg! de directive foarte utile.21

10.3.5.

Conversia caracterelor ASCII n binar

Func"ia f_ReadInt cite#te de la tastatur! un #ir de caractere ce reprezint! un num!r ntreg cu semn #i returneaz! valoarea numeric! n registrul EAX. Partea esen"ial! a func"iei converte#te o secven"! de digi"i de intrare da"i n format ASCII la echivalentul lor binar. Procesul de conversie implic! nmul"irea repetat! cu 10. Presupunem c! trebuie s! convertim #irul de caractere '475' n echivalentul s!u numeric 475. '475' nseamn! 343735H. Valoarea numeric! a fiec!rei cifre n parte se ob"ine simplu, prin sc!dere cu 30H. n acest caz, algoritmul este:
Digit de intrare Valoare numeric! Valoare ini"ial! '4' (34H) 4 '7' (37H) 7 '5' (35H) 5
21

Num!r = num!r " 10 + valoare numeric! 0 0 $ 10 + 4 = 4 4 $ 10 + 7 = 47 47 $ 10 + 5 = 475

http://www.nasm.us/doc/nasmdoc4.html

Deoarece num!rul este reprezentat pe 32 de bi"i, plaja de valori este cuprins! ntre 2.147.483.648 #i +2.147.483.647. Dac! introducem valorile maxime, pe lng! caracterul de semn vom avea nc! 10 coduri numerice. Un total de 11. Deoarece func"ia f_ReadStr adaug! la sfr#it un caracter NULL, num!rul maxim de caractere valid este 12. Algoritmul prezentat, tradus n linii de instruc"iuni, arat! astfel: .citeste_caracter: ;;furniz!m func"iei f_ReadStr parametri de intrare: registrul ESI specific! num!rul de caractere presupus a fi citit de la tastatur!, iar EDI adresa buffer-ului la care vor fi stocate caracterele. mov esi,0x10 ;buffer de 16 caractere. Acesta poate fi orict de mare, dar, din moment ce num!rul maxim va avea 12 caractere, 16 este acoperitor. mov edi,buffer call f_ReadStr mov esi,buffer ;ncarc! adresa bufferului n ESI .converteste_caracter: mov cl,byte [esi] ;ncarc! caracterul n CL cmp cl,0x0 ;NULL? je .sfarsit_conversie ;dac! da, #irul de caractere s-a sfr#it cmp al,0x30 ;comparam cu '0' jb .caracter_invalid ;caracter < '0' => nu este caracter numeric cmp al,0x39 ;comparam cu '9' ja .caracter_invalid ;caracter > '9' => nu este caracter numeric sub cl,0x30 ;convertim ASCII la numeric mul ebx ;nmul"im EAX cu 10 jb .depasire_nr_caractere ;apari"ia unui transport nseamn! dep!#irea domeniului de reprezentare. Se afi#eaz! mesaj de dep!#ire. add eax,ecx ;adun!m digitul curent jb .depasire_nr_caractere ;apari"ia unui transport n urma opera"iei de adunare nseamn! dep!#ire. cmp eax,0x80000000 ;compar! cu valoarea maxim! ja .depasire_nr_caractere ;dac! EAX > 2.147.483.648, num!rul dep!#e#te plaja de valori inc esi ;urm!torul caracter ;; reintr! n bucla de conversie. Din bucl! se iese atunci cnd se ajunge la caracterul NULL. jmp .converteste_caracter

.sfarsit_conversie: Acesta este algoritmul de conversie propriu-zis. Observa!i c" verific"m validitatea caracterelor din buffer. Un lucru la care nu ne-am gndit nainte. Dar, la o privire mai atent", secven!a are totu#i o problem". De fapt, mai multe. Utilizatorul poate introduce numere negative. n definitiv, putem aduna 30 cu -20. n acest caz, #irul de caractere '20' va fi precedat de caracterul '-'. Sau, dintr-un exces de precizie, utilizatorul poate specifica explicit semnul numerelor pozitive (de ex, +30) sau poate introduce spa!ii albe naintea caracterelor numerice. Aceste posibilit"!i trebuie adresate. n plus, v" aduce!i aminte c" num"rul are maxim 12 caractere. Un num"r cu mai mult de 12 caractere nu poate fi reprezentat, a#adar este invalid. Secven!a urm"toare de instruc!iuni trebuie s" apar" n cod imediat dup" introducerea caracterelor n buffer. .sarim_peste_spatii: inc esi cmp byte [esi],0x20 je .sarim_peste_spatii urm"torul caracter ;urm"torul caracter ;Spa!iu? ;dac" da, ignor"-l #i treci la

Bucla .sarim_peste_caractere este ntrerupt" de primul caracter diferit de caracterul de spa!iu. Din acest moment #tim c" #irul nu este precedat de spa!ii. .sir_fara_spatii: ;;Num"rul reprezentat pe 32 de bi!i are maxim 12 caractere (caracter de semn, 10 caractere numerice, caracter NULL). mov ecx,0xc ;contorizeaz" nr. de caractere prelucrate mov al,byte [esi] ;ncarc" n AL primul caracter cmp al,0x2b ;comparam cu semnul + je .caracter_valid ;dac" este +, atunci caracter valid cmp al,0x2d ;comparam cu semnul je .caracter_valid .caracter_valid: inc esi ;urm"torul caracter dec ecx ;decrement"m ECX jcxz .depasire_nr_caractere .caracter_invalid: Dac" ECX = 0 #i nu am terminat de parcurs #irul, nseamn" c" num"rul este prea mare pentru a putea fi reprezentat pe 32 de bi!i. Condi!ia a fost testat" cu

JCXZ. Deoarece instruc!iunea DEC nu seteaz" indicatorii de stare, nu putem folosi JZ. .depasire_nr_caractere: push ecx ; salveaz" ECX n stiv" ;;ncarc" n ECX adresa mesajului de dep"#ire, afi#at cu f_WriteStr mov ecx,mesaj_depasire call f_WriteStr pop ecx ;extrage ECX jmp .citeste_caracter ;reia procesul de citire Dac" primul caracter este invalid, semnal"m evenimentul #i relu"m procesul de citire. .niciun_caracter_valid: push ecx mov ecx,mesaj_lipsa_numar call f_WriteStr pop ecx jmp .citeste_caracter ;reia procesul de citire n acest moment putem n!elege listingul integral. n plus, parcurgem procedura pentru cazul n care am introdus num"rul -475 precedat de dou" caractere de spa!iu. ; ;f_ReadInt.asm ; section .data mesaj_depasire db "Depasire domeniu de reprezentare",0 mesaj_lipsa_numar db "Nu ati introdus niciun numar!",0 section .bss buffer resb 256 section .test extern f_ReadStr extern f_WriteStr global f_ReadInt f_ReadInt: push ebx push ecx

push edx push esi push edi pushf .citeste_caracter: mov esi,0x10 mov edi,buffer call f_ReadStr ;;deoarece am introdus dou! spa"ii #i '-''4''7''5', bufferul con"ine 7 caractere, ultimul este caracterul NULL, introdus de func"ia de citire. ;; 0x20 0x20 0x2d 0x34 0x37 0x35 NULL mov esi,buffer ;ncarc! adresa bufferului n ESI ;; 0x20 0x20 0x2d 0x34 0x37 0x35 NULL ;; ;; ;;ESI dec esi .sarim_peste_spatii: inc esi cmp byte [esi],0x20 je .sarim_peste_spatii ;; 0x20 0x20 0x2d 0x34 0x37 0x35 NULL ;; ;; ;; ESI mov edi,esi ;salvam adresa de nceput n EDI .sir_fara_spatii: mov ecx,0xc ;; 0x20 0x20 0x2d 0x34 0x37 0x35 NULL ;; ;; ;;ECX = 12 ESI = EDI mov al,byte [esi] cmp al,'+' je .caracter_valid cmp al,'-' je .caracter_valid .testeaza_caracter: cmp al,0x30 jb .caracter_invalid cmp al,0x39 ja .caracter_invalid

.caracter_valid: inc esi dec ecx ;; 0x20 0x20 0x2d 0x34 0x37 0x35 NULL ;; ;; ;;ECX = 11 EDI ESI jcxz .depasire_nr_caractere mov al,byte [esi] ;ncarc! n AL urm!torul caracter jmp .testeaza_caracter ;;napoi la eticheta .testeaz!_caracter. Din aceast! bucl! se iese cnd num!rul de caractere dep!"e"te 12 sau cnd se ajunge la caracterul NULL. A"adar, por#ile de ie"ire din bucl! sunt reprezentate de etichetele .depasire_nr_ caractere sau .caracter_invalid. .depasire_nr_caractere: push ecx mov ecx,mesaj_depasire call f_WriteStr pop ecx jmp .citeste_caracter .niciun_caracter_valid: push ecx mov ecx,mesaj_lipsa_numar f_WriteStr pop ecx jmp .citeste_caracter ;s!ri la nceput ;;la primul caracter invalid se ajunge aici. Primul caracter invalid poate fi caracterul NULL, a"a cum ne a"tept!m, sau poate fi orice alt caracter (de ex., utilizatorul introduce 687a). De aceea, prima instruc#iune din bucl! are grij! s! introduc! caracterul NULL pe pozi#ia primului caracter invalid. ;;n cazul nostru, se iese din bucl! cnd ajungem la caracterul NULL. ;; 0x20 0x20 0x2d 0x34 0x37 0x35 NULL ;; ;; ;;ECX = 8 EDI ESI .caracter_invalid: mov byte [esi],0x0 ;introduce caracterul NULL cmp ecx,0xc ;dac! ECX = 12, nseamn! c! este

vorba de primul caracter. Dac! primul caracter este invalid, afi"!m mesaj. je .niciun_caracter_valid mov esi,edi ;dac! ECX != 12, avem un num!r valid. n acest caz, reintroducem adresa primului caracter n ESI "i preg!tim registrele pentru conversia ASCII - binar. xor eax,eax ;EAX = 0 xor ecx,ecx ;ECX = 0 mov ebx,0xa ;EBX con#ine multiplicatorul ;; 0x20 0x20 0x2d 0x34 0x37 0x35 NULL ;; ;; ;;ECX = 0 ESI = EDI mov cl,byte [esi] ;ncarc! n CL primul caracter cmp cl,'-' ;semnul - ? je .sari_semn ;da, s!ri peste caracterul de semn cmp cl,'+' ;semnul + ? jne .converteste_caracter ;nu este caracter de semn; s!ri la bucla de conversie .sari_semn: inc esi ;s!ri peste semn ;; 0x20 0x20 0x2d 0x34 0x37 0x35 NULL ;; ;; ;;CL = 0x2d EDI ESI ;;conversia ASCII - binar .converteste_caracter: mov cl,byte [esi] cmp cl,0x0 je .sfarsit_conversie sub cl,0x30 mul ebx jb .depasire_nr_caractere add eax,ecx jb .depasire_nr_caractere cmp eax,0x80000000 ja .depasire_nr_caractere inc esi ;urm!torul caracter jmp .converteste_caracter ;;n acest moment num!rul este n registrul EAX ;; 0x20 0x20 0x2d 0x34 0x37 0x35 NULL ;;

;; ;;CL = NULL EDI ESI .sfarsit_conversie: mov esi,edi ;ncarc! n ESI adresa de nceput a "irului mov cl,byte [esi] ;ncarc! n CL primul caracter ;; 0x20 0x20 0x2d 0x34 0x37 0x35 NULL ;; ;; ;;CL = 0x2d ESI = EDI ;;verific!m dac! EDX este zero. Dac! este diferit de zero nseamn! c! num!rul a dep!"it domeniul de reprezentare. cmp edx,0x0 jne .depasire_nr_caractere ; cmp eax,0x80000000 jb .numar_OK ;nr. < 2.147.483.648, valid. cmp cl,0x2d ;negativ? jne .depasire_nr_caractere ;Pozitiv. Num!rul pozitiv nu trebuie s! fie mai mare de 2.147.483.647. Cum aici s-a ajuns deoarece nr. > 2.147.483.648, nseamn! c! a fost dep!"it! plaja de valori. .numar_OK: ;num!r < 2.147.483.648. cmp cl,0x2d ;negativ? jne .sfarsit ;pozitiv => utilizatorul a introdus un num!r pozitiv, f!r! semn explicit. neg eax ;negativ => calcul!m complementul fa#! de doi. .sfarsit: popf pop edi pop esi pop edx pop ecx pop ebx ret

10.3.6.

Conversia numerelor din binar n ASCII

Procedura f_WriteInt afi"eaz! pe ecran un ntreg de 32 de bi#i aflat n registrul EAX. Func#ia separ! digi#ii individuali ai num!rului "i i converte"te n reprezent!ri ASCII. Separarea digi#ilor individuali se face prin mp!r#ire la 10. Etapele implicate n procesul de conversie sunt exemplificate prin conversia num!rului 475.

475 / 10 47 / 10 4 / 10

Ct 47 4 0

Rest 5 + 30H 7 + 30H 4 + 30H

Valoare ASCII 35H 37H 34H

Apar cteva probleme: Prima const! n faptul c! ob"inem digi"ii n ordine invers!. n consecin"!, ace#tia trebuie introdu#i n buffer n ordine invers! ncepnd din partea dreapt! (sfr#itul bufferului). Dar, mai nainte, trebuie s! introducem caracterul NULL, astfel nct procedura de afi#are s! recunoasc! finalul #irului. Bufferul are 12 caractere: caracterul de semn, 10 caractere numerice, caracterul NULL. A doua problem! este legat! de semn. Dac! num!rul este negativ, trebuie afi#at semnul minus. Depistarea semnului se face prin comparare cu zero. Dac! valoarea din EAX este mai mic! dect zero, nseamn! c! num!rul este negativ. n acest caz, trebuie s! introducem pe prima pozi"ie din buffer caracterul '-' #i s! calcul!m complementul fa"! de doi al num!rului. Dac! num!rul este pozitiv, folosim caracterul spa"iu (afi#area obi#nuit! a numerelor pozitive), iar valoarea r!mne neschimbat!. Prezent!m procedura. Presupunem c! n registrul EAX se afl! valoarea 0xFFFFFF15 (num!rul negativ -235). ; ;f_WriteInt.asm ; section .bss buffer resb 100 section .text extern f_WriteStr global f_WriteInt f_WriteInt: pusha mov esi,buffer ;adresa de nceput a buffer-ului mov byte [esi],0x20 ;introduce caracterul de spa"iu n primul octet al buffer-ului ;;Buffer: 0x20 _ _ _ _ _ _ _ _ _ _ _ _ ;; ;;

;;

ESI cmp eax,0x0 ;verific!m semnul jge .numar_pozitiv ;pozitiv mov byte [esi],0x2d ;n caz c! num!rul este negativ rescrie primul octet al bufferului cu semnul '-'. In acest mod, la sfarsit stim daca numarul este pozitiv sau negativ. neg eax ;calculeaza complementul fata de 2 ;;Buffer: 0x2d _ _ _ _ _ _ _ _ _ _ _ _ ;; ;; ;; ESI, EAX = 0xEB (235) .numar_pozitiv: ;numar pozitiv mov ebx,0xa ;divizorul add esi,0xb ;s!rim la adresa ultimului caracter (ESI + 11) mov byte [esi],0x0 ;introducem un caracter NULL dec esi ;;Buffer: 0x2d _ _ _ _ _ _ _ _ _ _ _ NULL ;; ;; ;;EAX = 0xEB (235) ESI mov ecx,0xa ;contoriz!m num!rul de caractere procesate .converteste_numar: mov edx,0x0 ;EDX = 0 div ebx ;mp!r"im EDX:EAX la EBX add dl,0x30 ;restul din DL se transform! n caracter mov byte [esi],dl ;se introduce pe prima pozitie din dreapta a numarului ;;Buffer: 0x2d _ _ _ _ _ _ _ _ _ _ 0x35 NULL ;; ;; ;;EAX = 23 ESI dec esi ;se decremeanteaza ESI dec ecx ;ECX este contorul, num!rul nu trebuie s! dep!#easc! 11 cifre cmp eax,0x0 ;se compar! EAX cu zero ;;Buffer: 0x2d _ _ _ _ _ _ _ _ _ _ 0x35 NULL ;; ;;

;;EAX = 23, ECX = 10 ESI jne .converteste_numar de conversie

;dac! nu este egal reintr!m n bucla

;;La ie"irea din bucla de conversie: ;;Buffer: 0x2d _ _ _ _ _ _ _ _ 0x32 0x33 0x35 NULL ;; ;; ;;EAX = 0, ECX = 7 ESI jcxz .afiseaza_numar ;dac! EAX = 0 "i ECX = 0 num!rul este format din toate cele 10 caractere. ;;Dac! nu are 10 caractere, trebuie s! copiem semnul. Acesta este "i cazul nostru. mov bl,byte [buffer] ;compar! BL cu primul octet din buffer. Acesta poate fi 0x20 pentru num!r pozitiv "i 0x2d pentru num!r negativ mov byte [esi],bl ;copiaz! semnul la pozi#ia curent! ;;Buffer: 0x2d _ _ _ _ _ _ _ 0x2d 0x32 0x33 0x35 NULL ;; ;; ;;EAX = 0, ECX = 7 ESI cmp bl,0x20 ;dac! semnul este 0x20 atunci este num!r pozitiv "i nu trebuie s! afi"!m semnul. jne .afiseaza_numar ;dac! este negativ nseamn! c! putem afi"a semnul. inc esi .afiseaza_numar: mov ecx,esi call f_WriteStr popa ret Asambl!m programul suma.asm "i gener!m executabilul suma: yasm -f elf -g stabs suma.asm yasm -f elf -g stabs f_WriteStr.asm yasm -f elf -g stabs f_ReadStr.asm yasm -f elf -g stabs f_WriteInt.asm yasm -f elf -g stabs f_ReadInt.asm yasm -f elf -g stabs f_nwln.asm ld -o suma suma.o f_WriteStr.o f_nwln.o f_ReadStr.o f_ReadInt.o f_WriteInt.o melf_i386

10.4. Biblioteci de func!ii


Modularizarea, ca metod! de rezolvare a problemelor legate de cre"terea dimensiunii programelor, introduce, la rndul ei, o nou! problem!, de data aceasta, n procesul de generare a executabilului. Num!rul mare de module complic! procesul de asamblare "i editare de leg!turi, structura fi"ierului makefile, "i aglomereaz! directorul ce con#ine fi"ierele surs! "i obiect. n momente precum cele de la sfr"itul sec#iunii precedente, cnd a fost nevoie s! execut!m un num!r apreciabil de comenzi pentru generarea unui singur executabil, ncepem s! ne gndim cum putem scrie toate modulele ntr-un singur fi"ier. Una din posibilit!#ile de rezolvare pe care le avem la dispozi#ie const! n folosirea unor fi"iere bibliotec!, sau simplu, biblioteci. O bibliotec! este un fi"ier care con#ine un num!r oarecare de module obiect. n etapa de editare de leg!turi poate fi utilizat! ca entitate de sine st!t!toare. n mod obi"nuit, biblioteca este indexat!, astfel nct simbolurile con#inute (func#iile, datele, etc.) s! poat! fi g!site cu u"urin#!; indexul indic! modulul care con#ine defini#ia unui anumit nume de simbol. Din acest motiv, legarea unui program de module obiect aflate n biblioteci este mai rapid! dect legarea programului de fi"iere obiect aflate pe disc. De asemenea, utilizarea bibliotecilor presupune deschiderea unui singur fi"ier. Acest lucru cre"te "i mai mult viteza procesului de editare a leg!turilor. n Linux, la fel ca n toate sistemele de operare moderne, dispunem de dou! posibilit!#i prin care putem lega modulele bibliotecilor de programele principale. Prima metod! se nume"te legare static! (static linking). Legarea static! introduce modulul obiect al unei biblioteci direct n fi"ierul executabil. Indiferent dac! o func#ie definit! n acel modul obiect este utilizat! sau nu, codul s!u va face parte din executabil. Acest lucru poate crea executabile de mari dimensiuni "i poate duce la consum mare de memorie atunci cnd rul!m n acela"i timp mai multe instan#e ale programului (fiecare instan#! are propria copie pentru aceea"i func#ie). A doua metod! se nume"te legare dinamic! (dynamic linking). Legarea dinamic! permite programelor s! adreseze func#iile definite n biblioteci f!r! a insera codul acestora n executabil. Bibliotecile legate dinamic pot fi partajate de mai multe procese. Dac! un proces nou are nevoie de simboluri definite de o bibliotec! aflat! deja n memorie, poate folosi aceea"i instan#! a bibliotecii. Legarea dinamic! permite consum de memorie redus "i face posibil! generarea unor fi"iere executabile de dimensiuni mai mici, salvnd spa#iu pe disc.

10.4.1.

Crearea bibliotecilor statice

Bibliotecile statice sunt simple colec#ii de fi"iere obiect obi"nuite (deoarece sunt simple pachete de fi"iere obiect, se mai utilizeaz! "i termenul de arhiv!).

Aceast! colec"ie este creat! cu ajutorul programului ar (archiver). Prin conven"ie, bibliotecile statice ncep cu lib #i au extensia .a. Pentru a crea o bibliotec! static! sau pentru a ad!uga un fi#ier obiect la o bibliotec! static! existent! se folose#te o comand! de genul: ar -crs libioapi.a f_nwln.o f_WriteStr.o f_ReadStr.o f_WriteChar.o f_ReadChar.o f_WriteInt.o f_ReadInt.o unde op"iunile: -c creaz! o arhiv!, -r insereaz! n acea arhiv! fi#ierele obiect specificate, -s creaz! un index pentru arhiv!. n exemplul de mai sus a fost creat! o bibliotec! static! numit! libioapi.a, care con"ine copii ale fi#ierelor obiect prezente n comand!. Evident, fi#ierele obiect trebuie generate nainte printr-un proces de asamblare. Comanda ar permite, pe lng! alte op"iuni descrise n paginile de manual, #i afi#area modulelor con"inute de bibliotec!: ar t libioapi.a f_nwln.o f_WriteStr.o f_ReadStr.o f_WriteChar.o f_ReadChar.o f_WriteInt.o f_ReadInt.o Indexul poate fi listat cu ajutorul comenzii: nm libioapi.a Editarea leg!turilor cu programul se face prin op"iunea -l. Aceasta specific! numele bibliotecii utilizate de program. De asemenea, se poate utiliza op"iunea L, care specific! directorul n care se afl! biblioteca ('.', se refer! la directorul curent). ld o suma suma.o -L. -lioapi -melf_i386 Ordinea arhivelor n linia de comand! este important!. Pentru fiecare arhiv! ntlnit! n linia de comand!, asamblorul verific! dac! aceasta define#te vreun simbol cerut de fi#ierele obiect specificate naintea ei pe linia de comand!.

Dac! define"te vreun simbol necesar, modulul obiect respectiv este copiat n executabil. De aceea, bibliotecile trebuie specificate la sfr"itul liniei de comand!22.

10.4.2.

Crearea bibliotecilor partajate

Bibliotecile partajate se ob#in printr-un proces asem!n!tor celui descris anterior: asamblarea unei colec#ii de fi"iere obiect "i nglobarea lor ntr-un fi"ier partajat. Dar, spre deosebire de o bibliotec! static! - arhiv! de fi"iere obiect ce pot fi copiate individual n executabil, n func#ie de simbolurile necesare programului principal (fi"ierele obiect care nu con#in simboluri adresate de program nu sunt copiate n corpul executabilului) -, o bibliotec! partajat! nu este o arhiv!. Codul modulelor obiect este practic uniformizat ntr-un singur fi"ier obiect. n consecin#!, nc!rcarea n memorie a bibliotecii partajate implic! nc!rcarea n totalitate a codului definit n corpul s!u. Din faptul c! o bibliotec! partajat! este un fi"ier obiect rezult! alt! consecin#! important!. Cnd gener!m fi"iere obiect, nu cunoa"tem adresa de memorie la care vor fi nc!rcate. Pentru un fi"ier executabil, segmentele de cod "i date ncep la o adres! virtual! cunoscut! dinainte. Codul executabil nu este partajat "i fiecare executabil prime"te propriul spa#iu de adrese. Acest lucru nseamn! c! editorul de leg!turi cunoa"te exact unde se va afla sec#iunea de date n memorie "i o va putea adresa direct. Bibliotecile nu cunosc astfel de garan#ii. Sec#iunea lor de date se va afla la un anumit deplasament specificat fa#! de adresa de baz!; dar exact unde se afl! aceast! adres! nu se poate cunoa"te dect la lansarea n execu#ie. n concluzie, toate bibliotecile trebuie s! con#in! cod capabil de a fi executat indiferent de pozi#ia sa n memorie, cunoscut sub denumirea de cod independent de pozi!ie (PIC Position Independent Code). Re#ine#i c! sec#iunea de date se afl! tot la un deplasament fix fa#! de sec#iunea de cod, dar pentru a g!si adresa efectiv! a datelor, deplasamentul trebuie adunat cu adresa la care se ncarc! biblioteca n memorie. Din acest motiv, procesul de legare dinamic! are loc n dou! etape: prima, la momentul edit"rii leg"turilor, editorul de leg!turi verific! faptul c! toate simbolurile necesare programului se reg!sesc n program sau n una din bibliotecile sale partajate. Simbolurile din bibliotecile partajate nu sunt incluse n fi"ierul executabil final, ci numai etichetate. A"adar, editorul de leg!turi las! n urm! referin#e care trebuie completate cu informa#ii disponibile numai la momentul nc!rc!rii n memorie (de ex., adresa unei func#ii dintr-o bibliotec!). Aceste referin#e se numesc reloc"ri. n a doua etap!, la lansarea n execu!ie a programului principal (runtime), un alt program din sistem, numit editor de leg"turi dinamic
22

Specifica#i fi"ierul suma.o la sfr"itul comenzii ld "i observa#i rezultatul.

(spre deosebire de cel anterior, denumit !i editor de leg!turi static) ncarc" n memorie bibliotecile cu legare dinamic" !i completeaz" adresele referin#elor (procesul de rezolvare a reloc"rilor). Adresele la care editorul de leg"turi dinamic ncarc" n memorie bibliotecile partajate nu sunt cunoscute dinainte. Pur !i simplu, pentru fiecare bibliotec" necesar" programului, editorul dinamic g"se!te o zon" de memorie convenabil". Acest mecanism, mpreun" cu cel de memorie virtual", face posibil ca mai multe programe s" foloseasc" acela!i cod. Avantajul major al bibliotecilor partajate const" n faptul c" d" posibilitatea mai multor programe s" foloseasc" acela!i cod (prin partajarea paginilor de memorie). Tabelul deplasamentului global Dar bibliotecile partajate pot con#ine la rndul lor reloc"ri. Dac" editorul de leg"turi dinamic modific" codul unei biblioteci partajate, conform unei reloc"ri, acel cod nu mai poate fi partajat, !i pierdem avantajul utiliz"rii bibliotecilor partajate. Imagina#i-v" c" editorul de leg"turi dinamic trebuie s" completeze n sec#iunea de cod adresa unui simbol de date. Folosind mecanismul reloc"rilor, editorul de leg"turi dinamic afl" adresa de memorie a acestuia !i rescrie codul bibliotecii partajate. Din acest moment codul nu mai poate fi partajat. Pentru a evita rescrierea codului, s-a stabilit ca editorul de leg"turi dinamic s" rezerve o zon" din executabil special pentru memorarea adreselor de simboluri !i s" scrie adresa acolo. n acest mod, codul nu trebuie modificat. Zona rezervat" adreselor de simbol se nume!te tabelul deplasamentului global (GOT Global Offset Table). GOT este privat fiec"rui proces !i con#ine adresele absolute ale datelor private (locale). Numai procesul care l de#ine are drepturi de scriere asupra lui. Sec#iunea de date a unei biblioteci partajate nu are aceste restric#ii: din moment ce sec#iunea de date are drepturi de scriere, ea trebuie copiat" oricum n memorie (mai degrab" dect paginat") !i att timp ct este copiat" ea poate fi !i relocat". Tabelul de c!utare al procedurii Bibliotecile partajate con#in multe func#ii, iar programul poate include numai o parte din ele. Chiar !i a!a, n func#ie de instruc#iunile de salt, programul poate utiliza numai unele din cele incluse. A!a cum am v"zut, procesul de legare dinamic" folose!te resurse consistente, implic" nc"rcarea codului n memorie, c"utarea n mai multe tabele !i scrierea adreselor. Orice mecanism care optimizeaz" acest proces duce la o cre!tere de performan#". Tabelul de c"utare a procedurii (PLT Procedure Lookup Table) pune la dispozi#ie legarea ntrziat! (lazy binding). Legarea este sinonim" cu procesul de rezolvare a reloc"rilor pentru datele locale din GOT. Cnd se completeaz" o intrare n PLT se spune c" func#ia a fost

legat! de adresa real!. Procesul de legare a func"iilor consum! resurse la rndul s!u, de aceea, acesta este ntrziat pn! la momentul n care func"ia este apelat!. Fiecare func"ie din bibliotec! are o intrare n PLT care, ini"ial, adreseaz! un cod inactiv. Cnd programul apeleaz! func"ia, acesta apeleaz! de fapt o intrare n PLT (n acela#i mod ca datele referite prin GOT). Codul inactiv va transfera editorului dinamic un num!r de parametri cu ajutorul c!rora acesta afl! adresa real! a func"iei. Adresa real! nlocuie#te codul inactiv, astfel nct, la urm!torul apel, func"ia este nc!rcat! f!r! ajutorul editorului dinamic. Dac! o func"ie nu este utilizat!, intrarea PLT nu va fi niciodat! modificat!. Suport YASM pentru codul independent de pozi!ie Codul independent de pozi"ie presupune ca asamblorul s! poat! efectua reloc!rile prezentate n sec"iunile anterioare. YASM le implementeaz! prin intermediul operatorului WRT. Totodat!, pentru a ob"ine tipurile de reloc!ri necesare, YASM define#te cinci simboluri speciale. Aceste simboluri sunt utilizate la dreapta operatorului WRT. Ace#tia sunt ..gotpc, ..gotoff, ..got, ..plt #i ..sym. Ob!inerea adresei GOT Pentru a putea fi g!sit la nc!rcare, GOT este situat la o distan"! constant! fa"! de sec"iunea de cod a bibliotecii partajate. Numele de simbol standard prin care YASM se refer! la GOT este _GLOBAL_OFFSET_TABLE_. Fiecare modul al bibliotecii partajate trebuie s! defineasc! GOT ca simbol extern, astfel: extern _GLOBAL_OFFSET_TABLE_ La nceputul fiec!rei func"ii care trebuie s! acceseze sec"iunile DATA sau BSS, trebuie nti s! se calculeze adresa GOT. Acest lucru se face de obicei prin scrierea func"iei sub urm!toarea form!: func: push ebp mov ebp,esp push ebx call .get_GOT .get_GOT: pop ebx add ebx,_GLOBAL_OFFSET_TABLE_+$$-.get_GOT wrt ..gotpc ;corpul func"iei

mov ebx,[ebp-4] mov esp,ebp pop ebp ret Primele dou! linii ale func"iei reprezint! prologul C standard, destinat cre!rii cadrului de stiv!, iar ultimele trei linii formeaz! epilogul C standard. A treia #i a patra linie de la sfr#it salveaz! #i restaureaz! registrul EBX, deoarece bibliotecile partajate scrise n cod independent de pozi"ie folosesc acest registru pentru memorarea adresei GOT. Partea important! este format! din instruc"iunea CALL #i urm!toarele dou! linii. Combina"ia CALL #i POP ob"ine adresa etichetei .get_GOT, f!r! a fi necesar s! cuno#tem dinainte adresa la care va fi nc!rcat programul (instruc"iunea CALL este codificat! relativ la pozi"ia curent!). Instruc"iunea POP ncarc! n registrul EBX adresa etichetei .get_GOT (pozi"ia curent!). Instruc"iunea ADD utilizeaz! unul din tipurile speciale de relocare, GOTPC. Referirea la simbolul care marcheaz! nceputul GOT prin wrt ..gotpc se finalizeaz! cu ob"inerea distan"ei ntre cmpul operand al instruc"iunii ADD #i adresa GOT. De aceea este necesar s! adaug!m la rezultat adresa de nceput a sec"iunii curente, reprezentat! prin dou! simboluri $$, #i s! sc!dem distan"a ntre adresa sec"iunii curente #i adresa .get_GOT, aflat! deja n registrul EBX. La sfr#itul instruc"iunii ADD, EBX con"ine adresa de nceput a GOT. Modific!m codul func"iei f_nwln.asm astfel nct s! devin! independent de pozi"ie. ; ;func!ia f_nwln , PIC ; extern _GLOBAL_OFFSET_TABLE_ section .data new_line: db 0xa section .text global f_nwln:function f_nwln: push ebp mov ebp,esp push ebx call .get_GOT .get_GOT: pop ebx

add ebx,_GLOBAL_OFFSET_TABLE_+$$-.get_GOT wrt ..gotpc lea esi,[ebx + new_line wrt ..gotoff] mov eax,4 mov ebx,1 mov ecx,esi mov edx,1 int 80h mov ebx,[ebp-4] mov esp,ebp pop ebp ret Adresa GOT poate fi folosit! la ob"inerea adresei elementelor de date. Majoritatea acestora se vor afla n sec"iunile declarate local; ele pot fi accesate prin intermediul tipului special ..gotoff. Instruc"iunea arat! astfel: lea esi,[ebx + new_line wrt ..gotoff] Expresia new_line wrt ..gotoff este evaluat! la momentul edit!rii leg!turilor dinamice ca fiind distan"a de la nceputul GOT la variabila local! new_line. Adunarea cu adresa GOT din EBX va rezulta n ESI adresa loca"iei new_line. Dac! declar!m variabile de tip global f!r! s! le asociem o dimensiune, ele sunt partajate ntre modulele bibliotecii, dar nu sunt exportate c!tre programul care a nc!rcat biblioteca. Acestea se vor afla n sec"iunile DATA #i BSS ca de obicei, astfel nct s! le putem accesa n acela#i mod precum variabilele locale, folosind mecanismul ..gotoff. Adresarea elementelor de date externe !i comune Dac! biblioteca trebuie s! adreseze o variabil! extern! (extern! bibliotecii, nu doar a unuia din modulele sale), folosim tipul special ..got. Tipul ..got, n loc s! furnizeze deplasamentul dintre adresa de baz! GOT #i elementul de date, returneaz! deplasamentul dintre adresa de baz! GOT #i o nregistrare (intrare) GOT care con"ine adresa elementului de date. Editorul de leg!turi static va configura aceast! intrare GOT la crearea bibliotecii, iar la momentul nc!rc!rii n memorie editorul de leg!turi dinamic va plasa n ea adresa corect!. A#adar, pentru a ob"ine n EAX adresa unui element de date extern new_line, trebuie s! folosim instruc"iunea: mov eax,[ebx + new_line wrt ..got]

Aceasta ncarc! adresa new_line ntr-o intrare din GOT. Editorul static, atunci cnd creaz! biblioteca partajat!, colecteaz! mpreun! toate reloc!rile de tip ..got "i construie"te GOT astfel nct s! se asigure c! acesta prezint! toate intr!rile necesare. Elementele de date de tip common sunt adresate n acela"i mod. Directiva common se folose"te la declararea elementelor de date comune. Un element de date comun este asem!n!tor unuia global, numai c! este declarat n sec#iunea datelor neini#ializate. common este similar cu: global data section .bss data resd 1 Diferen#a apare atunci cnd elementul de date comun este definit n mai mult de un singur modul. Atunci, editorul de leg!turi static mbin! aceste elemente de date, iar referin#ele c!tre elementul de date respectiv, din toate modulele, vor fi direc#ionate c!tre aceea"i zon! de memorie. La fel ca directivele extern "i global, directiva common poate primi extensii specifice formatului de executabil: common vector 100:4 ;aliniere la 4 octe#i data 4

Exportul simbolurilor c!tre utilizatorul bibliotecii Dac! inten#ion!m s! export!m simboluri c!tre utilizatorul bibliotecii, trebuie s! declar!m dac! acestea sunt elemente de date sau func#ii, iar dac! sunt date, trebuie specificat! dimensiunea acestora. Acest lucru este necesar deoarece editorul dinamic trebuie s! creeze intr!ri PLT pentru orice func#ie exportat! "i, de asemenea, trebuie s! mute datele exportate n afara sec#iunii de date a bibliotecii care le declar!. Astfel, pentru exportul func#iilor trebuie s! folosim: global func:function ;declar! func ca func#ie func: push ebp ;etc. Iar pentru exportul elementelor de date, de exemplu, un vector:

global vector:data vector.end-vector ;se specific! m!rimea vector: resd 128 .end Aten"ie, dac! export!m un element de date c!tre utilizatorul bibliotecii prin declararea acestuia ca global #i specificarea dimensiunii, elementul de date respectiv va fi mutat n sec"iunea de date a programului principal. Acesta nu se va mai afla n sec"iunea de date n care este declarat. A#adar, trebuie s! adres!m propria variabil! global! cu mecanismul ..got, ca #i cum ar fi un element de date extern (ceea ce efectiv a #i devenit), nu cu ..gotoff. n mod asem!n!tor, dac! trebuie s! stoc!m adresa unui element global, exportat de c!tre alt modul, n una din sec"iunile de date curente, nu putem folosi declara"ia standard: data: dd element_de_date_global ;GRE!IT

YASM va interpreta acest cod ca fiind o relocare obi#nuit!, caz n care elementele de date globale se reg!sesc la un deplasament judecat n func"ie de nceputul sec"iunii curente. A#adar, aceast! referin"! indic! sec"iunea de date curent!, nu elementul global (acesta se afl! n alt! parte). n loc de codul de mai sus, scriem: data: dd element_de_date_global wrt ..sym

..sym provoac! YASM s! caute n tabela de simboluri un anumit element aflat la adresa respectiv!. Metodele anterioare au aceea#i semnifica"ie #i pentru func"ii: adresarea unei func"ii prin funcptr: dd function va furniza adresa codului scris n sec"iunea curent!, n timp ce funcptr: dd function wrt ..sym

va furniza adresa PLT pentru func"ia respectiv!, acolo unde programul apelant crede c! se afl! aceasta. Apelul func!iilor din exteriorul bibliotecilor Apelarea func"iilor din afara bibliotecii partajate trebuie s! se realizeze prin intermediul unui PLT. Fa"! de adresa la care este nc!rcat! biblioteca n memorie

PLT este plasat la un deplasament cunoscut, astfel nct codul bibliotecii s! poat! efectua apeluri PLT ntr-un mod independent de pozi"ie. PLT con"ine instruc"iuni de salt c!tre deplasamentele con"inute de GOT, astfel nct apelurile de func"ii c!tre alte biblioteci partajate sau rutine din programul principal pot fi transmise transparent c!tre destina"iile lor reale. Pentru a apela o rutin! extern! trebuie s! folosit un alt tip special de relocare PIC, wrt ..plt. Aceasta este mai simpl! dect variantele care lucreaz! cu GOT: pur #i simplu se nlocuie#te CALL f_nwln cu versiunea relativ! la PLT, CALL f_nwln wrt ..plt.

10.4.3.

Procesul de generare a bibliotecilor partajate

Urm!toarea comand! asambleaz! func"ia f_nwln.asm n format PIC dat! mai sus: yasm f elf g stabs f_nwln.asm Se ob"ine fi#ierul obiect f_nwln.o, transformat n bibliotec! partajat! cu comanda: ld -shared -o libioapi.so f_nwln.o -melf_i386 Numele unei biblioteci partajate trebuie prefixat de cuvntul lib #i finalizat cu .so. Op"iunea -shared indic! editorului de leg!turi faptul c! trebuie s! genereze o bibliotec! partajat!, nu un executabil. n acest moment, n directorul curent se afl! biblioteca partajat! libioapi.so, format! dintr-un singur modul obiect. Studiem biblioteca partajat! folosind trei unelte foarte utile, file, nm #i objdump. Programul file specific! tipul fi#ierului #i ne permite s! afl!m pentru ce platform! a fost asamblat (compilat) acesta. Fi#ierul interogat poate fi un fi#ier text, un executabil sau o bibliotec!. file libioapi.so libioapi.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, not stripped nm enumer! toate simbolurile care exist! ntr-un obiect (prin obiect n"elegem un fi#ier obiect sau o bibliotec!). Afi#eaz! numele func"iilor utilizate sau exportate de c!tre obiect, sec"iuni, simboluri, etc.. Biblioteca noastr! partajat! produce urm!torul listing: nm libioapi.so

00000175 t .n_so 00001178 a _DYNAMIC 000011f0 a _GLOBAL_OFFSET_TABLE_ 000011fd A __bss_start 000011fd A _edata 00001200 A _end 000011fc d new_line 00000140 T f_nwln 0000014e t f_nwln.get_GOT Dezasamblorul objdump ne permite s! studiem modul n care operatorul wrt a ac"ionat asupra instruc"iunilor: objdump -D -M intel libioapi.so 00000130 <f_nwln>: 130: 55 131: 89 e5 133: 53 134: e8 00 00 00 00 push mov push call ebp ebp,esp ebx 139 <f_nwln.get_GOT>

00000139 <f_nwln.get_GOT>: 139: 5b pop ebx 13a: 81 c3 7f 10 00 00 add ebx,0x107f 140: 8d b3 0c 00 00 00 lea esi,[ebx+0xc] 146: b8 04 00 00 00 mov eax,0x4 14b: bb 01 00 00 00 mov ebx,0x1 150: 89 f1 mov ecx,esi 152: ba 01 00 00 00 mov edx,0x1 157: cd 80 int 0x80 159: 8b 5d fc mov ebx,DWORD PTR [ebp-0x4] 15c: 89 ec mov esp,ebp 15e: 5d pop ebp 15f: c3 ret 000011b8 <.got.plt>: 11b8: 60 11b9: 11 00 ... Disassembly of section .data: pusha adc DWORD PTR [eax],eax

000011c4 <new_line>: 11c4:0a .byte 0xa n urma instruc!iunii LEA ESI,[EBX + 0xc], n registrul ESI se va afla adresa new_line, 000011c4. Dac" sc"dem din aceasta 0xc rezult" adresa 000011b8, adic" adresa de nceput a tabelei GOT.

10.4.4.

Instalarea !i utilizarea bibliotecilor partajate

Urm"torul program folose#te biblioteca partajat" pentru a afi#a la ecran un caracter de linie nou". ; ;prog.asm, PIC ; section .text extern f_nwln global _start _start: nop call f_nwln wrt ..plt mov eax,1 mov ebx,0 int 80h Asamblarea acestuia are loc n mod obi#nuit: yasm -f elf -g stabs prog.asm n schimb, deoarece folose#te o func!ie ce apar!ine unei biblioteci partajate, aceasta nu va fi inclus" n fi#ierul executabil final #i este nevoie ca editorul de leg"turi dinamic s" ncarce n memorie biblioteca partajat" #i s" rezolve reloc"rile. n sistemele Linux editorul de leg"turi dinamic este ld-linux.so.2, prezent n directorul /lib. Pentru a specifica programului principal c" are nevoie de editorul dinamic folosim parametrul -dynamic-linker. ld -dynamic-linker /lib/ld-linux.so.2 -o prog prog.o L. -lioapi -melf_i386 Cnd rul"m un program care depinde de o bibliotec" partajat", sistemul va c"uta

aceast! bibliotec! n cteva locuri standard: /lib "i /usr/lib. Dac! fi"ierul .so nu poate fi g!sit n niciuna din aceste loca#ii, executabilul nu va putea fi lansat n execu#ie. Comanda ldd [prog] poate depista bibliotecile partajate de care depinde programul "i dac! ele sunt pot fi g!site de sistem sau nu. Avem dou! op#iuni: copiem biblioteca partajat! n unul din directoarele amintite, lucru care nu este ntotdeauna posibil, deoarece sunt necesare drepturi privilegiate (de root), sau le folosim din cadrul unui alt director, posibil chiar directorul curent. n acest caz, trebuie s! configur!m corespunz!tor variabila de mediu LD_LIBRARY_PATH. De exemplu, dac! biblioteca partajat! se afl! n acela"i director cu fi"ierul executabil, execut!m comanda: export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH Acum putem instala biblioteca partajat!. Bibliotecile partajate sunt instalate cu ajutorul unui program special, numit ldconfig. n mod normal, dac! bibliotecile se g!sesc n directoarele standard, putem rula ldconfig pur "i simplu. Dar, pentru c! trebuie s! instal!m o bibliotec! aflat! n directorul curent, rul!m: ldconfig -v -n . Programul se execut! n mod obi"nuit: ./prog ncheiem aici subiectul bibliotecilor partajate. Procesul este mult mai complex "i necesit! divaga#ii care nu intr! n planul acestei c!r#i. Observa#i c! nu am transcris func#iile noastre n cod independent de pozi#ie. Metoda GOT este destul de ineficient! din punct de vedere al performan#elor: codul trebuie s! extrag! o adres! din GOT de fiecare dat! cnd cite"te sau scrie n segmentul de date (risip! de timp "i registre - EBX are rol dedicat). De"i se poate folosi "i alt! metod! mai rapid!, am ales s! prezint!m mecanismul standard. n plus, codul independet de pozi#ie este mai u"or de implementat pe sistemele de 64 de bi#i.

10.5. Apelul func!iilor de sistem prin biblioteca standard C


Orice sistem de operare similar ca func!ionalitate cu Unix con!ine o interfa!" de apelare a func!iilor de sistem. Aceasta define#te apelurile func!iilor de sistem. n Linux, biblioteca C se nume#te glibc #i con!ine func!ii pentru toate facilit"!ile puse la dispozi!ie de sistemul de operare. n consecin!", orice aplica!ie creat" sau instalat" de utilizator poate accesa kernelul prin interfa!a de apelare a func!iilor de sistem sau prin intermediul glibc.

Aplica!ie

Aplica!ie Spa!iul utilizator Aplica!ie Biblioteca C

Intefa!a de apelare a func!iilor de sistem Spa!iul kernel Kernel

Drivere de dispozitiv

Hardware

Figura 10.4 Rela!ia ntre aplica!ii, kernel "i hardware

Aceast" sec!iune descrie modul n care putem utiliza func!ii C n programele scrise n limbaj de asamblare. Bibliotecile C con!in toate func!iile standard utilizate n programele C, precum cea de afi#are a #irurilor de caractere (printf) sau func!ia de ncheiere a proceselor (exit).

Urm!torul program afi"eaz! propriile argumente primite din linia de comand!. ; ;args.asm ; section .data nrArgs db "Sunt %d argumente: ",10,0 Args db "%s",10,0 section .text extern printf extern exit global _start _start: nop mov ecx,[esp] push ecx push nrArgs call printf add esp,4 pop ecx mov ebp,esp add ebp,4 bucla: push ecx push dword [ebp] push Args call printf add esp,8 pop ecx add ebp,4 loop bucla push 0 call exit Observa#i c! func#iile printf "i exit sunt declarate cu directiva extern, la fel ca orice func#ie definit! ntr-un fi"ier extern. Dac! a#i lucrat n C, func#ia printf v! este cunoscut!. Ne permite s! tip!rim la ie"irea standard att text simplu f!r! nicio formatare, Argumentele sunt urm!toarele: ct "i propozi#ii complicate, formate din cuvinte obi"nuite, cifre sau caractere de conversie a datelor numerice:

Num!rul de argumente este %d: Sintaxa func!iei printf este urm"toarea: printf Text FORMATAT, arg1, arg2 ... unde textul formatat con!ine caractere obi#nuite, copiate explicit la ie#ire, dar #i coduri de control care determin" modul de conversie #i tip"rirea argumentelor. Fiecare specifica!ie de formatare este introdus" prin caracterul % #i ncheiat" de un caracter de conversie. Cteva din codurile de conversie sunt listate n Tabelul 10.3.
Tabelul 10.4 Coduri de conversie pentru func!ia printf

Cod de conversie %d %u %x %c %s %%

Descriere Argumentul este convertit n zecimal Argumentul este convertit n zecimal f"r" semn Argumentul este convertit n hexazecimal Argumentul este considerat ca fiind un singur caracter Argumentul este un #ir de caractere Afi#eaz" simbolul procent

ntre % #i caracterul de conversie pot fi: un semn (minus), care semnific" alinierea la stnga a argumentului convertit; un ntreg, care specific" lungimea minim" a #irului. Argumentul va fi aliniat la dreapta #i va fi completat cu spa!ii albe pn" la lungimea cmpului. Caracterele din cadrul argumentului corespunz"tor formatului %s sunt preluate pn" la ntlnirea caracterului NULL. Acesta este #i motivul pentru care n program am ata#at un zero la #irurile destinate mesajelor: "Sunt %d argumente: ",10,0 Num"rul 10 reprezint" caracterul ASCII \n. Mecanismul de formatare este simplu, problema real" const" n transmiterea argumentelor. Func!ia printf nu permite specificarea num"rului de argumente. Num"rul acestora variaz" n func!ie de necesit"!ile programatorului. n schimb, to!i parametrii primi!i de func!iile bibliotecii C trebuie transmi#i prin intermediul stivei, n concordan!" cu conven!ia C. Acest lucru se face direct, prin

introducerea valorii, sau indirect, prin referin!" (prin introducerea adresei de 32 de bi!i a argumentului). Pentru elemente de date cu valori de 32 sau 64 de bi!i, introducem valorile direct. Pentru elemente de date mai mari, precum #iruri sau vectori, introducem n stiv" adresa de nceput (n jargonul C, transmiterea unei adrese c"tre ceva se nume#te transmiterea unui pointer c"tre acel ceva). Cnd func!ia printf prime#te mai mul!i parametrii, ace#tia trebuie introdu#i n stiv" ntr-o ordine foarte exact": de la dreapta la stnga, a#a cum ar fi ap"rut n corpul instruc!iunii printf ntr-un program scris n C. Un exemplu simplu din C este urm"torul: printf(ntotdeauna %d + %d = %d, 2,3,5); Aceasta este o propozi!ie n C care apeleaz" func!ia printf. $irul de baz" este nchis ntre ghilimele #i reprezint" primul argument. $irul este urmat de cteva argumente numerice. Trebuie s" fie o valoarea numeric" pentru fiecare cod de formatare %d g"sit n #ir. Ordinea n care aceste elemente trebuie introduse n stiv" ncepe cu elementul din dreapta #i continu" c"tre stnga, #irul de baz" fiind ultimul. n asamblare, secven!a arat" astfel: push 5 push 3 push 2 push mesaj call printf add esp,16 Identificatorul mesaj este adresa #irului de baz", a#a cum este acesta definit n segmentul de date. Mesaj db ntotdeauna %d + %d = %d,0

Instruc!iunea de adunare de la final elibereaz" stiva. Ne amintim c", de fiecare dat" cnd introducem ceva n stiv" cu instruc!iunea PUSH, indicatorul de stiv" ESP se deplaseaz" c"tre adrese mai mici cu un num"r de octe!i egal cu dimensiunea elementelor. Patru argumente reprezint" 16 octe!i. La sfr#itul apelului indicatorul de stiv" trebuie s" con!in" adresa dinaintea acestuia, a#adar, adun"m 16.

10.5.1.

Editarea leg!turilor cu func"iile C

Cnd folosim n programele de asamblare func!ii din biblioteca C trebuie s" leg"m fi#ierele bibliotecii de fi#ierul obiect al programului. Dac" func!iile bibliotecii C nu sunt disponibile, editorul de leg"turi va afi#a mesaj de eroare. ld -o args args.o args.o: In function `_start': args.asm:13: undefined reference to `printf' args.o: In function `bucla': args.asm:20: undefined reference to `printf' args.asm:26: undefined reference to `exit' Pentru a putea edita leg"turile cu func!iile C, acestea trebuie s" fie disponibile n sistem. n sistemele Linux, biblioteca C standard dinamic" se afl" n fi#ierul libc.so.x, unde x este o valoarea care reprezint" versiunea bibliotecii. Acest fi#ier bibliotec" con!ine func!iile standard C, incluznd printf #i exit. Fi#ierul libc.so trebuie legat explicit de codul obiect, folosind parametrul -l al editorului de leg"turi GNU, ld. Cnd utiliz"m parametrul -l, nu trebuie s" specific"m numele complet al bibliotecii. Editorul de leg"turi presupune c" biblioteca se va afla ntr-un fi#ier numit /lib/libx.so, unde x este numele bibliotecii specificat ca parametru n linia de comand" n acest caz, litera c. Pe de alt" parte, func!iile nu vor fi incluse n fi#ierul executabil final #i biblioteca dinamic" trebuie nc"rcat" n memorie la momentul lans"rii n execu!ie a programului, de un alt program. Pentru sistemele Linux, acest program este ldlinux.so.2, reg"sit n directorul /lib. Pentru a specifica programului nostru c" are nevoie de editorul de leg"turi dinamic, folosim parametrul -dynamiclinker. ld -dynamic-linker /lib/ld-linux.so.2 args.o -verbose -o args -lc

Asamblarea se face n mod obi#nuit, cu YASM. La rulare, pentru a g"si biblioteca libc.so programul folose#te nc"rc"torul dinamic ld-linux.so.2. Putem testa programul args cu orice num"r de parametrii. ./args test 10 20 30 Sunt 5 argumente: ./args test 10

20 30 Aminti!i-v" c" primul parametru este considerat numele programului, a#adar, primul argument din linia de comand" este al doilea parametru. O gre#eal" ntlnit" frecvent const" n compararea cu zero a num"rului de argumente din linia de comand". Din moment ce numele programului se va reg"si ntotdeauna pe linia de comand", num"rul de parametri nu va fi niciodat" zero. Urm"torul program afi#eaz" variabilele de mediu. ; ;env.asm ; section .data Args db "%s",10,0 section .text extern printf extern exit global _start _start: nop mov ebp,esp add ebp,12 bucla: cmp dword [ebp],0 je sfarsit push dword [ebp] push Args call printf add esp,12 add ebp,4 loop bucla sfarsit: push 0 call exit ./env USERNAME=stefan DEFAULTS_PATH=/usr/share/gconf/gnome.default.path GIO_LAUNCHED_DESKTOP_FILE=/usr/share/applications/terminator.desktop XDG_CONFIG_DIRS=/etc/xdg/xdg-gnome:/etc/xdg PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games DESKTOP_SESSION=gnome

PWD=/home/stefan GDM_KEYBOARD_LAYOUT=us LANG=en_US.UTF-8 GDM_LANG=en_US MANDATORY_PATH=/usr/share/gconf/gnome.mandatory.path UBUNTU_MENUPROXY=libappmenu.so COMPIZ_CONFIG_PROFILE=ubuntu GDMSESSION=gnome SHLVL=1 HOME=/home/stefan LANGUAGE=en_US:en Cnd n linia de comand! nu sunt specifica"i parametrii, sec"iunea variabilelor de mediu ncepe la un deplasament de 12 octe"i fa"! de adresa stocat! n registrul ESP. Sfr#itul sec"iunii este marcat cu un caracter NULL. Compararea valorii din stiv! cu zero verific! faptul c! am ajuns la sfr#itul sec"iunii. Dac! adresa nu este zero, se afi#eaz! #irul indicat de aceasta. Variabilele de mediu prezente n sistem depind de aplica"iile active #i de set!rile locale. Putem verifica acest lucru prin crearea unei noi variabile. export TEST=/home/test ./env | grep TEST TEST=/home/test

11. INTERFA!A CU LIMBAJELE DE NIVEL NALT

n capitolul III am prezentat avantajele !i dezavantajele limbajelor de nivel nalt !i de asamblare !i, nc" din prefa#", am aten#ionat cititorul c" scrierea complet" a programelor n asamblare trebuie evitat" ct de mult posibil. Programele n asamblare sunt mai lungi, mai dificil de actualizat !i, mai ales, nu sunt portabile. n schimb, ofer" acces direct la hardware !i pot reduce timpul de execu#ie. Ca urmare, dac" este necesar, programele de nivel nalt pot beneficia de performan#a ridicat" a unor func#ii scrise n asamblare. n astfel de programe este posibil ca o func#ie de nivel nalt s" apeleze o func#ie de nivel sc"zut, sau invers. n acest capitol prezent"m diferite modalit"#i prin care putem introduce func#ii scrise n asamblare n corpul programelor de nivel nalt, n acest caz, limbajul C. Scopul nostru este acela de a ilustra principiile implicate. Odat" ce acestea sunt n#elese, discu#ia poate fi generalizat" la orice alt limbaj de nivel nalt. Cele dou! metode prin care putem introduce secven"e de instruc"iuni n asamblare n codul C sunt: scrierea instruc"iunilor de asamblare direct n codul C, sau legarea de programul C a unor module scrise n asamblare, la momentul compil!rii. Proces asem!n!tor celui de legare a programelor C de func"iile aflate n bibliotecile C standard. Prima metod! se nume#te inline assembly #i este util! numai atunci cnd trebuie s! includem n codul C o secven"! relativ scurt! de cod n asamblare. n caz contrar, este preferat! metoda modulelor separate. n acest ultim caz, modulul scris n asamblare devine o func"ie pe care programul C o tratateaz! la fel ca pe orice alt! func"ie C. Dac! sunt utilizate module separate, C #i asamblare, fiecare modul este translatat n fi#ierul obiect corespunz!tor: modulul C cu ajutorul unui compilator, modulul n asamblare cu ajutorul unui asamblor. n procesul de generare a fi#ierului executabil editorul de leg!turi utilizeaz! ambele fi#iere obiect. S! presupunem c! programul nostru hibrid con"ine dou! module: un modul C, fi#ierul main.c, #i un modul n asamblare, fi#ierul proc.asm. Procesul prin care se ob"ine fi#ierul executabil con"ine dou! etape. n prima etap! gener!m fi#ierul obiect pentru modulul n asamblare: yasm -f elf -g stabs proc.asm

Acest pas creaz! fi"ierul proc.o. A doua etap! compileaz! modulul C "i editeaz! leg!turile ntre cele dou! module obiect: gcc -g stabs -o program main.c proc.o m32 Editorul de leg!turi este invocat automat de c!tre GCC.

11.1. Apelarea modulelor n asamblare din C


n capitolul intitulat Func#ii am demonstrat cum trebuie s! arate o func#ie n limbaj de asamblare astfel nct s! poat! fi utilizat! de un program n asamblare. Aceea"i tehnic! poate fi utilizat! "i pentru func#iile n asamblare care vor fi ncorporate n programe C. Tot n acel capitol am v!zut c! func#iile pot primi n diferite moduri parametrii de intrare, unul dintre ele fiind caracteristic programelor C. Programele C folosesc o metod! "i un format specific, "i anume, transferul parametrilor prin intermediul stivei. n plus, unele registre au rol prestabilit, rol care trebuie respectat cu stricte#e.
Tabelul 11.1 Rolul registrelor n conven!ia de apel C

Descriere Destinat s! p!streze valoarea returnat! de func#ie; poate fi modificat EAX pn! la revenirea din func#ie. EBX Destinat s! indice tabelul global de deplasamente; trebuie p!strat ECX Disponibil pentru uzul intern al func#iei EDX Disponibil pentru uzul intern al func#iei EBP Indic! adresa de baz! a stivei; trebuie p!strat ESP Indic! noua loca#ie a stivei n cadrul func#iei; trebuie p!strat EDI Utilizat ca registru local de c!tre programul C; trebuie p!strat ESI Utilizat ca registru local de c!tre programul C; trebuie p!strat Destinat s! p!streze valoarea n virgul! mobil! returnat! de func#ie; ST(0) poate fi modificat pn! la revenirea din func#ie ST(1) - ST(7) Disponibile pentru uzul intern al func#iei

Registru

Regulile care trebuie respectate de orice func#ie pentru a putea fi apelat! dintr-un program C formeaz! a"a numitele conven!ii de apel C. Toate func#iile implementate n bibliotecile C respect! aceste reguli. Acelea"i conven#ii trebuie respectate cu stricte#e "i de func#iile scrise n asamblare. Pe scurt, acestea sunt: Func#ia trebuie s! p!streze valorile ini#iale ale registrelor EBX, ESP, ESI, EDI. Func#ia poate folosi aceste registre n corpul ei dar,

la revenirea din func!ie, registrele men!ionate trebuie s" con!in" valorile dinainte de apelarea acesteia. Con!inutul tuturor celorlalte registre de uz general poate fi modificat dup" dorin!". Rezultatul unei func!ii este returnat n registrul EAX - n cazul unei valori de 32 de bi!i sau mai mici -, n EDX:EAX - pentru o valoare de 64 de bi!i -, sau n registrul ST(0) pentru valori n virgul" mobil". #irurile, structurile sau alte elemente de date mai mari de 32 de bi!i sunt returnate prin referin!" (func!ia returneaz" n EAX adresa de nceput a acestora). Parametrii de intrare ai func!iilor sunt introdu$i n stiv" n ordine invers" fa!" de cea a apari!iei lor n declara!ia func!iei. Presupunnd c" avem func!ia Proc(alpha, beta, gamma), primul parametru introdus n stiv" trebuie s" fie gamma, urmat de beta $i, ultimul, alpha. Func!iile nu extrag parametrii din stiv". Programul apelant efectueaz" acest lucru dup" revenirea din func!ie, fie prin instruc!iunea POP, fie prin adunarea unui deplasament la indicatorul de stiv" ESP (metod" ntlnit" mai des, deoarece este mai rapid"). De$i nu este o conven!ie explicit", urm"toarea cerin!" este important": eticheta punctului de intrare n program pentru func!ia n asamblare trebuie s" fie declarat" global.

Respectarea conven!iilor de apel C ncepe cu salvarea $i refacerea con!inutului registrelor: introducerea lor n stiv", la nceputul func!iei, $i extragerea lor din stiv", la revenirea n programul principal. Procesul are loc n secven!ele standard, prolog $i epilog (la fel ca la func!iile utilizate de programele n asamblare studiate n capitolele precedente).

11.1.1.

Structura func!iei n asamblare

Structura $ablon a func!iilor n asamblare destinate apel"rii din interiorul programelor C arat" astfel: ; ;FuncTemplate.asm ; section .data section .bss

section .text global proc proc:

;punct de intrare necesar editorului de leg!turi

push ebp ;seteaz! cadrul de stiv! mov ebp,esp sub esp,12 push ebx ;func"ia trebuie s! p!streze EBP, EBX, ESI, & EDI push esi push edi < codul func"iei > pop pop pop mov pop ret edi esi ebx esp,ebp ebp ;restaureaz! registrele EBP, EBX, ESI & EDI ;elimin! cadrul de stiv! nainte de revenire ;revenire n program

Acest #ablon trebuie respectat de toate func"iile n asamblare ce vor fi apelate din cadrul programelor C sau C++. Desigur, dac! o func"ie nu altereaz! con"inutul registrelor EBX, ESI sau EDI, putem omite instruc"iunile PUSH #i POP echivalente. O mic! remarc!: din faptul c! este necesar! salvarea registrele EBX, ESP, EBP, ESI #i EDI reiese c! toate celelalte registre de uz general pot fi rescrise. $i aici, mare aten"ie: pot fi rescrise de oricine, nu numai de noi. Dac! din interiorul func"iei scrise de noi sunt apelate alte func"ii (din bibliotecile standard, de exemplu), acele func"ii pot altera valorile din EAX, ECX #i EDX. Acest lucru nseamn! c! nu putem presupune faptul c! o valoare contor aflat! n ECX va r!mne nemodificat! dup! un apel al func"iei C printf. Dac! func"ia scris! de noi utilizeaz! ECX ca registru contor #i totodat! include apeluri c!tre func"ii bibliotec! sau c!tre orice alt! func"ie care nu e scris! de noi trebuie s! salv!m explicit valoarea acestuia n stiv!, nainte de apel, #i s! refacem explicit valoarea acestuia, la revenirea din func"ie. Acela#i lucru este valabil #i pentru EAX #i EDX. n cazul celui dinti, #tim c! func"iile standard returneaz! rezultatul n registrul EAX, a#adar, cnd apel!m astfel de func"ii, este evident c! acesta va fi rescris. Observa"i instruc"iunea SUB inclus! n prolog. Aceasta rezerv! n stiv! spa"iu destinat stoc!rii variabilelor locale (utilizate n cadrul func"iei noastre). Instruc"iunea din #ablon rezerv! n stiv! un num!r de 12 octe"i de memorie. Ace#tia pot stoca trei elemente de date a cte 4 octe"i fiecare. Dac! este necesar mai mult spa"iu, se scade din ESP num!rul de octe"i corespunz!tor. Variabilele locale sunt

adresate din interiorul func!iei, relativ la registrul EBP. De exemplu, dac" prima variabil" local" ocup" 4 octe!i, adresa loca!iei va fi [EBP-4]. A doua variabil" local" poate fi adresat" cu [EBP-8], iar a treia cu [EBP-12]. Totu#i, func!iile n asamblare pot declara propriile segmente .data #i .bss. n acest caz, la momentul compil"rii, aceste zone de memorie vor fi combinate cu zonele .data #i .bss ale programului C.

11.1.2.

Cadrul de stiv!

Pentru programele n asamblare, stiva este extrem de important". Pentru programele C sau cele care interac!ioneaz" cu C, stiva este esen!ial". n C, stiva are un rol central. Motivul este simplu: compilatoarele sunt robo!i care traduc codul C n limbaj n asamblare. Acest lucru nseamn" c" folosesc metode mecanice, iar majoritatea acestora depind enorm de existen!a stivei. n sistemele Linux, mecanismele folosite de compilator se bazeaz" pe no!iunea de cadru de stiv!. Compilatoarele folosesc cadrele de stiv" n procesul de alocare a spa!iului pentru variabile locale. Un cadru de stiv" reprezint" o regiune (din stiv") marcat" ca apar!innd unei anumite func!ii. n esen!", aceasta este regiunea cuprins" ntre adresele aflate n dou" registre: indicatorul de baz" (EBP) #i indicatorul de stiv" (ESP).

Stiva

EBP+16: EBP+12: EBP+8: EBP+4: EBP+0: EBP-4: EBP-8: EBP-12: EBP-16: EBP-20: EBP-24: EBP-28: EBP-32: EBP-36: EBP apelant EBX apelant ESI apelant EDI apelant (loca!ie temporar") (loca!ie temporar") (loca!ie temporar") (loca!ie temporar") (loca!ie temporar") (loca!ie temporar") ESP Aceast" regiune reprezint" cadrul de stiv" curent Datele din aceast" zon" apar!in urm"torului cadru de stiv" EBP r"mne fix pn" cnd cadrul de stiv" este EBP eliminat. EPB con!ine valoarea ESP a func!iei apelante.

Direc!ia de cre#tere a adreselor de memorie

Memorie neutilizat" ESP se deplaseaz" n sus #i jos

Figura 11.1 Un cadru de stiv!

Cadrul de stiv! este creat prin salvarea n stiv! a registrului EBP (registrul EBP al func"iei apelante) #i copierea indicatorului de stiv! al func"iei apelante n registrul EBP. Odat! ce EBP este ancorat la acel cap!t al cadrului de stiv!, indicatorul de stiv!, ESP, se poate deplasa liber, n func"ie de necesit!"ile func"iei. Primele dou! instruc"iuni din prolog: push ebp mov ebp,esp n urma acestor dou! instruc"iuni, registrul EBP este considerat ancora noului cadru de stiv! (sau indicator de cadru). Toate elementele aflate deasupra lui n stiv! (deasupra cadrului de stiv! al func"iei curente) nu pot fi adresate dect prin intermediul acestuia. Acolo sunt #i parametrii de intrare ai func"iei, dac! aceasta necesit! a#a ceva. Un alt motiv pentru care EBP nu trebuie modificat este c! valoarea indicatorului de stiv! al apelantului, ESP, se afl! n EBP. Revenirea din func"ie cu un ESP modificat nseamn! func"ionarea defectuoas! a programului

apelant. nainte de finalul func!iei, cadrul de stiv" trebuie eliminat. Acesta este rolul ultimelor dou" instruc!iuni din epilog: mov esp,ebp pop ebp n acest moment, cadrul de stiv" nu mai exist" #i putem executa n siguran!" instruc!iunea RET. Instruc!iunea RET red" controlul programului C.

11.1.3.

Compilarea modulelor

Compilatorul GCC poate ob!ine fi#iere obiect din func!ii scrise n limbaj de asamblare #i le poate ad"uga la corpul programului C. Fi#ierul obiect al func!iei n asamblare este generat cu ajutorul asamblorului YASM. Urm"toarea func!ie n asamblare afi#eaz" un mesaj prin intermediul func!iei standard printf. ; ;proc.asm ; section .data Msg db "Mesaj din interiorul functiei in asamblare.",10,0 section .text global proc extern printf proc: push ebp mov ebp,esp sub esp,12 push ebx push esi push edi push Msg call printf add esp,4 pop pop pop mov edi esi ebx esp,ebp

pop ebp ret Func!ia proc.asm folose"te secven!ele prolog "i epilog specifice conven!iei de apel C. Observa!i cum numele s#u este declarat global "i faptul c# textul mesajului este declarat n sec!iunea datelor ini!ializate. Pentru afi"area acestuia se folose"te func!ia standard printf, declarat# ca extern. Asambl#m func!ia n asamblare: yasm -f elf -g stabs proc.asm melf_i386 Odat# creat fi"ierul obiect, acesta poate fi specificat n linia de comand# a compilatorului, al#turi de fi"ierul C surs#. Fi"ierul programului principal este numit main.c. /* programul principal apeleaz# func!ia n asamblare */ #include <stdio.h> int main() { extern void proc(); proc(); printf("Mesaj din interiorul programului principal.\n"); return 0; } Programul principal apeleaz# func!ia n asamblare pe baza numelui. Parantezele rotunde indic# faptul c# numele respectiv reprezint# o func!ie. Foarte important, func!ia trebuie declarat# ca func!ie extern#. n acest caz, func!ia nu necesit# parametri de intrare "i nici nu returneaz# vreo valoare. Urm#toarele comenzi creaz# executabilul "i l ruleaz#. gcc -g stabs -o program main.c proc.o m32 ./program Mesaj din interiorul functiei in asamblare. Mesaj din interiorul programului principal. Codul compilat poate fi dezasamblat cu programul objdump: objdump -d program -M intel -j .text

Ve!i observa c" sunt prezente mai multe sec!iuni. Cele care ne intereseaz" sunt main #i proc. Sec!iunea main con!ine codul n asamblare generat de compilator pentru programul C. 080483f4 <main>: 80483f4: 55 80483f5: 89 e5 80483f7: 83 e4 f0 80483fa: 83 ec 10 80483fd: e8 1e 00 00 00 8048402: c7 04 24 00 85 04 08 8048409: e8 16 ff ff ff 804840e: b8 00 00 00 00 8048413: c9 8048414: c3 push ebp mov ebp,esp and esp,0xfffffff0 sub esp,0x10 call 8048420 <proc> mov DWORD PTR [esp],0x8048500 call 8048324 <puts@plt> mov eax,0x0 leave ret

Sec!iunea proc con!ine codul func!iei n asamblare: 08048420 <proc>: 8048420: 55 8048421: 89 e5 8048423: 83 ec 0c 8048426: 53 8048427: 56 8048428: 57 8048429: 68 18 a0 04 08 804842e: e8 e1 fe ff ff 8048433: 83 c4 04 8048436: 5f 8048437: 5e 8048438: 5b 8048439: 89 ec 804843b: 5d 804843c: c3 push mov sub push push push push call add pop pop pop mov pop ret ebp ebp,esp esp,0xc ebx esi edi 0x804a018 8048314 <printf@plt> esp,0x4 edi esi ebx esp,ebp ebp

Func!ia proc este apelat" din programul principal n mod obi#nuit, cu instruc!iunea CALL. n acela#i mod n care func!ia proc, la rndul s"u, apeleaz" func!ia printf.

11.2. Linii de asamblare n codul surs! C


11.2.1. Sintaxa AT&T

nc! din capitolul II am v!zut c! instruc"iunile ma#in! ale procesoarelor x86 sunt codificate n limbaj de asamblare prin dou! seturi de instruc"iuni mnemonice. Totodat!, ne amintim c! instruc"iunea mnemonic! reprezint! numai o modalitate prin care fiin"ele umane deduc ce nseamn! pentru procesor o anumit! secven"! de cifre binare. n loc s! scriem secven"a de zero #i unu 1000100 111000011, scriem MOV BX,AX. La fel de bine am putea scrie COPIAZ! BX n AX, dar, din nefericire, creatorul limbajului de asamblare nu a fost romn. Folosim MOV BX,AX numai pentru c! a#a a sugerat Intel. Setul alternativ de instruc"iuni mnemonice pentru procesoare x86 a ap!rut din dorin"a de a face sistemul de operare Unix ct mai u#or de implementat pe diferite arhitecturi hardware. Aceste instruc"iuni se numesc mnemonici AT&T. Cum toate instrumentele de dezvoltare software cu surs! deschis! (compilatorul GCC, depanatorul GDB, asamblorul AS) sunt destinate unui sistem de operare nrudit cu Unix, #i anume Linux, toate folosesc nativ sintaxa AT&T. n procesul de compilare, GCC nu face altceva dect s! traduc! codul surs! C n cod surs! scris n limbajul de asamblare conform cu sintaxa AT&T. Ne amintim din capitolul III cum compilatorul CC prime#te ca intrare un fi#ier surs! .c #i genereaz! un fi#ier surs! .s, pe care l trimite apoi asamblorului GAS. Utilitarele GNU lucreaz! n acela#i fel pe toate platformele. ntr-un sens, limbajul de asamblare este un limbaj intermediar folosit numai n beneficiul compilatorului. De cele mai multe ori, programatorii nu se vor ntlni cu el. Cu toate acestea, dac! trebuie s! lucra"i cu GCC #i biblioteca standard C sau cu o mul"ime de alte biblioteci scrise n C #i pentru C, trebuie cel pu"in s! v! familiariza"i cu mnemonicele AT&T. Mai ales dac! lucra"i pe platforme Unix sau nrudite. S! ne amintim cu arat! un program n aceast! sintax!: gcc -S prog.c -o - -m32 .file .text .globl main .type main: pushl movl subl "prog.c" main, @function %ebp %esp, %ebp $16, %esp push mov sub ebp ebp, esp esp, 16

movl $40, -4(%ebp) mov DWORD PTR [ebp-4], 40 movl $50, -8(%ebp) mov DWORD PTR [ebp-8], 50 movl -4(%ebp), %eax mov eax, DWORD PTR [ebp-4] movl %eax, -12(%ebp) mov DWORD PTR [ebp-12], eax movl -8(%ebp), %eax mov eax, DWORD PTR [ebp-8] movl %eax, -4(%ebp) mov DWORD PTR [ebp-4], eax movl -12(%ebp), %eax mov eax, DWORD PTR [ebp-12] movl %eax, -8(%ebp) mov DWORD PTR [ebp-8], eax movl $0, %eax mov eax, 0 leave leave ret ret .size main, .-main .ident "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2" .section .note.GNU-stack,"",@progbits n dreapta listingului apare echivalentul instruc!iunilor AT&T n sintaxa Intel. Sintaxa Intel a fost ob!inut" cu: gcc -S prog.c -o - -masm=intel Reguli generale impuse de sintaxa AT&T: n sintaxa AT&T, comentariile sunt delimitate cu semnul # (diez). n sintaxa Intel se folose#te ; (punct #i virgul"). Mnemonicele AT&T #i numele registrelor sunt scrise ntotdeauna cu caractere mici. Acest lucru respect" faptul c" Unix diferen!iaz" literele mari de cele mici. n timp ce Intel sugereaz" utilizarea majusculelor, dar accept" literele mici, AT&T cere litere mici. Numele de registre sunt ntotdeauna precedate de simbolul % (procent). Acest lucru permite asamblorului s" recunoasc" numele de registre. Intel: EAX AT&T: %eax n sintaxa AT&T, operandul destina!ie este ntotdeauna n dreapta, operandul surs" este n stnga. A!adar, operanzii sunt n ordine invers" fa#" de sintaxa Intel. ntotdeauna, la mnemonica instruc!iunilor ma#in" cu operanzi se adaug" un sufix de un caracter, sufix care indic" dimensiunea operazilor. Caracterele sufix sunt b (byte), w (word) #i l (long), indicnd un octet, doi octe!i sau patru octe!i. n caz contrar, GAS va ncerca s" ghiceasc" singur dimensiunea operanzilor. Este indicat ca asamblorul s" nu fie l"sat s"

ghiceasc!, deoarece o poate face gre"it. Intel: mov bx,ax AT&T: movw %ax,%bx n sintaxa AT&T, operanzii imedia#i "i valorile constante sunt ntotdeauna precedate de semnul $ (dolar). Acest lucru permite asamblorului s! recunoasc! operanzi de tip imediat. Intel: mov eax, _const AT&T: movl $_const, %eax Introducem imediatul 0A00BH n registrul EBX: Intel: mov ebx, 0A00BH AT&T: movl $0xa00b, %ebx Introducem imediatul 255 n registrul AL: Intel: mov al, 255 AT&T: movb $255, %al ncarc! n registrul ECX adresa variabilei globale C, total: Intel: mov ecx, total AT&T: movl $total, %ecx n sintaxa AT&T, deplasamentul din metodele de adresare a memoriei sunt valori cu semn plasate n afara parantezelor rotunde care con#in baza, indexul "i factorul de scal!. Intel: [baz! + index " scal! ) deplasament] AT&T: deplasament (baz!, index, scal!) Simbolul semnific! faptul c! deplasamentul este cu semn; poate fi pozitiv sau negativ, lucru care indic! dac! aceast! valoare se adun! sau se scade din restul adresei efective. n mod obi"nuit, vom ntlni explicit semnul minus numai atunci cnd deplasamentul este negativ, lipsa semnului denot! deplasament pozitiv. Deplasamentul "i factorul de scal! sunt op#ionale. Pentru adresarea indirect! "i direct!, sintaxa AT&T folose"te paranteze

rotunde, spre deosebire de sintaxa Intel, care folose!te paranteze p"trate. De exemplu, mov eax, [ebx] mov eax,[d] este scris" n AT&T ca movl (%ebx), %eax movl d,%eax n acest ultim caz, observa#i diferen#a dintre: Intel: mov eax,[d] Intel: mov eax, d AT&T: movl $d, %eax AT&T: movl d, %eax

Prima instruc#iune ncarc" n registrul EAX con#inutul adresat de eticheta d, a doua instruc#iune ncarc" chiar adresa. n sintaxa Intel, dac" dorim s" extragem un element de o anumit" dimensiune, folosim operatorii byte ptr, word ptr sau dword ptr, unde ptr poate s" lipseasc". De exemplu: Intel: mov ax, word [ebp] AT&T: movw (%ebp), %ax sau Intel: mov byte al, [ebx] AT&T: movb (%ebx), %al Dac" exist" deplasament, acesta trebuie pozi#ionat n fa#a parantezelor: Intel: mov dword eax, [ebx-4] AT&T: movl -4(%ebx), %eax Intel: mov al, byte [ebx + edi + 28] AT&T: movb 28(%ebx,%edi), %al Intel: mov ebx, [eax + _variabila] AT&T: movl _variabila(%eax), %ebx Cnd sunt folosite toate cmpurile modului de adresare a memoriei, ntlnim expresii de genul:

Intel: mov edx, [ebx + edi * 8 + _vector] AT&T: movl _vector(ebx,edi,8), %edx Cteva expresii mai pu!in intuitive: Intel: mov ebx, [eax * 4 + vector] ;adresare indexat" AT&T: movl vector(,%eax,4), %ebx #i Intel: mov ecx, [eax + 1] ;adresare bazat" AT&T: movl 1(%eax), %ecx Ne oprim aici. Ca not", aminti!i-v" c" pute!i folosi registrul ESP n interiorul expresiei de calcul a adresei efective, dar numai ca registru de baz".

11.2.2.

Formatul de baz!

Structura necesar" unei func!ii n asamblare pentru a putea fi introdus" direct n programele C (introducerea direct" a instruc!iunilor de asamblare n corpul C) nu difer" foarte mult fa!" de structura func!iilor n limbaj de asamblare studiate pn" acum. Singura diferen!" este c", de aceast" dat", secven!a de instruc!iuni se afl" chiar n fi#ierele surs" C. Compilatorul GNU C este aten!ionat c" urmeaz" o sec!iune scris" n asamblare prin cuvntul cheie asm. Formatul de baz" al unei sec!iuni asm este urm"torul: asm(cod n asamblare ); Codul n asamblare aflat ntre paranteze rotunde trebuie s" respecte un format specific: Instruc!iunile trebuie introduse ntre ghilimele; Dac" sunt prezente mai multe instruc!iuni, acestea trebuie separate printrun caracter de linie nou", \n. Adesea, pentru a face liniile mai u#or de citit, este introdus #i un caracter \t. A doua regul" este necesar" deoarece compilatorul trateaz" codul din sec!iunea asm textual, plasndu-l n codul generat exact a#a cum este scris. Urm"torul exemplu reprezint" func!ia de ie#ire din program: asm(movl $1, %eax\n\tmovl $0, %ebx\n\tint $0x80); Deoarece formatul nu este foarte lizibil, majoritatea programatorilor scriu

instruc!iunile pe linii separate. n acest caz, fiecare instruc!iune trebuie nchis" ntre ghilimele. asm ( movl $1, %eax\n\t movl $0, %ebx\n\t int $0x80); Acest format este mai u#or de citit #i n!eles. Sec!iunea asm poate fi inclus" oriunde n codul surs". Urm"torul program demonstreaz" cum arat" o sec!iune asm ntr-un program. /* global.c AT&T Exemplu care utilizeaz" variabile C */ #include <stdio.h> int a = 50; int b = 60; int rez; int main() { asm ( pusha\n\t movl a, %eax\n\t movl b, %ebx\n\t imull %ebx, %eax\n\t movl %eax, rez\n\t popa); printf(the answer is %d\n, rez); return 0; } Variabilele a, b #i rez sunt definite n programul C ca variabile globale #i sunt folosite n sec!iunea asm. Observa!i c", n interiorul sec!iunii asm, valorile sunt utilizate ca loca!ii de memorie #i nu ca elemente de date imediate. Variabilele pot fi de asemenea folosite n alt" parte a programului. Variabilele de date trebuie declarate ca globale. n interiorul sec!iunii asm nu putem folosi variabile locale. Codul n asamblare generat de compilator arat" astfel: gcc -S global.c -o - -m32 .file "global.c"

.globl a .data .align 4 .type a, @object .size a, 4 a: .long 50 .globl b .align 4 .type b, @object .size b, 4 b: .long 60 .comm rez,4,4 .section .rodata .LC0: .string "the answer is %d\n" .text .globl main .type main, @function main: pushl %ebp movl %esp, %ebp andl $-16, %esp subl $16, %esp #APP # 8 "global.c" 1 pusha movl a, %eax movl b, %ebx imull %ebx, %eax movl %eax, rez popa # 0 "" 2 #NO_APP movl rez, %edx movl $.LC0, %eax movl %edx, 4(%esp) movl %eax, (%esp) call printf movl $0, %eax leave

ret .size main, .-main .ident"GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2" .section .note.GNU-stack,"",@progbits Observa!i c" a #i b au fost definite n segmentul datelor ini!ializate #i au primit valoare, iar rez a fost definit n segmentul datelor neini!ializate. Sintaxa AT&T define#te dou" directive prin care putem declara date neini!ializate, .comm este una dintre ele. Nu intr"m n detalii. Codul generat folose#te prologul #i epilogul C standard, ultimul implementat prin instruc!iunea leave. n cadrul codului generat se afl" o regiune cuprins" ntre simbolurile #APP #i #NO_APP. Aceasta este sec!iunea care con!ine codul specificat cu asm. Observa!i efectul caracterelor \n #i \t asupra amplas"rii codului. Din exemplu reiese nc" o caracteristic" important": secven!a util" de instruc!iuni n asamblare trebuie precedat" de instruc!iunea PUSHA #i ncheiat" cu instruc!iunea POPA. Este important de re!inut c" nainte de execu!ia codului n asamblare trebuie s" salva!i valorile ini!iale ale registrelor, iar la final trebuie s" restaura!i con!inutul acestora deoarece este posibil ca GCC s" foloseasc" acele registre n alt" parte a codului surs" (dac" sunt modificate n interiorul sec!iunii asm, pot ap"rea efecte nedorite). Sintaxa Intel Pn" acum codul inserat n program a respectat sintaxa AT&T. A fost mai u#or pentru noi s" folosim sintaxa AT&T pe o platform" Unix, cu un compilator ce recunoa#te nativ sintaxa AT&T. S" vedem cum se modific" programul anterior dac" specific"m sec!iunea asm n sintaxa Intel. /* global.c Intel - Exemplu care utilizeaz" variabile C */ #include <stdio.h> int a = 50; int b = 60; int rez; int main() { asm (".intel_syntax noprefix\n\t" "pusha\n\t" "mov eax,a\n\t" "mov ebx,b\n\t" "imul eax,ebx\n\t" "mov rez,eax\n\t"

"popa\n\t" ".att_syntax prefix"); printf("the answer is %d\n", rez); return 0; } Observa!i c" la nceputul secven!ei n asamblare am inserat ".intel_syntax noprefix\n\t". Aceasta indic" asamblorului GAS c" urm"toarea secven!" de instruc!iuni n asamblare folose#te sintaxa Intel. noprefix nseamn" c" registrele nu au nevoie de simbolul % ca prefix. Ultima linie, ".att_syntax prefix", indic" asamblorului GAS c" instruc!iunile urm"toare vor fi asamblate n sintaxa implicit", AT&T. n acest caz, compilarea se face n mod obi#nuit: gcc -g stabs -o global global.c m32 Dac" lipsea ultima linie din sec!iunea asm, ".att_syntax noprefix", puteam ob!ine executabilul for!nd compilatorul GCC s" tranduc" tot codul n sintaxa Intel: gcc -g stabs -o global global.c -masm=intel m32 Modificatorul volatile Cnd introducem instruc!iuni n asamblare n programe C trebuie s" ne gndim ce efect ar putea avea procesul de compilare asupra acestora. n etapele de transformare a codului surs" n cod de asamblare, compilatorul poate ncerca s" optimizeze codul scris n asamblare n vederea cre#terii performan!ei. De obicei, acest lucru are loc prin eliminarea func!iilor neutilizate, partajarea registrelor ntre variabile care nu sunt folosite n acela#i timp sau rearanjarea codului pentru o parcurgere mai u#oar". ns" este posibil ca optimizarea s" produc" efecte nedorite, n special asupra func!iilor din sec!iunea asm. Modificatorul volatile, plasat imediat dup" cuvntul cheie asm, indic" compilatorului faptul c" nu este dorit" optimizarea acelei sec!iuni de cod. Formatul este urm"torul: asm volatile (cod n asamblare); Utilizarea __asm__ n unele cazuri, cuvntul asm, utilizat la identificarea unei sec!iuni de cod n asamblare, trebuie modificat. Specifica!iile ANSI C utilizeaz" cuvntul asm n alte scopuri, lucru care mpiedic" utilizarea sa ca identificator de sec!iune n asamblare. Dac" scrie!i cod utiliznd conven!iile ANSI C, trebuie s" utiliza!i

cuvntul cheie __asm__ (dou! caractere underscore). Codul n asamblare din interiorul sec"iunii nu se modific!. Dac! avem nevoie de modificatorul volatile, acesta trebuie scris __volatile__. __asm__ __volatile__ (".intel_syntax noprefix\n\t" "pusha\n\t" "mov eax,a\n\t" "mov ebx,b\n\t" "imul eax,ebx\n\t" "mov rez,eax\n\t" "popa\n\t" ".att_syntax prefix");

11.2.3.

Formatul extins

Formatul de baz! are cteva limit!ri. n primul rnd toate valorile de intrare #i de ie#ire trebuie s! utilizeze variabile globale definite n program. n plus, trebuie s! fim extrem de aten"i s! nu modific!m valorile vreunui registru. Formatul extins pune la dispozi"ie cteva op"iuni adi"ionale ce ne permit s! control!m exact modul n care este interpretat codul n asamblare. Formatul versiunii extinse a sec"iunii asm arat! astfel: asm (cod n asamblare : loca!ii de ie"ire : operanzi de intrare : lista de modific#ri); Acest format are patru sec"iuni, fiecare separat! prin dou! puncte: cod n asamblare - propozi"iile n asamblare propriu zise; loca!ii de ie"ire - registre #i/sau loca"ii de memorie ce vor con"ine valorile de ie#ire la finalul codului n asamblare; operanzi de intrare - registre #i/sau loca"ii de memorie ce con"in valorile de intrare necesare codului din sec"iunea scris! n asamblare; lista de modific#ri - registre ce vor fi modificate de c!tre codul n asamblare. Prezen"a tuturor sec"iunilor nu este obligatorie. Dac! codul n asamblare nu genereaz! valori de ie#ire, sec"iunea loca"iilor de ie#ire poate lipsi. n schimb, separarea sec"iunilor prin dou! puncte se p!streaz!. Doar dac! sec"iunea codului n asamblare nu modific! niciun registru ultimele dou! puncte pot fi omise. n formatul asm de baz! valorile de intrare #i ie#ire erau definite ca variabile globale n programul C #i ncorporate n sec"iunea n asamblare pe baza

numelui acestora. n formatul extins putem atribui valori de intrare !i ie!ire att registrelor ct !i loca"iilor de memorie. Formatul listei de valori de intrare !i ie!ire este: caracter_de_control (variabil!) unde variabila este o variabil# C declarat# n program. n formatul asm extins pot fi folosite att variabile globale ct !i locale. Caracterul de control (constraint) specific# unde trebuie plasat# variabila (pentru valori de intrare) sau unde trebuie depozitat# (pentru valori de ie!ire). Acesta define!te loca"ia final# a unei variabile: registru sau loca"ie de memorie.
Tabelul 11.2 Caractere de control

Caracter de control a b c d S D r q A f m V i n g

Descriere Folose!te registrele %eax, %ax sau %al Folose!te registrele %ebx, %bx sau %bl Folose!te registrele %ecx, %cx sau %cl Folose!te registrele %edx, %dx sau %dl Folose!te registrele %esi sau %si Folose!te registrele %edi sau %di Folose!te orice registru de uz general Folose!te registrul %eax, %ebx, %ecx sau %edx Combin# registrele %eax !i %edx pentru valori de 64 de bi"i Folose!te un registrul pentru variabile n virgul# mobil# Folose!te loca"ia de memorie a variabilei Folose!te numai o loca"ie de memorie direct# Folose!te un ntreg imediat Folose!te un ntreg imediat de valoare cunoscut# Folose!te orice registru sau loca"ie de memorie disponibil#

Pe lng# caracterele de control, valorile de ie!ire pot include modificatori de control. Modificatorii de control indic# modul n care compilatorul trebuie s# trateze operanzii.
Tabelul 11.3 Modificatori de control

Modificator de ie!ire Descriere + Operandul poate fi att citit ct !i scris (read-write) = Operandul poate fi numai scris (write-only). Valoarea anterioar# este nlocuit# cu valoarea de ie!ire curent#. % Operandul poate fi schimbat cu urm#torul dac# este necesar & Operandul poate fi !ters !i reutilizat nainte de finalizarea codului n asamblare.

Urm!torul exemplu asm volatile (".intel_syntax noprefix\n\t" "cld\n\t" "rep\n\t" "stosl\n\t" ".att_syntax prefix\n\t" : /* nicio loca"ie de ie#ire */ : "c" (contor), "a" (valoare), "D" (dest) : "%ecx", "%edi" ); ncarc! valoarea aflat! n registrul EAX n loca"ia de memorie indicat! de adresa dest, de un num!r de ori contor. Linia operanzilor de intrare : "c" (contor), "a" (valoare), "D" (dest) ncarc! contor n ECX, valoare n EAX #i dest n EDI. Aceste informa"ii pot ajuta compilatorul s! optimizeze codul. De exemplu, n timpul opera"iunilor de alocare a registrelor compilatorul ar putea aranja ca valoarea s! se afle deja n registrul EAX sau, dac! codul n asamblare s-ar afla ntr-o bucl!, ar putea p!stra con"inutul EAX de-a lungul execu"iei acesteia. Observa"i c! nu am specificat nimic n sec"iunea loca"iilor de ie#ire. Nu este necesar ca valorile de ie#ire s! fie ntotdeauna precizate. Valorile de intrare ale unor instruc"iuni indic! #i valorile de ie#ire. n cazul nostru, valoarea de ie#ire este deja definit! ca fiind una din valorile de intrare (adresa indicat! de registrul EDI), a#adar aceasta nu mai trebuie specificat! n cmpul loca"iilor de ie#ire. Dar, deoarece nu am definit explicit nicio valoare de ie#ire, este important s! folosim cuvntul cheie volatile. n caz contrar, din moment ce sec"iunea asm nu produce niciun rezultat, compilatorul poate considera toat! sec"iunea inutil! #i renun"! la ea (nu o introduce n fi#ierul executabil). Lista de modific!ri : "%ecx", "%edi" indic! compilatorului faptul c! registrele EAX #i EDI au fost rescrise (valorile acestora la finalul secven"ei n asamblare difer! de cele avute la intrarea n sec"iune). n lista de modific!ri registrele sunt scrise cu prefixul %. Dac! scriem ntr-o loca"ie de memorie trebuie s! includem n list! cuvntul memory. Dac! sunt modifica"i indicatorii de condi"ii din registrul EFLAGS este indicat s! introducem n lista de modific!ri operatorul cc (conditional codes), care anun"!

compilatorul de aceste modific!ri. Din nefericire, directivele extinse folosesc sintaxa AT&T, din acest motiv am inserat n fa"a acestora op"iunea ".att_syntax prefix". Sintaxa GNU Intel define#te numai sintaxa pentru codurile de instruc"iune, nu pentru directive, func"ii, macroinstruc"iuni, etc.. Directivele folosesc nc! sintaxa AT&T. Se poate ntampla s! fie nevoie s! comut!m de la o sintax! la alta chiar #i n interiorul secven"ei n asamblare. n special atunci cnd lucr!m cu operanzi afla"i n memorie, deoarece mecanismul de substitu"ie al operanzilor folose#te sintaxa AT&T. Din acest motiv, n exemplele urm!toare vom folosi numai sintaxa AT&T. Definirea registrelor Urm!toarea secven"! demonstreaz! cum putem declara registre n formatul asm extins. asm (imull %%edx, %%ecx\n\t movl %%ecx, %%eax : =a(rez) : d(val1), c(val2));

Registrul de ie#ire este modificat cu semnul egal; indic!m faptul c! asupra lui pot fi efectuate numai opera"ii de scriere. Compilatorul ncarc! valorile variabilelor val1 #i val2 n registrele EDX #i ECX. Val1 #i val2 pot fi variabile globale sau locale. n ultimul caz, ele se g!sesc n zona de stiv! a programului. Rezultatul generat n registrul EAX este apoi transferat n variabila rez. Observa"i c! registrele au ca prefix dou! semne %% n loc de unul singur. Acest lucru este necesar deoarece, n secven"a n asamblare, fiecare operand este adresat de compilator pe baza unui num!r (placeholder) precedat de semnul %. Compilatorul atribuie fiec!rei valori de intrare sau ie#ire prezente n cmpurile formatului extins un num!r, pe baza pozi"iei sale n list!, ncepnd cu zero. De exemplu: asm (cod n asamblare : =r (rez) : r (val1), r (val2) ); va produce urm!toarele coduri: %0, pentru registrul care con"ine variabila rez. %1, pentru registrul care con"ine variabila val1. %2, pentru registrul care con"ine variabila val2. Metoda permite utilizarea n secven"a de asamblare att a registrelor ct #i a

loca!iilor de memorie. Num"rul total de operanzi este limitat la zece sau la num"rul maxim de operanzi pe care l poate lua o instruc!iune (care este mai mare). Codul n asamblare arat" astfel: imull %1, %2 movl %2, %0 Deoarece GCC identific" operanzii pe baza %0, %1, #.a.m.d, %edx ar fi interpretat ca fiind parametrul %e, care nu exist" #i, n consecin!", ar fi ignorat. Apoi ar ncerca s" g"seasc" simbolul dx, simbol invalid, deoarece nu are prefixul %, dar care oricum nu era ce se inten!ionase. A#adar, pentru o secven!" n asamblare, de exemplu una care nmul!e#te o valoare cu 5, putem declara registrele explicit asm ("leal (%%ebx,%%ebx,4), %%ebx" : "=b" (x) : "b" (x) ); caz n care trebuie s" avem grij" s" folosim dou" simboluri procent, %%, sau putem permite compilatorului s" aleag" registrele. Cu excep!ia cazului n care avem nevoie explicit de un anumit registru, cel mai bine este s" permitem compilatorului s" aleag". Num"rul registrelor este limitat #i se poate ntampla ca GCC s" nu poat" folosi registrele specificate f"r" s" ascund" valorile anterioare. asm ("leal (%1,%1,4), %0" : "=r" (x) : "r" (x) ); Mai mult, dac" dorim ca variabila s" foloseasc" acela#i registru, att pentru intrare ct #i pentru ie#ire, putem specifica registrul atribuit pe baza codului %0. asm ("leal (%0,%0,4), %0" : "=r" (x) : "0" (x) ); Dac" se lucreaz" cu un num"r mare de valori de intrare #i ie#ire, metoda numeric" poate deveni problematic". De aceea, compilatorul GNU pune la dispozi!ie o variant" alternativ", #i anume, declararea unor denumiri. Numele este declarat n sec!iunea care define#te valorile de intrare sau ie#ire #i respect" urm"torul format: %[nume] caracter_de_control (variabil!)

n acest caz, valoarea nume devine identificatorul variabilei. asm (imull %[valoare1], %[valoare2] : [valoare2] =r(val2) : [valoare1] r(val1), 0(val2));

Bibliografie

1. Intel Corporation, Software Developers Manual Basic Architecture, vol. 1, Order Number 243190, 1997. 2. Intel Corporation, Software Developers Manual Instruction Set Reference, vol. 2, Order Number 243191, 1997. 3. Intel Corporation, Software Developers Manual System Programming Guide, vol. 3, Order Number 243192, 1997. 4. Intel Corporation, Intel 80386 Programmers Reference Manual, 1986. 5. Iulian B!descu, Microprocesoare, Printech, Bucure"ti, 2002, ISBN: 973-652-547-3 6. Ubuntu documentation team, Ubuntu Server Guide, 2012, https://help.ubuntu.com/12.04/serverguide/serverguide.pdf. 7. Vasile Lungu, Procesoare INTEL, Programarea n limbaj de asamblare, Edi#ia a II-a, Editura Teora, 2004, ISBN: 973-200099-6. 8. Jeff Dunteman, Assembly Language Step-by-Step, Wiley Publishing, Inc., 2009, ISBN: 978-0-470-49702-9. 9. Sivarama Dandamudi, Guide to Assembly Language Programming in Linux, Springer Science+Bussiness Media, Inc., 2005, ISBN-10: 0-387-25897-3. 10. Richard Stallman, Roland Pesch, Stan Shebs, et al., Debugging with GDB The GNU Source-Level Debugger, Ninth Edition, ver. 20040217, Free Software Foundation, ISBN: 1-882114-77-9. 11. Peter Jay Salzman, Using GNUs GDB Debugger, Tutorial, http://www.cs.cmu.edu/~gilpin/tutorial/ 12. Richard Blum, Professional Assembly Language, Wiley Publishing, Inc., 2005, ISBN: 0-7645-7901-0. 13. Bob Nevelin, Linux Assembly Language Programming, First Edition, Prentice Hall, Inc., 2000, ISBN: 0-13-087940-1. 14. Paul Carter, PC Assembly Language, 2006, http://www.dr paulcarter.com/pcasm/ 15. Robert Platz, Introduction to Computer Organization with x86-64 Assembly Language & GNU/Linux, 2011, http://bob.cs.sonoma. edu/IntroCompOrg_Jan_2011.pdf 16. Yariv Kaplan, Introduction to Protected-Mode, 1997, Articol,

17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30.

Internals.com, http://www.internals.com/articles/protmode/introd uction.htm Randal Bryant, David OHallaron, Computer Systems A Programmers Perspective, 2nd Edition, Pearson Education, Inc, 2011, ISBN: 0-13-610804-0. Drago! Acost"chioaie, Programare C !i C++ pentru Linux, Editura Polirom, 2002, ISBN: 973-681-112-3. blog.interlinked.org, Vim Introduction and Tutorial, Tutorial, http://blog.interlinked.org/tutorials/vim_tutorial.html Free Software Foundation, GCC 4.6.3 Manual, 2010, http://gcc. gnu.org/onlinedocs/gcc-4.6.3/gcc/ NASM Development Team, NASM The Netwide Assembler, ver. 2.10.01, 2012, http://www.nasm.us/xdoc/2.10.01/nasmdoc.pdf Peter Johnson, Yasm User Manual, 2012, http://www.tortall.net /projects/yasm/manual/manual.pdf Tool Interface Standards, Executable and Linkable Format (ELF), Portable Formats Specification, ver. 1.1, http://www.sky free.org/linux/references/ELF_Format.pdf Phillip, Using Assembly Language in Linux, Articol, 2001, http://asm.sourceforge.net//articles/linasm.html Bharata Rao, Inline assembly for x86 in Linux, Articol, 2001, http://www.ibm.com/developerworks/linux/library/l-ia/index.html Brennan Underwood, Brennans Guide to Inline Assembly, ver. 1.1.2.2, Articol, http://www.delorie.com/djgpp/doc/brennan/bren nan_att_inline_djgpp.html Ram Narayan, Linux assemblers: A comparison of GAS and NASM, Articol, 2007, http://www.ibm.com/developerworks/linux /library/l-gas-nasm/index.html iecc.com, Dynamic Linking and Loading, rev. 2.3, Articol, 1999, http://www.iecc.com/linker/linker10.html Ashish Bansal, Shared objects for the object disoriented!, Articol, 2001, http://www.ibm.com/developerworks/library/lshobj/ Baris Simsek, Libraries, EnderUNIX Software Development Team, 2004, http://www.enderunix.org/simsek/articles/ libraries.pdf