Tutorial Limbaj de Asamblare (Assembler) Intel 8086 – Partea 5 – Proceduri

In acest tutorial destinat imbajului de asamblare pentru procesoare din familia Intel 8086 sunt prezentate procedurile. Acestea permit reutilizarea codului si reducerea dimensiunii acestuia insa implica un efort suplimentar generat de trimiterea parametrilor si apel.

Atentie: La procesoarele 80×86 urmatoarea instructiune de executat este determinata de continutul registrelor CS:IP (registrul asociat segmentului de cod CS si pointerul la instructiune IP) ce reprezinta adresa fizica a segmentului de cod si offset-ul in cadrul acestuia.

Instructiunile de salt neconditionat (Ex. JMP) permit salturi in program insa intoarcere la punctul de salt este gestionata in intregime de utilizator care trebuie fie sa indice punctul respectiv printr-o eticheta care ulterior sa fie de o instructiune de salt, fie sa salveze continutul registrului IP.

Apelurile de proceduri, reprezinta salturi la secvente de cod (reutilizabile) declarate de utilizator in corpul procedurii, care permit reintoarcerea la punctul de start. Acest lucru este posibil prin implementarea instructiunilor CALL (apel procedura) si RET (iesire din procedura si intoarcere in programul apelator).

Diferenta dintre CALL si JMP este data de faptul ca prima instructiune salveaza pe stiva inainte de a face saltul adresa instructiunii urmatoare.

Tipuri de CALL

  • near; salveaza pe stiva valoarea pe 16 biti din IP si face salt la prima instructiune din corpul procedurii; are forma interna pe 3 bytes: 1 byte codul operatiei (E8h), 2 bytes reprezentand distanta ca numar de bytes pana la codul procedurii;
  • far; salveaza pe stiva valoarea din CS si apoi din IP; are forma interna pe 5 bytes: 1 byte codul operatiei (9Ah), 2 bytes offset si 2 bytes adresa segemntului.

Structura unei proceduri in assembler

Sintaxa declararii unei proceduri:

Nume_procedura PROC [FAR | NEAR]

…………..

[Nume_procedura] ENDP

Structura generala a unei proceduri scrisa in limbaje de asamblare este:

Nume_procedura PROC [FAR | NEAR]
 Salvare registre
 Bloc prelucrare date cu referirea parametrilor formali
 Stocare rezultate
 Restaurarea registrelor
 RET [nr_octeti]
[Nume_procedura] ENDP
Structura generica proceduri in assembler

Apelul si iesirea din proceduri

Apelul unei proceduri se face prin instructiunea CALL:

  • sintaxa: CALL operand
  • aceasta salveaza pe stiva adresa instructiunii urmatoare (daca saltul este de tip intersegment – far se salveaza inainte si adresa din CS) si executa salt la locatia indicata de operand;
  • tipul operandului este:
Tip operandDescriere
CALL nume_proceduraNumele procedurii apelate reprezinta in esenta o eticheta.
CALL etichetaProcesorul presupune in aceasta situati ca eticheta este locala si atunci face un salt de tip NEAR. Aceasta trebuie sa fie la o distanta cuprinsa in intervalul [-32768,32676] de bytes. A se vedea exemplul de mai jos.
CALL FAR PTR etichetaEticheta este in alt segment. Inlocuieste CS si IP cu segmentul si offsetul etichetei.
CALL registru sau variabilaContinutul din registru sau variabila este copiat in IP dupa ce acesta a fost salvat pe stiva. Deci variabilasau registrul respectiv reprezinta de fapt un pointer near (tine doar offsetul unei proceduri sau etichete)
CALL WORD PTR variabilaContinutul variabilei reprezinta un offset si are loc un salt de tip NEAR. De obicei variabila este reprezentata de o adresare indirecta cu registru index (SI,DI), [SI] sau registru de baza (BX). [BX] si atunci trebuie specificat cati bytes trebuie cititi (trebuie indicat procesorului tipul de salt – near, se citesc 2 octeti; far se citesc 4 octeti). De vazut exemplul cu apeluri indirecte de proceduri.
CALL DWORD PTR adresaContinutul variabilei reprezinta un segment + offset si are loc un salt de tip FAR. De obicei variabila este reprezentata de o adresare indirecta cu registru index (SI,DI), [SI] sau registru de baza (BX). [BX]. De vazut exemplul cu apeluri indirecte de proceduri.
Modalități de apel a unei proceduri în assembler
  • instructiunea CALL se traduce prin secventele de instructiuni:

