Scrigroup - Documente si articole

Username / Parola inexistente      

Home Documente Upload Resurse Alte limbi doc  
AccessAdobe photoshopAlgoritmiAutocadBaze de dateCC sharp
CalculatoareCorel drawDot netExcelFox proFrontpageHardware
HtmlInternetJavaLinuxMatlabMs dosPascal
PhpPower pointRetele calculatoareSqlTutorialsWebdesignWindows
WordXml


INTRODUCERE IN LIMBAJUL DE ASAMBLARE INTEL

calculatoare



+ Font mai mare | - Font mai mic



INTRODUCERE IN LIMBAJUL DE ASAMBLARE INTEL

1.Registrii microprocesorului Intel



Registrii (sau registrele) microprocesorului reprezinta locatii de memorie speciale aflate direct pe cip; din aceasta cauza reprezinta cel mai rapid tip de memorie. Alt lucru deosebit legat de registri este faptul ca fiecare dintre acestia au un scop bine precizat, oferind anumite functionalitati speciale, unice. Exista patru mari categorii de registri: registrii de uz general, registrul indicatorilor de stare (flags), registrii de segment si registrul pointer de instructiune.

Fig. Registrii de uz general - acumulator, index de baza, contor si de date

2.1. Registrii de uz general

Registrii de uz general sunt implicati in operarea majoritatii instructiunilor, drept operanzi sursa sau destinatie pentru calcule, copieri de date, pointeri la locatii de memorie sau cu rol de

contorizare. Fiecare dintre cei 8 registrii de uz general AX, BX, CX, DX, SP, BP, DI,SI sunt registrii pe 16 biti pentru microprocesorul 8086, iar de la procesorul 80386 incoace au devenit registrii pe 32 de biti, denumiti, respectiv: EAX, EBX, ECX, EDX, ESP, EBP, EDI, ESI (litera E provine de la Extended extins in engleza). Mai mult, cei mai putin semnificativi 8 biti ai registrilor AX, BX, CX, DX formeaza respectiv registrii AL, BL, CL, DL (litera L provine de la Low jos in engleza), iar cei mai semnificativi 8 bitiai acelorasi registrii formeaza registrii AH, BH, CH, DH (litera H provine de la High inalt in engleza).

Fig. Registrii de uz general index si pointer

Ne vom concentra in continuare atentia asupra registrilor generali pe 16 biti; fiecare dintre acestia poate stoca o valoare pe 16 biti, poate fi folosit pentru stocarea unei valori din memorie sau poate fi utilizat pentru operatii aritmetice si logice. Spre exemplu, urmatoarele instructiuni:

MOV BX, 2

MOV DX, 3

ADD BX, DX

Incarca valoarea 2 in registrul BX, valoarea 3 in registrul DX, aduna cele doua valori iar rezultatul (5) este memorat in registrul BX. In exemplul anterior putem utiliza oricare dintre registrii de uz general in locul registrilor BX si DX. In afara proprietatii de a stoca valori si de a folosi drept operanzi sursa sau destinatie pentru instructiunile de manipulare a datelor, fiecaredintre cei opt registri de uz general au propria "personalitate". Vom vedea in continuare care sunt caracteristicile specifice fiecaruia dintre registrii de uz general.

Registrul AX (EAX)

Registrul AX (EAX) este denumit si registrul acumulator, fiind principalul registru de uz general utilizat pentru operatii aritmetice, logice si de deplasare de date. Totdeauna operatiile de inmultire si impartire presupun implicarea registrului AX. Unele dintre instructiuni sunt optimizate pentru a se executa mai rapid atunci cand este folosit AX. In plus, registrul AX este folosit si pentru toate transferurile de date de la/catre porturile de Intrare/Iesire. Poate fi accesat pe portiuni de 8, 16 sau 32 de biti, fiind referit drept AL (cei mai putin semnificativi 8 biti din AX), AH (cei mai semnificativi 8 biti din AX), AX (16 biti) sau EAX (32 de biti).

Prezentam in continuare alte cateva exemple de instructiuni ce utilizeaza registrul AX. De remarcat este faptul ca transferurile de date se fac pentru instructiunile (denumite si mnemonice) Intel de la dreapta spre stanga, exact invers decat la Motorola, unde transferul se face de la stanga la dreapta.