pentru NEAR

PUSH IP        ; salvare adresa instructiunii urmatoare lui CALL

JMP adresa_salt     ;adresa_salt reprezinta un offset si este indicata de operand

JMP adresa_salt     ;adresa_salt reprezinta un offset si este indicata de operand

Imaginea stivei dupa CALL si la pozitionarea pe prima instructiune din corpul procedurii
   
  Stiva creste pe directia ↑! Adresele scad
SP →adresa( IP ) de intors
  
   

pentru FAR

PUSH CS        ;salvare adresa segment de cod curent

PUSH IP        ; salvare adresa instructiunii urmatoare lui CALL

JMP adresa_salt    ;adresa_salt reprezinta un sehment+offset si este indicata de operand

Imaginea stivei dupa CALL si la pozitionarea pe prima instructiune din corpul procedurii

     
   

Stiva creste pe directia ↑

! Adresele scad

SP →

adresa offset ( IP ) de intors

SP +2 →

Adresa segment (CS) de intors

   
     

Iesirea din proceduri se realizeaza prin instructiunea RET:

  • sintaxa: RET [valoare numerica]
  • aceasta scoate de pe stiva adresa instructiunii urmatoare (daca saltul este de tip intersegment – far se restaureaza dupa IP si CS salvat anterior) si initializeaza registrele care controleaza executarea instructiunilor, IP si CS (ambele daca procedura a fost de tip FAR);
  • daca se da si valoarea numerica optionala are loc curatarea stivei prin modificarea pozitiei curente din stiva (indicata de SP) adunand la SP atatia bytes cati indica valoarea numerica;
  • instructiunea RET se traduce prin secventele de instructiuni:

pentru NEAR

POP IP ;reinitializeaza registrul IP cu valoarea salvata la intrarea in procedura

;cum acest registru contine offsetul instructiunii de executat, programul se ;reia de la instructiunea urmatoare saltului

[add SP, valoare_numerica] ;instructiune optionala care se executa doar daca se da ;instructiunea RET + valoare numerica

pentru FAR

POP IP

POP CS ;reinitializeaza registrul CS cu adresa segmentului de cod

[add SP,valoare_numerica]

  • instructiunea stie ce iesire sa faca in functie de modul in care a fost declarata procedura sau mai exact in functie de tipul apelului FAR sau NEAR; la asamblare fiecare instructiune de tip return este inlocuita cu RETN sau RETF (instructiunile pot fi utilizate – a se vedea exemplul urmator) care reprezinta forma explicita a instructiunii de iesire.

Realizarea unei proceduri fara PROC si ENDP

Exemplul urmator subliniaza modul de interpretare interna a procedurii asemenea unei secvente de cod la care se realizeaza salturi si de la care programul stie sa se intoarca gestionand adresa punctului de start.

Procedura realizeaza suma a doua numere de tip word ale caror valori sunt puse pe stiva iar rezultatul este returnat in registrul CX.

.model small
.286
.stack 100h
.data
	a dw 5
	b dw 3
	s dw ?
.code

	mov AX,@data
	mov DS,AX
	
	push a	;pun valoarea lui a pe stiva
	push b;	;pun valoarea lui b pe stiva

	call NEAR PTR start_procedura	;apel explicit de procedura NEAR

	mov s, CX	;pun rezultatul in s

	mov AX, 4c00h
	int 21h

start_procedura:	;eticheta ce indica inceputul procedurii
	push BP	;salvez valoarea din BP
	mov BP,SP	;initializez BP cu valoarea lui SP pentru a-l utiliza 
;ca reper in citirea datelor de pe stiva
	push AX	;salvez valoarea lui AX
	mov AX,[BP+6]	;copiez in AX valoarea lui a primita pe stiva
;a se vedea figura de mai jos care descrie stiva in acest moment
	add AX,[BP+4]	;adun in AX valoarea lui b primita pe stiva
	mov CX,AX		;pun rezultatul in CX
	pop AX	;restaurez AX
	mov SP,BP	;copiez in SP valoarea din BP
;aduc SP la pozitia reperului
	pop BP	;restaurez SP
	retn		;return de tip NEAR – scote doar IP de pe stiva
end
Imaginea stivei la momentul adunarii celor doua valori de pe stiva
Pozitie in stiva relativa fata de    
BP

SP

 

Stiva creste pe directia ↑

! Adresele scad

BP-2→

SP →

valoare din AX

BP→

SP + 2 →

valoare din BP

BP+2→

SP + 4 →

adresa offset ( IP ) de intors

BP+4→

SP + 6 →

valoare b

BP+6→

SP + 8 →

valoare a

   
     

Acelasi program in limbaj de asamblare se scrie utilizand directivele PROC si ENDP:

.model small
.286
.stack 100h
.data
	a dw 5
	b dw 3
	s dw ?
.code
	mov AX,@data
	mov DS,AX
	push a
	push b
	call suma
	mov s, CX	
	mov AX, 4c00h
	int 21h
suma PROC
	push BP
	mov BP,SP
	push AX
	mov AX,[BP+6]
	add AX,[BP+4]
	mov CX,AX
	pop AX
	mov SP,BP
	pop BP
	ret
ENDP
end

Proceduri de tip FAR

Procedurile FAR sunt proceduri care se gasesc in alt segment decat cel curent. Pentru a exemplifica o astfel de situatie se definesc explicit segmentele si se renunta la definirea simplificata a unui program utilizand directivele .model .code .stack .data. De exemplu, se scrie programul assembler care aduna doua numere de tip double trimitand parametrii prin referinta pe stiva.

Variabile SEGMENT	;declar un segment numit Variabile in care declar 
;datele
a	dd	1234677
b	dd	3456123
sum	dd	?
Variabile ENDS	;sfarsit segment de date

Stiva SEGMENT	;declar segment numit Stiva in care rezerv 512 octeti
			;pentru a-i utiliza pe post de stiva
	dw	100h	dup(?)
baza	label word	;declar o variabila simbolica de tip word pentru a 
			;lua offset-ul in stiva
Stiva ENDS		;sfarsit segment de stiva

Principal SEGMENT	;declar segment numit Parincipal in care scriu codul 
;programului principal
	ASSUME CS:Principal,DS:Variabile,SS:Stiva
			;se realizeaza asocieri logice intre registrele de 
;segment si segmentele utilizate – NU inseamna ca 
;sunt si initializate registrele
start:
	mov AX, Variabile	;initializez DS
	mov DS,AX
	mov AX,Stiva	;initializez SS
	mov SS,AX
	mov SP,offset baza	;initializez SP
	
	mov AX,offset a	;pun pe stiva adresa lui a
	push AX
	mov AX,offset b	;pun pe stiva offset b
	push AX
	mov AX,offset sum	;pun pe stiva offset sum
	push AX
	
	call FAR PTR suma	;apel procedura FAR

	mov AX,4c00h
	int 21h
Principal ENDS	;sfarsit segment de cod principal

Procedura SEGMENT	;definesc un alt segment de cod in care scriu 
;procedura
	ASSUME CS:Procedura
			;asociere logica
suma PROC FAR	;definesc procedura
	push BP	;salvez BP
	mov BP,SP	;initializez BP cu valoarea lui SP
	push AX	;salvez AX
	mov SI,[BP+10]	;copiez in SI offset a
	mov DI,[BP+8]	;copiez in DI offset b
	mov AX,[SI]		;copiez in AX cuvant inferior din a
	add AX,[DI]		;adun la AX cuvant inferior din b
	push SI		;salvez continut SI – adica affset a
	mov SI,[BP+6]	;copiez in SI offset sum
;a se vedea figura urmatoare ce descrie stiva in acest punct
	mov [SI],AX		;copiez in sum suma cuvintelor inferioare
	pop SI		;restaurez SI – adica offset a
	mov AX,[Si+2]	;adun cu carry cuvinte superioare din a si b
	adc AX,[DI+2]
	mov SI,[BP+6]
	mov [SI+2],AX	;copiez in partea superioara a sum rezultatul
	pop AX		;restaurez AX
	mov SP,BP
	pop BP
	ret 6			;curat stiva stergand logic cele 3 offset-uri
suma ENDP
Procedura ENDS
end start
Imaginea stivei la momentul copierii in sum a rezultatului adunarii cuvintelor inferioare din a si b
Pozitie in stiva relativa fata de    
BP

SP

   
BP-4→

SP →

valoare din SI

Stiva creste pe directia ↑

! Adresele scad

BP-2→

SP + 2 →

valoare din AX

BP→

SP + 4 →

valoare din BP

BP+2→

SP + 6 →