Instructiunea: MOV AX, 1234H incarca valoarea 1234H (4660 in zecimal) in registrul acumulator AX. Dupa cum spuneam, cei mai putini semnificativi 8 biti ai registrului AX sunt identificati de AL (A-Low) iar cei mai semnificativi 8 biti ai aceluiasi registru sunt identificati ca fiind AH (A-High). Acest lucru este utilizat pentru a lucra cu date pe un octet, permitand ca registrul AX sa fie folosit pe postul a doi registri separati (AH si AL). Aceeasi regula este valabila si pentru registrii de uz general BX, CX, DX. Urmatoarele trei instructiuni seteaza registrul AH cu valoarea 1, incrementeaza cu 1 aceasta valoare si apoi o copiaza in registrul AL:

MOV AH, 1

INC AH

MOV AL, AH

Valoarea finala a registrului AX va fi 22 (AH = AL = 2).

Registrul BX (EBX)

Registrul BX (Base), sau registrul de baza poate stoca adrese pentru a face referire la diverse structuri de date, cum ar fi vectorii stocati in memorie. O valoare reprezentata pe 16 biti stocata in registrul BX poate fi utilizata ca fiind o portiune din adresa unei locatii de memorie ce va fi accesata. Spre exemplu, urmatoarele instructiuni incarca registrul AH cu valoarea din memorie de la adresa 21.

MOV AX, 0

MOV DS, AX

MOV BX, 21

MOV AH, [ BX ]

Se observa ca am incarcat valoarea 0 in registrul DS inainte de a accesa locatia de memorie referita de registrul BX. Acest lucru este datorat segmentarii memoriei (segmentare discutata mai in detaliu in sectiunea consacrata registrilor de segment); implicit, atunci cand este folosit ca pointer de memorie, BX face referire relativa la registrul de segment DS

adresa la care face referire este o adresa relativa la adresa de segment continuta in registrul DS).

Registrul CX (ECX)

Specializarea registrului CX (Counter) este numararea; de aceea, el se numeste si registrul contor. De asemenea, registrul CX joaca un rol special atunci cand se foloseste instructiunea LOOP. Rolul de contor al registrului CX se observa imediat din exemplul urmator:

MOV CX, 5

start:

<instructiuni ce se vor executa de 5 ori>

SUB CX, 1JNZ start

Deoarece valoarea initiala a lui CX este 5, instructiunile cuprinse intre eticheta start si instructiunea JNZ se vor executa de 5 ori (pana cand registrul CX devine 0). Instructiunea SUB CX, 1 decrementeaza registrul CX cu valoarea 1 iar instructiunea JNZ start determina saltul inapoi la eticheta start daca CX nu are valoarea 0.

In limbajul microprocesorului exista si o instructiune speciala legata de ciclare. Aceasta este instructiunea LOOP, care este folosita in combinatie cu registrul CX. Liniile de cod urmatoare sunt echivalente cu cele anterioare, dar aici se utilizeaza instructiunea LOOP:

MOV CX, 5

start:

<instructiuni ce se vor executa de 5 ori>

LOOP start

Se observa ca instructiunea LOOP este folosita in locul celor doua instructiuni SUB si JNZ anterioare; LOOP decrementeaza automat registrul CX cu 1 si executa saltul la eticheta specificata (start) daca CX este diferit de zero, totul intr-o singura instructiune.

Registrul DX (EDX)

Registrul de uz general DX (Data register), denumit si registrul de date, poate fi folosit in cazul transferurilor de date Intrare/Iesire sau atunci cand are loc o operatie de inmultire sau de impartire. Instructiunea IN AL, DX copiaza o valoare de tip Byte dintr-un port de intrare, a carui adresa se afla in registrul DX. Urmatoarele instructiuni determina scrierea valorii 101

in portul I/O 1002:

MOV AL, 101MOV DX, 1002

OUT DX, AL

Referitor la operatiile de inmultire si impartire, atunci cand impartim un numar pe 32 de biti la un numar pe 16 biti, cei mai semnificativi 16 biti ai deimpartitului trebuie sa fie in DX. Dupa impartire, restul impartirii se va afla in DX. Cei mai putin semnificativi 16 biti ai deimpartitului trebuie sa fie in AX iar catul impartirii va fi in AX. La inmultire, atunci cand se

inmultesc doua numere pe 16 biti, cei mai semnificativi 16 biti ai produsului vor fi stocati in DX iar cei mai putin semnificativi 16 biti in registrul AX.

Registrul SI

Registrul SI (Source Index) poate fi folosit, ca si BX, pentru a referi adrese de memorie. De exemplu, secventa de instructiuni urmatoare:

MOV AX, 0

MOV DS, AX

MOV SI, 33

MOV AL, [ SI ]

Incarca valoarea (pe 8 biti) din memorie de la adresa 33 in registrul AL. Registrul SI este, de asemenea, foarte folositor atunci cand este utilizat in legatura cu instructiunile dedicate tipului STRING (sir de caractere).