adresa offset ( IP ) de intors

BP+4→

SP + 8 →

adresa segment (CS) de intors

BP+6→

SP + 10 →

offset sum

BP+8→

SP + 12 →

offset b

BP+10→

SP + 14 →

offset a

   
     

Reguli la scriere procedurilor:

  • secventele de cod ce compun corpul procedurii realizeaza operatii cu caracter general;
  • utilizarea registrelor in proceduri implica salvarea continutului acestora pe stiva inainte de efectuarea prelucrarilor si restaurarea lor de pe stiva inainte de a iesi; pentru acest lucru se utilizeaza instructiunile PUSH (pune pe stiva) si POP (scoate de pe stiva). De exemplu:
ProcTest PROC
push AX
push BX
push CX
…………
Pop CX
Pop BX
Pop AX
ret
ENDP

Atentie: Restaurarea registrelor cu POP se face in ordine inversa salvarii cu PUSH.

  • citirea datelor de pe stiva se realizeaza numai cu registrul BP

Apeluri indirecte de proceduri

Se realizeaza prin intermediul pointerilor la functii. De exemplu programul in limbaj de asamblare care aduna doua numere de tip word prin intermediul unei proceduri.

.model small
.286
.stack 100h
.data
	pointer_functie		dw ?	;pointer la functie de tip NEAR
	pointer_functie_far	DD ?	;pointer la functie de tip FAR
	a dw 5
	b dw 3
	s dw ?
	dif dw ?
.code

	mov AX,@data
	mov DS,AX
	
	mov AX, offset suma		;incarc in AX offset proecdura
	mov pointer_functie,AX		;initializez pointerul la procedura

	mov AX,a	;trimit parametrii prin registrii
	mov BX,b
	call pointer_functie	;apelez procedura	NEAR

	mov s,CX
			; incarc pointerul cu offsetul si adresa segmentului
	mov WORD PTR pointer_functie_far,offset diferenta
	mov WORD PTR pointer_functie_far+2,seg diferenta
	mov AX,a	;trimit parametrii prin registrii
	
call pointer_functie_far	;apelez procedura	FAR
; sau call FAR PTR diferenta	;apel prin nume

	mov dif,CX
	mov AX, 4c00h
	int 21h
suma PROC
	add AX,BX
	mov CX,AX
	ret
ENDP
diferenta PROC FAR	;declar explicit procedura de tip FAR
	sub AX,BX
	mov CX,AX
	ret
ENDP
end

In exemplul anterior procesorul stie ce tip de procedura sa apeleze pentru ca pointerii sunt declarati ca fiind de tip word, respectiv, double, ceea ce inseamna ca poate sa contina doar offsetul procedurii apelate (in cazul near) sau adresa completa, segment de cod + offset (pentru far).

In caz ca exista un vector de variabile de tip pointeri la functii, la apelul procedurii trebuie indicat explicit tipul acesteia prin WORD PTR (pentru NEAR) sau DWORD PTR (pentru FAR).

Daca in exemplul anterior incarc in SI offsetul de inceput al variabilei pointer_functie (simulez utilizarea unui vector) si atunci apelurile echivalente sunt:

call WORD PTR [SI]    ;apel de tip near pentru suma

call DWORD PTR [SI+2] ;apel de tip far pentru diferenta

Daca se da apelul call [SI] atunci implicit se considera ca apelul este de tip NEAR si se vor citi 2 octeti de la adresa [SI] reprezentand offsetul saltului. De aceea este important (mai ales in cazul salturilor de tip FAR) sa se indice explicit tipul saltului prin WORD sau DWORD.

Transmiterea parametrilor de intrare in proceduri

Pentru a exemplifica fiecare metoda, se realizeaza un program care verifica daca elementele de tip student (definit prin nume, varsta si numar matricol) ale unui vector au campul varsta cu valori cuprinse intr-un interval definit.

Se realizeaza utilizand:

  • variabile declarate in memorie in segmentul de date; situatia este echivalenta in limbajele de nivel inalt cu utilizarea variabilelor declarate global in interiorul subprogramelor; prima varianta a programului implementeaza modelul small de definire a segmentelor si a tipului de memorie.
.model small
.286
.stack 100h
.data
	student struc	;definesc structura de date
		nume db 10 dup (?)
		varsta db ?
		nr_matricol dw ?
	ends
	dimStudent equ size student	;dimensiune student 13 octeti
 
	s1 student <'Popescu',22,1234>
	s2 student <'Ionescu',21,1235>
	mes_eroare db 'Depasire limite!','$'
	mes_corect db 'Date corecte!','$'
 
	lim_inf db 14
	lim_sup db 89