Secventa urmatoare :

CLD

MOV AX, 0

MOV DS, AX

MOV SI, 33

LODSB

nu numai ca incarca registrul AX cu valoarea de la adresa de memorie referita de registrul SI, dar aduna, de asemenea, valoarea 1 la SI. Acest lucru este deosebit de eficient atunci cand se acceseaza secvential o serie de locatii de memorie, cum ar fi sirurile de caractere. Instructiunile de tip STRING se pot repeta de mai multe ori, astfel incat o singura instructiune

poate avea ca efect sute sau mii de operatii.

Registrul DI

Registrul DI (Destination Index) este utilizat in mod asemanator registrului SI. In secventa de instructiuni urmatoare:

MOV AX, 0

MOV DS, AX

MOV DI, 1000

ADD BL, [ DI ]

se aduna la registrul BL valoarea pe 8 biti stocata la adresa 1000. Registrul DI este putin diferit fata de registrul SI in cazul instructiunilor de tip string; daca SI este intotdeauna pe post de pointer sursa de memorie, registrul DI serveste drept pointer destinatie de memorie. Mai mult, in cazul instructiunilor de tip string, registrul SI adreseaza memoria relativ la

registrul de segment DS, in timp ce DI contine referiri la memorie relativ la registrul de segment ES. In cazul in care SI si DI sunt utilizati cu alte instructiuni, ei fac referire la registrul de segment DS.



Registrul BP

Pentru a intelege mai bine rolul registrilor BP si SP, a sosit momentul sa spunem cateva lucruri despre portiunea de memorie denumita stiva (in engleza stack). Stiva reprezinta o portiune speciala de locatii adiacente din memorie. Aceasta este continuta in cadrul unui segment de memorie si identificata de un selector de segment memorat in registrul

SS (cu exceptia cazului in care se foloseste modelul nesegmentat de memorie in care stiva poate fi localizata oriunde in spatiul de adrese liniare al programului). Stiva este o portiune a memoriei unde valorile pot fi stocate si accesate pe principul LIFO (Last In - First Out), drept urmare ultima valoare stocata in stiva este prima ce va fi citita din stiva. De regula, stiva

este utilizata la apelul unei proceduri sau la intoarcerea dintr-un apel de procedura (principalele instructiuni folosite sunt CALL si RET).

Registrul pointer de baza, BP (Base Pointer) poate fi utilizat ca pointer de

Fig. Structura stivei

Registrul pointer de baza, BP (Base Pointer) poate fi utilizat ca pointer de memorie precum registrii BX, SI si DI. Diferenta este aceea ca, daca BX, SI si DI sunt utilizati in mod normal ca pointeri de memorie relativ la segmentul DS, registrul BP face referire relativ la segmentul de stiva SS. Principiul este urmatorul: o modalitate de a trece parametrii unei subrutine este aceea de a utiliza stiva (acest lucru se intampla in mod obisnuit in limbajele de nivel inalt, C sau Pascal, spre exemplu). Daca stiva se afla in portiunea de memorie referita de registrul de segment SS (Stack Segment), datele se afla in mod normal in segmentul de memorie referit de

catre DS, registrul segment de date. Deoarece BX, SI si DI se refera la segmentul de date, nu exista o modalitate eficienta de a folosi registrii BX, SI, DI pentru a face referire la parametrii salvati in stiva din cauza ca stiva este localizata intr-un alt segment de memorie. Registrul BP ofera rezolvarea acestei probleme asigurand adresarea in segmentul de stiva. Spre exemplu, instructiunile:

PUSH BP

MOV BP, SP

MOV AX, [ BP+4 ]

fac sa se acceseze segmentul de stiva pentru a incarca registrul AX cu primul parametru trimis de un apel C unei rutine scrise in limbaj de asamblare. In concluzie, registrul BP este conceput astfel incat sa ofere suport pentru accesul la parametri, variabile locale si alte necesitati legate de accesul la portiunea de stiva din memorie.

Registrul SP

Registrul SP (Stack Pointer), sau pointerul de stiva, retine de regula adresa de deplasament a urmatorului element disponibil in cadrul segmentului de stiva. Acest registru este, probabil, cel mai putin "general" dintre registrii de uz general, deoarece este dedicat mai tot timpul

administrarii stivei.

Registrul BP face in fiecare clipa referire la varful stivei - acest varf al stivei reprezinta adresa locatiei de memorie in care va fi introdus urmatorul element in stiva. Actiunea de a introduce un nou element in stiva se numeste "impingere" (in engleza push); de aceea, instructiunea respectiva poarta numele de PUSH. In mod asemanator, operatia de scoatere a unui element din varful stivei poarta, in engleza, numele de pop, iar instructiunea echivalenta operatiei se numeste POP.

Este permisa stocarea valorilor in registrul SP precum si modificarea valorii sale prin adunare sau scadere la fel ca si in cazul celorlalti registri de uz general; totusi, acest lucru nu este recomandat daca nu suntem foarte siguri de ceea ce facem. Prin modificarea registrului SP, vom modifica adresa de memorie a varfului stivei, ceea ce poate avea efecte neprevazute,

aceasta pentru ca instructiunile PUSH si POP nu reprezinta unicele modalitati de utilizare a stivei.

Indiferent daca apelam o subrutina sau ne intoarcem dintr-un astfel de apel de subrutina, fie procedura sau functie, in acest caz este folosita stiva. Unele resurse de sistem, precum tastatura sau ceasul de sistem, pot folosi stiva in momentul trimiterii unei intreruperi la microprocesor. Acest lucru presupune ca stiva este folosita continuu, deci daca se modifica registrul SP (adica adresa stivei), datele din noile locatii de memorie nu vor mai fi cele corecte. In concluzie, registrul SP nu trebuie modificat in mod direct; el este modificat automat in urma instructiunilor POP, PUSH, CALL, RET. Oricare dintre ceilalti registri de uz general pot fi modificati in mod direct in orice moment.

2.2. Registrul pointer de instructiuni (IP)

Registrul pointer de instructiuni este folosit, intotdeauna, pentru a stoca adresa urmatoarei

instructiuni ce va fi executata de catre microprocesor. Pe masura ce o instructiune este executata, pointerul de instructiune este incrementat si se va referi la urmatoarea adresa de memorie (unde este stocata urmatoarea instructiune ce va fi executata). De regula, instructiunea ce urmeaza a fi executata se afla la adresa imediat urmatoare instructiunii ce a fost executata, dar exista si cazuri speciale (rezultate fie din apelul unei subrutine prin instructiunea CALL, fie prin intoarcerea dintr-o subrutina, prin instructiunea RET). Pointerul de instructiuni nu poate fi modificat sau citit in mod direct; doar instructiuni speciale pot incarca acest registru cu o noua valoare. Registrul pointer de instructiune nu specifica pe de-a intregul adresa din memorie a urmatoarei instructiuni ce va fi executata, din aceeasi cauza a segmentarii memoriei. Pentru a aduce o instructiune din memorie, registrul CS ofera o adresa de baza iar registrul pointer de instructiuneindica adresa de deplasament plecand de la aceasta adresa de baza.

Fig. Registrii de segment, pointerul de instructiuni si registrul

indicatorilor de stare

2.3. Registrul indicatorilor de stare (FLAGS) pe 16 biti contine informatii legate de starea microprocesorului precum si de rezultatele ultimilor instructiuni executate. Un indicator de stare (flag) este in sine o locatie de memorie de 1 bit ce indica starea curenta a microprocesorului si modalitatea sa de operare. Un indicator se spune ca "este setat" daca are

valoarea 1 si "nu este setat" in caz contrar. Indicatorii de stare se modifica dupa executia unor instructiuni aritmetice sau logice.

Exemple de indicatori de stare:

- C (Carry) indica aparitia unei cifre binare de transport in cazul unei adunari sau imprumut in cazul unei scaderi;

- O (Overflow) apare in urma unei operatii aritmetice. Daca este setat, inseamna ca rezultatul nu incape in operandul destinatie;

- Z (Zero) indica faptul ca rezultatul unei operatii aritmetice sau logice este zero;

- S (Sign) indica semnul rezultatului unei operatii aritmetice;

- D (Direction) - cand este zero, procesarea elementelor sirului se face de la adresa mai mica la cea mai mare, in caz contrar este invers;

- I (Interrupt) controleaza posibilitatea microprocesorului de a raspunde la evenimente externe (apeluri de intrerupere);

- T (Trap) este folosit de programele de depanare (de tip debugger), activand sau nu posibilitatea executiei programului pas cu pas. Daca este setat, UCP intrerupe fiecare instructiune, lasand programul depanator sa execute programul respectiv pas cu pas;

- A (Auxiliary carry) suporta operatii in codul BCD. Majoritatea programelor nu ofera suport pentru reprezentarea numerelor in acest format, de aceea se utilizeaza foarte rar;