.code
Validare PROC 	 ;procedura valideaza doar varsta studentului s1
	push BP
	mov BP,SP
	push aX
 
	xor AX,AX
	mov AL,lim_inf	;copiez in AL valoarea limitei inferioare
	mov AH,lim_sup	;copiez in AH valoarea limitei superioare
	cmp AL,s1.varsta	;compar varsta cu limita inferioara
	ja eroare 		;daca varsta e mai mica, afisez mesaj
	cmp AH,s1.varsta	;compar varsta cu limita superioara
	jb eroare		;daca varsta e mai mare,afisez mesaj
 
	mov AH,09h	;afisez mesaj date corecte
	lea DX,mes_corect
	int 21h
	jmp final
 
eroare:
	mov AH,09h	;afisez mesaj eroare
	lea DX,mes_eroare
	int 21h
final:
	pop AX
	mov SP,BP
	pop BP
	ret	;termin procedura
ENDP
 
start:			;indic de unde incep instructiunile programului
	mov AX,@data
	mov DS,AX
 
	call validare
 
	mov AX,4c00h
	int 21h
 
end start	;indic terminarea programului dar si de unde incepe 
                ;executia codului

A doua versiune a programului assembler utilizeaza segmente definite de programator.

Date SEGMENT	;segmentul de date
	student struc
		nume db 10 dup (?)
		varsta db ?
		nr_matricol dw ?
	ends
	dimStudent equ size student
	s1 student <'Popescu',22,1234>
	s2 student <'Ionescu',21,1235>
	mes_eroare db 'Depasire limite!','$'
	mes_corect db 'Date corecte!','$'
	lim_inf db 14
	lim_sup db 89
Date ENDS
 
Stiva SEGMENT		;segmentul aferent stivei
	dw 100 dup (?)	;rezerv 100 de cuvinte pentru stiva
	varf label word	;definesc o eticheta pentru a extrage adresa bazei stivei
Stiva ENDS
 
Main SEGMENT	;segmentul aferent codului
	ASSUME CS:Main,DS:Date,SS:Stiva	;fac asocieri logice
 
Validare PROC 	;procedura valideaza doar varsta studentului s1
	push BP
	mov BP,SP
	push aX
	xor AX,AX
	mov AL,lim_inf	;copiez in AL valoarea limitei inferioare
	mov AH,lim_sup	;copiez in AH valoarea limitei superioare
	cmp AL,s1.varsta	;compar varsta cu limita inferioara
	ja eroare 		;daca varsta e mai mica, afisez mesaj
	cmp AH,s1.varsta	;compar varsta cu limita superioara
	jb eroare		;daca varsta e mai mare,afisez mesaj
 
	mov AH,09h	;afisez mesaj date corecte
	lea DX,mes_corect
	int 21h
	jmp final
 
eroare:
	mov AH,09h	;afisez mesaj eroare
	lea DX,mes_eroare
	int 21h
final:
	pop AX
	mov SP,BP
	pop BP
	ret	;termin procedura
ENDP
 
start:			;indic de unde incep instructiunile programului
	mov AX,Date		;incarc in DS adresa segmentului de date
	mov DS,AX
	mov AX,Stiva	;incarc in SS adresa segmentului de stiva
	mov SS,AX
	mov AX,varf		;initializez SP cu offsetul curent in stiva
	mov SP,AX
 
	call validare	;apelez procedura
 
	mov AX,4c00h
	int 21h
Main ENDS
 
end start	;indic terminarea programului dar si de unde incepe 
                ;executia codului

Marele dezavantaj al acestei metode de transmitere a parametrilor este diminuarea caracterului de generalitate pe care procedura trebuie sa-l aiba, deoarece este conditionata de existenta variabilelor (in cazul anterior lim_inf, lim_sup si s1) definite in segmentul de date.

  • registrele pentru a transmite parametrii de intrare; consider mesajele de avertizare ca fiind declarate global si atunci trebuie doar sa trimit in procedura limitele intervalului si valoarea de verificat; pentru a realiza acest lucru folosesc AX pentru limitele intervalului (lim_inf in AL si lim_sup in AH) si CL pentru valoarea de verificat; se observa ca din toate datele studentului intereseaza doar varsta si atunci trimit doar aceasta data.