- P (Parity) este setat in conformitate cu paritatea bitilor cei mai putin semnificativi ai unei operatii cu date. Astfel, daca rezultatul unei operatii contine un numar par de biti 1, acest indicator este setat. Daca numarul de biti 1 din rezultat este impar, atunci indicatorul PF este zero. Este folosit de regula de programe de comunicatii, dar Intel a introdus acest indicator nu pentru a indeplini o anumita functionalitate, ci pentru a asigura compatibilitatea cu vechile microprocesoare ale familiei x86.

3.4 Registrii de segment

Proprietatile registrilor de segment     sunt in stransa legatura cu notiunea de segmentare a memoriei. Premisa de la care se pleaca este urmatoarea: 8086 este capabil sa adreseze 1MB de memorie, astfel ca sunt necesare adrese pe 20 de biti pentru a cuprinde toate locatiile din

spatiul de 1 MB de memorie. Totusi, registrele utilizate sunt registre pe 16 biti, deci a trebuit sa se gaseasca o solutie pentru aceasta problema.

Solutia gasita se numeste segmentarea memoriei in acest caz memoria de

1MB este impartita in 16 segmente de cate 64 KB (16*64 KB = 1024 KB = 1 MB).

Notiunea de segmentare a memoriei presupune utilizarea unor adrese de memorie formate din doua parti. Prima parte reprezinta adresa segmentului iar cea de-a doua portiune reprezinta adresa de deplasament, sau offset-ul.

3. ELEMENTE ALE LIMBAJULUI DE ASAMBLARE

3.1 Formatul general al unei instructiuni in limbaj de asamblare

O linie de cod scrisa in limbaj de asamblare are urmatorul format general:

<nume> <instructiune/directiva> <operanzi> <;comentariu>

unde:

<nume> - reprezinta un nume simbolic optional;

<instructiune/directiva> - reprezinta mnemonica (numele) unei instructiuni sau a unei directive;

<operanzi> - reprezinta o combinatie de unul, doi sau mai multi operanzi (sau chiar nici unul), care pot fi constante, referinte

de memorie, referinte de registri, siruri de caractere, in functie de structura particulara a instructiunii;

<;comentariu> - reprezinta un comentariu optional ce poate fi plasat dupa caracterul ";" pana la sfarsitul liniei respective de cod.

3.2 Nume de variabile si etichete

Numele folosite intr-un program scris in limbaj de asamblare pot identifica variabile numerice, variabile sir de caractere, locatii de memorie sau etichete. Spre exemplu, urmatoarea secventa de cod, care calculeaza valoarea lui trei factorial (3! = 1 x 2 x 3 = 6) cuprinde cateva nume de variabile si etichete:

.MODEL small

.STACK 200h

.DATA

Valoare_Factorial DW ?

Factorial DW ?

.CODE

Trei_Factorial PROC

MOV ax, @data

MOV ds, ax

MOV [Valoare_Factorial], 1

MOV [Factorial], 2

MOV cx, 2

Ciclare:

MOV ax, [Valoare_Factorial]

MUL [Factorial]

MOV [Valoare_Factorial], ax

INC [Factorial]

LOOP Ciclare

RET

Trei_Factorial ENDP

END

Numele Valoare_Factorial si Factorial sunt utilizate pentru definirea a doua variabile de tip word (pe 16 biti), Trei_Factorial identifica numele procedurii (subrutinei) ce contine codul pentru calculul factorialului, permitand apelul sau din alta parte a programului. Ciclare reprezinta un nume de eticheta, identificand adresa instructiunii MOV ax, [Valoare_Factorial], astfel incat instructiunea LOOP folosita mai jos sa poata face un salt inapoi la aceasta instructiune. Numele de variabile pot contine urmatoarele caractere: literele a-z si A-Z, cifrele de la 0-9 precum si caracterele speciale _ (underscore - liniuta de subliniere), @ ("at" in engleza - citit si "a rond" sau "coada de maimuta"), $ si ?. Se poate folosi si caracterul punct (".") drept prim caracter al numelui unei etichete. Cifrele 0-9 nu pot fi utilizate pe prima pozitie a numelui; de asemenea, nu pot fi folosite nume care sa contina un singur caracter $ sau ?. Fiecare nume poate fi definit o singura data (numele sunt unice) si pot fi utilizate ca operanzi de oricate ori se doreste intr-un program. Un nume poate sa apara intr-un program singur pe o linie (linia respectiva nu mai contine alta instructiune sau directiva). In acest caz, valoarea numelui este data de adresa instructiunii sau directivei de pe linia urmatoare din program.



De exemplu, in secventa urmatoare:

JMP scadere

scadere:

SUB AX, CX

urmatoarea instructiune care va fi executata dupa instructiunea JMP scadere va fi instructiunea SUB AX, CX. Exemplul anterior este echivalent cu secventa:

JMP scadere

scadere: SUB AX, CX

Exista unele avantaje atunci cand scriem instructiunile pe linii separate. In primul rand, atunci cand scriem un nume de eticheta pe o

singura linie, este mai usor sa folosim nume lungi de etichete fara a strica "forma" programului scris in limbaj de asamblare. In al doilea rand, este mai usor sa adaugam ulterior o noua instructiune in dreptul etichetei daca aceasta nu este scrisa pe aceeasi linie cu instructiunea.

Numele variabilelor sau etichetelor folosite intr-un program nu trebuie sa se confunde cu numele rezervate de asamblor, cum ar fi numele de directive si instructiuni, numele registrilor, etc. De exemplu, o declaratie de genul:

ax DW 0

BYTE:

nu poate fi acceptata, deoarece AX este numele registrului acumulator, AX, iar BYTE reprezinta un cuvant cheie rezervat.

Orice nume de eticheta ce apare pe o linie fara instructiuni sau apare pe o linie cu instructiuni trebuie sa aiba semnul ":" dupa numele ei.

Tototdata, se incearca sa se dea un nume sugestiv etichetelor din program.

Fie urmatorul exemplu:

CMP AL, 'a'

JB Nu_este_litera_mica

CMP AL, 'z'

JA Nu_este_litera_mica

SUB AL, 20H ; se transforma in litera mare

Nu_este_litera_mica:

comparativ cu:

CMP AL, 'a'

JB x5

CMP AL, 'z'

JA x5

SUB AL, 20H ; se transforma in litera mare

x5:

Daca in primul caz am folosit un nume sugestiv de eticheta (Nu_este_litera_mica), in cazul al doilea, identic din punct de vedere al functionalitatii cu primul, eticheta a fost denumita x5, absolut nesugestiv!

Observatie:

Limbajul de asamblare nu este case sensitive. Aceasta semnifica faptul ca, intr-un program scris in limbaj de asamblare, numele de variabile, etichete, instructiuni, directive, mnemonice etc., pot fi scrise atat cu litere mari cat si cu litere mici, nefacandu-se diferenta intre ele (Nu _ este _ litera _ mica este acelasi lucru cu nu_este_litera_mica sau Nu_Este_Litera_Mica

etc.).

3.3 Directive de segment simplificate

Datorita faptului ca registrii microprocesorului 8086 sunt registrii pe 16 biti, s-a impus folosirea unor segmente de memorie de cate 64 Ko (maxim cat se poate adresa avand la dispozitie 16 biti - 64 Ko = 2 ^ 16 = 65536). Intr-un program scris in limbaj de asamblare (vom folosi in continuare prescurtarea ASM) exista trei segmente: segmentul de cod, segmentul de date si segmentul de stiva.

Directivele de segment (fie sub forma standard, fie sub forma simplificata) sunt necesare in orice program scris in limbaj de asamblare

pentru a defini si controla utilizarea segmentelor iar directiva END este folosita intotdeauna pentru a incheia codul programului.

Exemple de directive de segment simplificate sunt:

.STACK

.CODE

.DATA

.MODEL

DOSSEG

END

.STACK,.CODE,.DATA definesc, respectiv, segmentele de stiva, de cod si de date.

De exemplu, .STACK 200H defineste o stiva de 512 octeti (in ASM valorile ce sunt incheiate cu litera H semnifica faptul ca este vorba despre hexazecimal). O astfel de valoare pentru stiva este suficienta in mod normal; unele programe, insa (indeosebi cele recursive) pot necesita dimensiuni mai mari ale stivei.

Directiva .CODE marcheaza inceputul segmentului de cod.

Directiva .DATA marcheaza inceputul segmentului de date, adica locul in care vom plasa variabilele de memorie. Reprezentativ aici este faptul ca trebuie incarcat in mod explicit registrul de segment DS cu valoarea '@data' inaintea accesarii locatiilor de memorie in segmentul definit de .DATA. Avand in vedere ca un registru de segment poate fi incarcat fie dintr-un registru general fie dintr-o locatie de memorie dar nu poate fi incarcat direct cu o constanta, registrul de segment DS este incarcat in general printr-o secventa de doua instructiuni:

mov ax, @data

mov ds, ax

(se poate folosi si alt registru general in locul lui AX).

Secventa anterioara semnifica faptul ca DS se va referi catre segmentul de date ce incepe cu directiva .DATA.