.model small
.286
.stack 100h
.data
	student struc
		nume db 10 dup (?)
		varsta db ?
		nr_matricol dw ?
	ends
	dimStudent equ size student	;dimensiune student 13 octeti
	s1 student <'Popescu',22,1234>
	mes_eroare db 'Depasire limite!','$'
	mes_corect db 'Date corecte!','$'
	lim_inf db 14
	lim_sup db 89
.code
Validare PROC 	;procedura valideaza varsta oricarui student, aceasta ;fiind trimisa prin CL
	push BP
	mov BP,SP
	push AX	;salvez valoarea din AX, poate mai trebuie
	push CX;
 
	cmp AL,CL	;compar varsta cu limita inferioara
	ja eroare 	;daca varsta e mai mica, afisez mesaj
	cmp AH,CL	;compar varsta cu limita superioara
	jb eroare	;daca varsta e mai mare,afisez mesaj
 
	mov AH,09h	;afisez mesaj date corecte
	lea DX,mes_corect
	int 21h
	jmp final
 
eroare:
	mov AH,09h	;afisez mesaj eroare
	lea DX,mes_eroare
	int 21h
final:
	pop CX
pop AX
	mov SP,BP
	pop BP
	ret	;termin procedura
ENDP
start:		;indic de unde incep instructiunile programului
	mov AX,@data
	mov DS,AX
 
	mov AL,lim_inf
	mov AH,lim_sup
	xor CX,CX
	mov CL,s1.varsta
 
	call validare
 
	mov AX,4c00h
	int 21h
end start

Dezavantajul metodei deriva din numarul limitat de registre si din faptul ca instructiunile salvare/restaurare a valorilor registrelor pe/de pe stiva consuma resurse (de exemplu daca valoarea parametrului de intrare ce a fost trimisa prin intermediul registrului AX este necesara in procedura dupa efectuarea altor prelucrari trebuie sa ne asiguram ca nu o pierdem salvand-o pe stiva).

  • stiva pe post de zona de transfer a datelor catre proceduri; utilizarea stivei in acest sens se face in doua moduri in functie de semnificatia valorilor de pe stiva: adresa variabilei (referinta) sau valoarea ei; indiferent de modul ales, secventa se rezuma la a salva valorile respective pe stiva (prin instructiunea PUSH) inainte de a apela procedura si la a le accesa in procedura prin intermediul registrului BP; primul program exemplifica transmiterea parametrilor pe stiva prin valoare, iar al doilea transmite referinta variabilelor de intrare.
.model small
.286
.stack 100h
.data
	student struc
		nume db 10 dup (?)
		varsta db ?
		nr_matricol dw ?
	ends
	dimStudent equ size student	;dimensiune student 13 octeti
	s1 student <'Popescu',22,1234>
	mes_eroare db 'Depasire limite!','$'
	mes_corect db 'Date corecte!','$'
 
	lim_inf db 14
	lim_sup db 89
.code
Validare PROC 	;procedura valideaza varsta oricarui student, aceasta ;fiind trimisa prin stiva
	push BP
	mov BP,SP
	push AX	
	push CX
			;* a se vedea figura stivei de mai jos
 
	mov AL,[BP+6]
	mov AH,[BP+7]
	mov CL,[BP+4]
	cmp AL,CL	;compar varsta cu limita inferioara
	ja eroare 	;daca varsta e mai mica, afisez mesaj
	cmp AH,CL	;compar varsta cu limita superioara
	jb eroare	;daca varsta e mai mare,afisez mesaj
 
	mov AH,09h	;afisez mesaj date corecte
	lea DX,mes_corect
	int 21h
	jmp final
eroare:
	mov AH,09h	;afisez mesaj eroare
	lea DX,mes_eroare
	int 21h
final:
	pop CX
	pop AX
	mov SP,BP
	pop BP
	ret 4	;termin procedura si golesc stiva
ENDP
start:			;indic de unde incep instructiunile programului
	mov AX,@data
	mov DS,AX
 
	mov AL,lim_inf	;salvez pe stiva limitele intervalului
	mov AH,lim_sup	
	push AX
	xor CX,CX
	mov CL,s1.varsta	;salvez pe stiva varsta studentului
	push CX
 
	call validare	;apelez procedura
 
	mov AX,4c00h
	int 21h
end start

In cazul acestui program, la momentul * stiva este descrisa de figura urmatoare:

Imaginea stivei la momentul incarcarii de pe stiva a valorilor parametrilor de intrare
Pozitie in stiva relativa fata de    
BP

SP

   
BP-4→

SP →

valoare din CX

Stiva creste pe directia ↑

! Adresele scad

BP-2→

SP + 2 →

valoare din AX

BP→

SP + 4 →

valoare din BP

BP+2→

SP + 6 →

adresa offset ( IP ) de intors

BP+4→

SP + 8 →

valoarea varsta student; doar primul octet.

BP+6→

SP + 10 →

limite interval; sunt scrise pe un cuvant in forma:[[lim_sup][lim_inf]]

   
     

Atentie ! In cazul trimiterii parametrilor de tip sir de caractere este indicat sa se utilizeze metoda prin referinta deoarece punerea unui sir pe stiva este o operatie ineficienta ce consuma spatiu si cicluri masina. Din acest motiv, s-a trimis doar valoarea varstei studentului pe stiva si nu intreaga structura.

Al doilea exemplu de program assembler descrie trimiterea referintelor pe stiva.

.model small
.286
.stack 100h
.data
	student struc
		nume db 10 dup (?)
		varsta db ?
		nr_matricol dw ?
	ends
	dimStudent equ size student	;dimensiune student 13 octeti
	s1 student <'Popescu',22,1234>
	mes_eroare db 'Depasire limite!','$'
	mes_corect db 'Date corecte!','$'
	lim_inf db 14
	lim_sup db 89
.code
Validare PROC 	;procedura valideaza varsta oricarui student, acesta 
                        ;este trimis prin stiva utilizand referinta sa
	push BP
	mov BP,SP
	push AX	
	push CX
	push SI
	push DI
			;* a se vedea figura stivei de mai jos
 
	mov SI,[BP+8]
	mov AL,[SI]
	mov SI,[BP+6]
	mov AH,[SI]
	mov SI,[BP+4]
	cmp AL,[SI].varsta	;compar varsta cu limita inferioara
	ja eroare 			;daca varsta e mai mica, afisez mesaj
	cmp AH,[SI].varsta	;compar varsta cu limita superioara
	jb eroare			;daca varsta e mai mare,afisez mesaj
 
	mov AH,09h	;afisez mesaj date corecte
	lea DX,mes_corect
	int 21h
	jmp final
 
eroare:
	mov AH,09h	;afisez mesaj eroare
	lea DX,mes_eroare
	int 21h
final:
	pop DI
	pop SI
pop CX
	pop AX
	mov SP,BP
	pop BP
	ret 6		;termin procedura si golesc stiva
ENDP
start:			;indic de unde incep instructiunile programului
	mov AX,@data
	mov DS,AX
 
	mov AX,offset lim_inf
	push AX
	mov AX,offset lim_sup
	push AX
	mov AX, offset s1
	push AX
 
	call validare
 
	mov AX,4c00h
	int 21h
end start
Imaginea stivei la momentul incarcarii de pe stiva a valorilor parametrilor de intrare
Pozitie in stiva relativa fata de    
BP

SP

   
BP-8→

SP →

valoarea din DI

 
BP-6→

SP + 2 →

valoarea din SI

 
BP-4→

SP + 4 →

valoare din CX

Stiva creste pe directia ↑

! Adresele scad

BP-2→

SP + 6 →

valoare din AX

BP→

SP + 8 →

valoare din BP

BP+2→

SP + 10 →

adresa offset ( IP ) de intors

BP+4→

SP + 12 →

adresa offset student

BP+6→

SP + 14 →

adresa offset a lim_sup

BP+8→

SP + 16 →

Adresa offset a lim_inf

   
     

Atentie ! In cazul trimiterii parametrilor prin referinta pe stiva orice modificare a valorii lor utilizand o adresare indirecta (bazata sau indexata) are loc in segmentul de date si valoarea se pastreaza si dupa iesirea din procedura.

Transmiterea parametrilor de iesire din proceduri

Intoarcerea rezultatelor din proceduri se realizeaza prin intermediul registrelor AX, BX, CX, DX. De exemplu, programul care aduna doua numere de tip double trimise prin valoare returneaza suma in registrele CX (cuvantul inferior) si DX (cuvantul superior).

Utilizarea procedurilor din fisiere incluse

[urmeaza]

MACRODEFINITII

[urmeaza]

[urmeaza]