Consideram in continuare un exemplu de program ce afiseaza textul memorat in DataString pe ecran:

;Program p01.asm

.MODEL small ;se specifica modelul de memorie

;SMALL

.STACK 200H ;se defineste o stiva de 512 octeti

.DATA ;se specifica inceputul segmentului de

;date

DataString DB 'Hello!$' ;se defineste variabila

;DataString, initializata cu valoarea

;'Hello!'

.CODE ;inceputul segmentului de cod al

;programului

ProgramStart: ;orice program are o eticheta de

;inceput

mov bx,@data ;secventa ce seteaza registrul DS sa

;faca referire la segmentul de date ce

;incepe cu .DATA

mov ds,bx

mov dx, OFFSET DataString ;se incarca in DX adresa

;variabilei DataString

mov ah,09 ;codul functiei DOS de afisare a unui

;string

int 21H ;apelul DOS de afisare a string-ului

mov ah, 4cH ;codul functiei DOS de terminare a

;programului

int 21H ;apelul DOS de terminare

;a programului

END ProgramStart ;directiva de terminare a codului

;programului

Explicatii:

Se pot introduce comentarii intr-un program ASM prin folosirea ';'. Tot ce urmeaza dupa ';' si pana la sfarsitul liniei este considerat comentariu.

Nu are importanta daca programul este scris folosind litere mari sau mici (nu este 'case sensitive').

Fara cele doua instructiuni care seteaza registrul DS catre segmentul definit de .DATA, functia de afisare a string-ului nu ar fi functionat cum trebuie. Variabila DataString se afla in segmentul .DATA si nu poate fi accesata daca DS nu este pozitionat catre acest segment. Acest lucru se explica in modul urmator: atunci cand facem apelul DOS de afisare a unui string, trebuie sa parcurgem intreaga adresa de tipul segment:offset a string-ului in DS:DX. De aceea, de abia dupa ce am incarcat DS cu segmentul .DATA si DX cu adresa (offset-ul) lui DataString avem o referinta completa segment:offset catre DataString.

Observatii:

Nu trebuie sa incarcam in mod explicit registrul de segment CS deoarece DOS face acest lucru automat in momentul cand rulam un program. Astfel, daca CS nu ar fi deja setat la momentul executiei primei instructiuni din program, procesorul nu ar sti unde sa gaseasca instructiunea si programul nu ar rula niciodata. In mod asemanator, registrul de segment SS este setat de DOS inainte de executia programului si de regula ramane nemodificat pe perioada executiei programului.

Cu registrul de segment DS lucrurile stau altfel. In timp ce registrul CS se refera la intructiuni (cod), SS se refera ('pointeaza') la stiva, DS 'pointeaza' la date. Programele nu manipuleaza direct instructiuni sau stive dar au de-a face in mod direct cu date. De asemenea, programele vor acces la date situate in segmente diferite in orice moment. Se poate dori incarcarea in DS a unui segment, accesarea datelor din acel segment si apoi incarcarea lui DS cu un alt segment pentru a accesa un bloc diferit de date. In programe mici sau medii nu vom avea nevoie de mai mult de un segment de date dar programe mai complexe folosesc deseori segmente de date multiple.



Urmatorul program va afisa un caracter pe ecran, folosind incarcarea registrului ES in locul lui DS.

;Program p02.asm

.MODEL small

.STACK 200H

.DATA

OutputChar DB 'B' ;definirea variabilei OutputChar

;initializata cu valoarea 'B'

.CODE

ProgramStart:

mov dx, @data

mov es, dx ;spre deosebire de programul anterior,

;se foloseste ES pentru specificarea

;segmentului de date

mov bx, offset OutputChar ;se incarca BX cu adresa

;variabilei OutputChar

mov dl, es:[bx] ;se incarca AL cu valoarea de la

;adresa explicita es:[bx]

;(adresare indexata)

mov ah,02 ;codul functiei DOS de afisare a unui caracter int 21H

;apelul DOS de executie a afisarii

mov ah, 4cH ;codul functiei DOS de terminare a

;programului

int 21H ;apelul DOS de terminare

;a programului

END ProgramStart ;directiva de terminare a codului

;programului

DOSSEG este directiva ce face ca segmentele dintr-un program sa fie grupate conform conventiilor Microsoft de adresare a segmentelor.

Directiva .MODEL Este directiva ce specifica modelul de memorie pentru un program ASM ce foloseste directive de segment simplificate.

Definitii:

'near' inseamna adresa (offset-ul) pe 16 biti din cadrul aceluiasi segment, in timp ce 'far' inseamna o adresa completa de tip segment:offset, din cadrul altui segment decat cel curent.

Modelele de memorie ce se pot specifica prin intermediul directivei

.MODEL sunt:

tiny - atat codul cat si datele programului incap in acelasi segment de 64 Ko. Atat codul cat si datele sunt de tip near

small - codul programului trebuie sa fie intr-un singur segment de 64 Ko si datele intr-un bloc separat de 64Ko; codul si datele sunt near

medium - codul programului poate fi mai mare decat 64 Ko dar datele trebuie sa fie intr-un singur segment de 64 Ko. Codul este far, datele sunt near

compact - codul programului poate fi intr-un singur segment, datele pot fi mai mari de 64 Ko. Codul este near, datele sunt far

large - atat codul cat si datele pot depasi 64Ko, dar nici un masiv de date nu poate depasi 64 Ko. Atat codul cat si datele sunt far

huge - atat codul cat si datele pot depasi 64 Ko si masivele de date pot depasi 64 Ko. Atat codul cat si datele sunt far. Pointerii la elementele dintr-un masiv sunt far

In continuare sunt prezentate cateva exemple legate de modalitatile

de declarare a variabilelor si de adresare a memoriei:

var1 DW 01234h ;se defineste o variabila word cu

;valoarea 1234h

var2 DW 01234 ;se defineste o variabila word cu valoarea zecimala 1234 (4D2 in hexa)

var3 RESW 1 ;se rezerva spatiu pentru o variabila

;word (de valoare 0)

var4 DW ABCDh ;atribuire ilegala!

; Memoria poate fi adresata folosindu-se patru registri:

; SI -> Implica DS

; DI -> Implica DS

; BX -> Implica DS

; BP -> Implica SS ! (nu este foarte des utilizat)

Exemple:

mov ax,[bx] ; ax <- word in memorie referit de BX

mov al,[bx] ; al <- byte in memorie referit de BX

mov ax,[si] ; ax <- word referit de SI

mov ah,[si] ; ah <- byte referit de SI

mov cx,[di] ; di <- word referit de DI

mov ax,[bp] ; AX <- [SS:BP] Operatie cu stiva!

; In plus, sunt permise BX+SI si BX+DI:

mov ax,[bx+si]

mov ch,[bx+di]

; Deplasamente pe 8 sau 16 biti:

mov ax,[23h] ; ax <- word in memorie DS:0023

mov ah,[bx+5] ; ah <- byte in memorie [DS:BX+5]

mov ax,[bx+si+107] ; ax <- word la adresa [DS:BX+SI+107]

mov ax,[bx+di+47] ; ax <- word la adresa [DS:BX+DI+47]

; ATENTIE: copierea din memorie in memorie este ilegala!

;Totdeauna trebuie sa se treaca valoarea copiata printr-un registru

mov [bx],[si] ;Ilegal

mov [di],[si] ;Ilegal

; Caz special: operatiile cu stiva!

pop word [var] ; var <- [SS:SP]

.4 Adrese instructiuni generale

o        MOV - mutare de informatie,

o        PUSH - punere de informatii in memoria organizata ca o stiva,

o        POP - aducerea informatiei din memoria stiva;

instructiuni de intrare/iesire

o        IN - depunerea in registrul acumulator a informatiei stocate in registrul de intrare/iesire (portul de date),

o        OUT - scrierea in portul de date a informatiei aflate in registrul acumulator;

instructiuni aritmetice

o        adunare (ADD, ADC, INC etc.),

o        scadere (SUB, DEC, NEG, CMP etc.),

o        inmultire (MUL, IMUL etc.),

o        impartire (DIV, IDIV etc.);

instructiuni de manipulare a sirurilor de biti

o        operatii logice (NOT, AND, OR, XOR, TEST),

o        deplasare (SHL, SAL, SHR, SAR),

o        rotire (ROL, ROR, RCL, RCR);

instructiuni de transfer

o        salt neconditionat (CALL, RET, JMP),

o        salt conditionat - prin testarea indicatorilor de conditii (JC, JNC, JE, JG, JL etc.),

o        cicluri (LOOP etc.),

o        intreruperi (INT, IRET etc.);

instructiuni de sincronizare externa: HLT, WAIT, NOP etc.





Politica de confidentialitate | Termeni si conditii de utilizare



DISTRIBUIE DOCUMENTUL

Comentarii


Vizualizari: 2049
Importanta: rank

Comenteaza documentul:

Te rugam sa te autentifici sau sa iti faci cont pentru a putea comenta

Creaza cont nou

Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved