420 likes | 501 Views
Transferul parametrilor pentru proceduri
E N D
Transferul parametrilor pentru proceduri Programele scrise în LNI folosesc anumite convenţii pentru transmiterea parametrilor către subprograme. Compilatorul translatează o instrucţiune de apel a unui subprogram astfel: depune în stivă (push) argumentele subprogramului şi apelează apoi subprogramul, cu o instrucţiune de apel (call). În funcţie de compilator argumentele sunt puse în stivă într-o anumită ordine. În cazul în care se leagă o procedură scrisă în LA cu un program scris într-un LNI trebuie cunoscut modul de transmitere a parametrilor şi convenţiile stabilite de limbajul respectiv pentru apel de subprogram (nume externe, valori returnate). Parametrii pot fi transmişi prin valoare sau prin referinţă. În Pascal şi în C se cunosc ambele mecanisme de transmitere a parametrilor. Limbajele de nivel înalt folosesc pentru returnarea de valori către programul apelant, următoarele registre: (AL) - pentru valori de 1 octet; (AX) - pt. valori de 2 octeţi, sau adresă de tip NEAR; (EAX)- valori de 4 octeţi sau adresă de tip NEAR la 386/486; (DX,AX)- valori de 4 octeţi sau pointer FAR, pt. 286; (EDX,EAX)- valori de 8 octeţi sau pointer FAR, pt. 386/486;
Pentru valori mai mari de 4 octeţi, limbajul C consideră valoarea întoarsă în zona de memorie alocată pentru segmentul de date, şi returnează în (DX:AX) pointerul către acea zonă. Limbajul PASCAL rezervă o zonă de date în stivă: zona rezervată în stivă şi offsetul către aceasta se realizează de către programul apelant; procedura returnează în (DX:AX) pointerul la zonă. Descărcarea stivei se face în programul apelant, procedura terminându-se cu RET, sau pentru descărcarea unor argumente se poate termina cu RET număr_argumente*dimensiune. Deci, în principiu, programul apelant realizează operaţiile: - depune argumentele în stivă; - apelează procedura; - descarcă stiva; Variabilele locale într-o procedură se folosesc pentru a economisi spaţiu de memorie (cu menţiunea că valorile lor nu se transmit în afara procedurii). Spaţiul de memorie necesar pentru variabilele locale se rezervă în stivă şi el este eliberat la terminarea execuţiei procedurii.
Alocarea de spaţiu pentru variabilele locale se realizează cu o secvenţă de forma: push bp mov bp,sp sub sp,n ; n = număr de octeţi alocaţi; Pentru accesarea variabilelor locale se vor utiliza adresări de forma: [BP - 2], [BP - 6], etc. iar pentru argumente, de forma: [ BP + 2 ], [ BP + 4 ], etc. argument equ <[bp+6]> var_loc equ <[bp-2]> p1 proc far push bp ; salvare valoare BP mov bp,sp ; iniţializare cu vârful curent al stivei sub sp,2 ; rezervare spaţiu pt. var_loc, 2 octeţi mov var_loc,0 ; iniţializare varaibilă locală . . . . . . . . . . mov ax,argument ; se ia argumentul transmis prin stivă add var_loc,ax ; utilizarea variabilei locale . . . . . . . . . .
mov sp,bp ; eliberarea spaţiului rezervat var_loc pop bp ; refacerea valorii lui BP ret ; sau ret 2, dacă se descarcă stiva în procedură p1 endp Dacă descărcarea stivei nu se face în procedură, atunci în programul apelant trebuie descărcată stiva cu: add sp, 2
Convenţiile utilizate de limbajele de nivel înalt pentru transferul parametrilor pentru proceduri Să considerăm o procedură, definită în PASCAL: procedure modul (a : integer; var b : real); begin . . . . . . end; iar apelul de forma: modul (x, y); Pentru această procedură se va genera secvenţa: push bp mov bp,sp BP salvare BP . . . . . . + 2 adresa de revenire mov ax,[bp+8];(AX)x + 4 adr_off var. b . . . . . . + 6 adr_seg var. b les di,[bp+4] + 8 valoarea var. a ;(ES):(DI) adresa lui y . . . . . .
; în final se va descărca stiva pop bp ret 6 Pentru apelul acestei proceduri se va genera secvenţa următoare: mov ax,x push ax ; depune în stivă valoarea parametrului x mov di, offset y push ds ; depune adresa de segment a parametrului y push di ; depune offsetul parametrului y call modul ; apelul procedurii În limbajul C, argumentele sunt puse în ordine inversă faţă de ordinea din lista de apel, în care apar (adică de la dreapta la stânga). Adresele de revenire pot fi de tip NEAR, ca în exemplul anterior, sau de tip FAR, în funcţie de modul de definire al procedurii.
Pointerii salvaţi în stivă, ca referinţă de parametru sau ca adresă de revenire respectă definiţia modelului de memorie stabilit în directiva model. De exemplu stiva va arăta astfel, pentru un singur argument: - modelul medium push bp SP, BP salvare bp mov bp,sp + 2 adr revenire - offset mov di,[bp+6] adr revenire - segment mov ax,[di] ; acces argument + 6 adresa argument ; tip cuvânt - modelul large push bp SP, BP salvare bp mov bp,sp + 2 adr revenire - offset les di,[bp+6] adr revenire - segment mov ax,es:[di] ; acces argument + 6 adr argument – offset ; tip cuvânt adr arg. – segment
Pentru a nu modifica prea multe linii, în funcţie de modelul utilizat se pot utiliza directivele de asamblare condiţionată: Ptr_FAR equ 1 . . . . . . . . push bp mov bp,sp . . . . . . . . ifdef Ptr_FAR les di,[bp+6] mov ax,es:[di] else mov di,[bp+6] mov ax,[di] endif care dacă este definită va considera modelul large, iar dacă nu este definită va considera modelul medium.
Transferul parametrilor pentru subprograme în PASCAL şi C program schimba_vectori; type tip_vector = array [1..20] of real; var vector1, vector2 : tip_vector; n,i : integer; {$F+} {$L SCHIMB.OBJ} procedure InterSchimb (var v1, v2 : tip_vector; lung: word); External; begin { se citesc : dimensiunea şi cei doi vectori } InterSchimb (vector1, vector2, sizeof(vector1)); { se afişează cei doi vectori după interschimbare } end.
Procedura Interschimb (fişierul SCHIMB.OBJ) este următoarea: .model TPascal ; sau model large,Pascal .code stiva struc val_BP dw ? IP_rev dw ? ; sau adr_rev dd ? CS_rev dw ? lung dw ? offs_sir2 dw ? ; sau adr_sir1 dd ? seg_sir2 dw ? offs_sir1 dw ? ; sau adr_sir2 dd ? seg_sir1 dw ? stiva ends public InterShimb InterSchimb proc far push bp mov bp, sp push ds ; se salvează registrele de lucru
push si push es push di push ax push cx ; urmează iniţializările de adrese şi contor mov es, [bp].seg_sir1 ; sau les di, [bp].adr_sir1, sau mov di, [bp].offs_sir1 ; les di, [bp+8] mov ds, [bp].seg_sir2 ; sau lds si, [bp].adr_sir2, sau mov si, [bp].offs_sir2 ; lds si, [bp+12] mov cx, [bp].lung ; sau mov cx, [bp+6] iar: mov al, ds:[si] xchg al, es:[di] mov ds:[si], al inc si inc di loop iar
pop cx ; refacerea registrelor salvate în stivă pop ax pop di pop es pop si pop ds ret 10 ; se descarcă stiva de cei 10 octeţi InterSchimb endp end Linia de declarare a procedurii poate fi şi de forma: InterSchimb proc far Ad_sir1:dword, Ad_sir2:dword, lung:word iar în acest caz preluarea parametrilor se poate face mai simplu: les di,Ad_sir2 lds si,Ad_sir1 mov cx,lung
;function Suma (sir: tip_vector; n:word):integer;External; .model large, Pascal public Suma .code Suma proc far adr_sir equ <[bp+8]> n equ <[bp+6]> s equ <[bp-2]> ; variabila locală pt. sumă push bp mov bp, sp sub sp, 2 ; rezervare spaţiu pt. variabila locală s push ds ; salvarea registrelor de lucru push si push cx lds si, adr_sir ; iniţializare adresă, contor, şi suma mov cx, n mov ax, 0 mov s, ax
cld ; direcţia de parcurgere a şirului jcxz gata ; dacă contorul a fost 0 s-a terminat adun: lodsw add s, ax loop adun gata: mov ax, s pop cx pop si pop ds mov sp, bp ; eliberarea spaţiului alocat variabilei locale s pop bp ret 6 ; descărcarea stivei de parametrii Suma endp end
Să considerăm, acum, şi cazul limbajului C. Vom rescrie funcţia suma(). Întrucât codul generat de compilatorul C transformă denumirile parametrilor funcţiei suma() adăugându-le caracterul ”_” la începutul lor, codul modulului apelat cu numele suma() se va numi de fapt _suma(); acelaşi lucru se întâmplă şi pentru ceilalţi parametri utilizaţi în ambele module. .model small, C .code public _suma _suma proc push bp mov bp, sp push cx push ds push si mov cx, [bp+8] lds si, [bp+4] mov ax, 0 ; iniţializarea sumei cu 0
aduna: add ax, [si] add si, 2 loop aduna pop si pop ds pop cx pop bp ret _suma endp end
#include <stdio.h> extern "C" int suma (int vect[], int dim); void main(void) { int i, dim, vect[100]; printf("Numarul de elemente din vector:"); scanf("%d", &dim); printf("Elementele vectorului:\n"); for (i=0; i<dim; i++) { printf("vect[%d]=", i+1); scanf("%d", &vect[i]); } printf("Suma elementelor vectorului este: %d\n", suma(vect, dim)); }
Avantajele utilizării limbajului de asamblare - multe medii şi compilatoare LNI prezintă facilităţi de inserare de linii scrise în limbaj de asamblare (C, Pascal, LabView, etc.). - componente ale sistemului de operare, şi ale altor aplicaţii, care sunt considerate drept critice şi performante sunt realizate în LA. - programele sunt hibride: ele conţin linii scrise în LNI, dar pot conţine şi linii în LA. - cunoaşterea mecanismelor fine ale procesorului, pentru a le folosi în diferite aplicaţii. -> prog. mai eficiente în limbajele evoluate. - depanarea unui program poate trece de sursă, şi ajunge la depanarea codului obiect, în care caz e necesar cunoaşterea LA. - motivul pentru care secvenţele critice se scriu în LA, şi nu în limbaje de nivel înalt: compilatorul are "cunoştinţe limitate" asupra întregului program, dar el trebuie să genereze un set generalizat de instrucţiuni maşină, care vor lucra în toate situaţiile, dar nu vor fi optime în situaţii particulare. Exemplu: Să se însumeze elementele unui vector, iar rezultatul să se depună într-o variabilă de memorie.
mov var_mem, 0 ; varianta LNI mov si, lung_vect*2 - 2 ; ultimul element: vect + lungime*2 - 2 iar: mov ax, vect[si] add var_mem, ax sub si, 2 jnz iar mov ax, 0 ; varianta LA mov si, lung_vect* - 2 ; ultimul element: vect + lungime*2 - 2 iar: add ax, vect[si] sub si, 2 jnz iar mov var_mem, ax
Un alt exemplu, tot foarte simplu, dacă considerăm secvenţa generată, în C, pentru o secvenţă de program ce realizează rotirea biţilor dintr-o variabilă. În timp ce secvenţei în C îi vor corespunde cam 7÷8 instrucţiuni limbaj de asamblare, celei de-a doua secvenţe, scrisă direct în asamblare, îi vor corespunde doar 2 instrucţiuni (respectiv: mov cl,n / rol ax,cl). În C, pentru o rotire cu n poziţii stânga, trebuie scrise instrucţiunile pentru a realiza următoarele operaţii: deplasare stânga cu n ranguri a variabilei: variabila1 = variabila << n; deplasare dreapta cu “dimensiune_variabila – n” ranguri a variabilei: variabila2 = variabila >> 8*sizeof variabila - n; rezultatul final se obţine printr-un sau logic între cele două deplasări: variabila = variabila1 | variabila2;
Din punct de vedere al vitezei de execuţie sunt evidente trei lucruri: - instrucţiunile mai scurte, ca dimensiune, se execută mai rapid; - instrucţiunile fără referire la memorie se vor executa mai rapid; - instr. cu moduri de adresare complexe se vor executa mai lent; Din acest motiv se recomandă să păstraţi variabilele în registre. nmov ax, 100h mov bx, 100h mov cx, 100h add ax, 100h ; această secvenţă ocupă 12 octeţi în memorie Putem reduce dimensiunea acestei secvenţe: mov ax, 100h mov bx, ax mov cx, ax add ax, ax ; această secvenţă ocupă doar 6 octeţi În cazul instrucţiunilor de salt condiţionat, programatorul poate determina care condiţie este mai des îndeplinită, şi să aranjeze progr. astfel încât condiţia care este îndeplinită mai des să fie pusă pentru continuarea progr., decât să se realizeze saltul condiţionat.
O altă observaţie utilă în scrierea programelor este legată de hazardurile ce pot să apară. Un tip de hazard este cel legat de date, care apare când operandul sursă al unei instrucţiuni a fost şi operand destinaţie al instrucţiunii anterioare: mov dx, 400h mov bx, [200h] ; se încarcă în BX cuv. de la adresa 200h mov ax, [bx] ; se încarcă în AX cuv. de la adresa din BX Este clar că în acest mod de scriere a secvenţei anterioare, instrucţiunea mov ax,[bx] va fi întârziată pe banda de asamblare, cu două cicluri, până când conţinutul lui BX va fi actualizat. Se poate însă reduce efectul hazardului ce există în această secvenţă de cod, prin simpla rearanjare a instrucţiunilor: mov bx, [200h] ; se încarcă în BX cuv. de la adresa 200h mov dx, 400h mov ax, [bx] ; se încarcă în AX cuv. de la adresa din BX Dacă se mai inserează încă o instrucţiune între instrucţiunile mov bx,[200h] şi mov ax,[bx], atunci se poate elimina complet efectul hazardului.
Definirea şi utilizarea de macroinstrucţiuni • O macroinstrucţiune (MI) reprezintă o secvenţă de instrucţiuni căreia i se asociază un nume. Apariţia macroinstrucţiunii în textul programului este înlocuită, automat, de către asamblor, cu secvenţa de instrucţiuni asociată. Ea poate să fie parametrizată, adică poate fi definită în funcţie de o serie de parametrii formali, care sunt actualizaţi la utilizarea macroinstrucţiunii, fiind, deci, înlocuiţi cu parametrii actuali. • Diferenţe între MI şi proc: codul obiect al unei proceduri apare o singură dată în program, în schimb codul obiect generat pentru o MI este repetat în program, ori de câte ori apare numele macroinstrucţiunii. Proc. reduce atât dimensiunea prog. sursă, cât şi pe cea a celui obiect, în timp ce MI nu reduce codul obiect, ci doar dimensiunea programului sursă. MI nu modifică timpul de execuţie al programului, pe când utilizarea procedurilor creşte timpul de execuţie. • Utilizare macroinstrucţiunilor: - simplificarea şi reducerea secvenţelor de cod ce se repetă; - reducerea erorilor cauzate de codul repetitiv; - program în limbaj de asamblare mai uşor de urmărit.
< nume_macro > MACRO [ lista_parametri_formali ] < declaraţii/ corpul macroinstrucţiunii > [;comentarii] ENDM aduna macro t1,t2,suma mov ax, t1 add ax, t2 mov suma, ax endm Utilizarea se poate face astfel: aduna a, b, c mov ax, a add ax, b mov c, ax sau aduna bx,cx,dx mov ax, bx add ax, cx mov dx, ax
Dacă în definirea unei macro, se utilizează etichete, acestea trebuie declarate LOCAL. De exemplu dacă dorim să realizăm un ciclu, o secvenţă de forma: mov cx, durata_ciclu iar: loop iar va genera erori de multidefinire a etichetei la utilizările ulterioare. delay macro durata LOCAL iar push cx ;; se salvează registrul CX mov cx, durata iar: loop iar pop cx endm LOCAL < lista_etichete > • Rolul său este de a declara simbolurile din listă ca locale pentru fiecare apel. Directiva se poate utiliza numai în MI, şi precede instrucţiunile din corpul MI. Pentru aceste etichete asamblorul va genera, la expandare, nume de etichete succesive:??0000, ??0001, etc.
1) Calculul puterii întregi a unui număr întreg. putere macro numar, exponent local iar, gata push cx ; salvare (CX) şi (BX) push bx xor dx, dx ; rezultatul este returnat în (DX, AX) mov ax, 1 ; pregătire rezultat, dacă exponentul e 0 mov cx, exponent jcxz gata ; dacă CX=0, puterea este 1 mov bx, numar ; înmulţitorul în BX iar: mul bx jc gata ; dacă apare eroare la *, se poziţionează CF loop iar gata: pop bx ; refacerea registrelor salvate pop cx endm ; programul ce utilizează această macro, va testa ; valoarea lui CF, dacă este 0 valoare corectă în ; (DX,AX), dacă însă CF=1, a apărut depăşire
2) Înmulţirea unei valori cu 10. ori10 macro x local gata push ax push bx mov ax, x shl ax, 1 ; * 2 jc gata mov bx, ax shl ax, 1 ; * 4 jc gata shl ax, 1 ; * 8 jc gata add ax, bx jc gata ; după utilizare macro ori10 se va mov x, ax ; testa indicatorul CF pentru a testa gata: pop bx ; o eventuală depăşire pop ax endm
Macroinstrucţiunea de repetare REPT <expresie_contor> < corpul macroinstrucţiuni > ENDM 1) Alocarea unor valori consecutive la o anumită adresă: alocare macro tabela, lungime, vi, pas tabela label byte valoare = vi ; valoare iniţială rept lungime valoare = valoare + pas db valoare endm endm Utilizare: alocare tab1, 3, 0, 2 tab1 db 2, 4, 6 alocare tab2, 10, 0, 1 tab2 db 1 , . . , 10
2) Generarea alfabetului, pentru litere mari, la o anumită adresă. generare_alfabet macro nume nume label byte i = 0 rept 26 db 'A' + i i = i + 1 endm endm alocare macro tab, dim tab label byte i = 0 rept dim if (i gt 255) exitm ;; ieşire forţată din macro else ;; înainte de execuţia tuturor db i ;; instrucţiunilor secvenţei endif i = i + 1 endm endm
Macroinstrucţiuni de repetare condiţionată (Indefinite RePeat) IRP <nume>,<<lista>> < corpul macroinstrucţiunii > ENDM <nume>, va fi înlocuit, în corpul MI cu valorile din <lista>. 1) irp val, <1, 2, 3, 4, 5> dw val*val endm dw 1, 4, 9, 16, 25 2) suma label byte irp x, <1, 3, 5, 7, 9> db x+x endm suma db 2, 6, 10, 14, 18 3) irp reg, <ax, cx, dx, bx, sp, bp, si, di> push reg endm
IRPC (Indefinite RePeat Character) - rolul valorilor numerice din IRP este preluat de caractere. 1) irpc c, 12345 dw c*c endm 2) Memorarea, la o adresă a unei valori în zecimal neîmpachetat: scrie_val macro adresa, valoare lea si, adresa irpc v, valoare mov byte ptr [si], v inc si endm endm Pentru o utilizare de forma: scrie_val adr1, 1997 se va genera secvenţa, de cod, care va 1, 9, 9, 7, în format zec. Dacă dorim să depunem o anumită secvenţă de caractere ASCII, se modifică doar linia: mov byte ptr [si], '&v'
Utilizarea operatorilor &, % şi ! Operatorul & este utilizat pentru substituirea simbolurilor, pe care le precede, cu valoarea numerică sau subşirul de caractere asociat simbolului respectiv (sau, altfel spus, concatenează valoarea asociată simbolului), în cazul utilizării simbolurilor respective ca argumente (parametrii) ale utilizării unei macroinstrucţiuni. 1) Declararea unor mesaje, iterative, în cadrul unui program: mesaj macro n msg&n db 'mesaj nr.&n' endm mesaj 5 va genera: msg5 db 'mesaj nr.5' mesaj 11 va genera: msg11 db 'mesaj nr.11’ Dacă MI are 2 parametri sau mai mulţi, atunci ea se defineşte astfel: meserr macro n, o err&n&o db 'eroare &n&&o' endm Utilizarea acestei macro de forma: meserr 2,2 va genera: err22 db 'eroare 22'
Dublarea caracterului &, a amânat evaluarea şirului &&o, pentru momentul evaluării MI IRP. 2) Compararea reg. AL cu caracterele 'a'..'f', şi execuţia pentru fiecare dintre ele unei anumite secvenţe (eticha, etichb, ..., etichf): irpc car, abcdef cmp al, '&car' jz etich&car endm 3) Definirea unei MI pentru rotirea conţinutului unei destinaţii, cu un număr de biţi şi o direcţie, specificate ca parametrii: rotire macro sens, nr_rot, dest push cx ; salvare CX ; NU salv/reface CX mov cl, nr_rot ; sau rept nr_rot ro&sens dest, cl ; ro&sens dest, 1 pop cx ; refacere CX ; endm endm
Operatorul % realizează conversia simbolului care urmează, de la o valoare numerică la un şir de caractere, ce poate fi utilizat pentru a substitui un argument, pentru un apel de MI. Acest operator, de expansiune (%), forţează evaluarea imediată a expresiei ce urmează şi converteşte rezultatul expresiei la un şir de cifre. mesaj5 macro nume,val db '&nume = &val' endm şi declaraţia: const1 equ <LOW> pentru a defini mesajul db 'const1 = LOW' se va utiliza MI anterioară, cu următorii parametrii: mesaj5 const1, %const1 Parantezele unghiulare < > se utilizează pentru a specifica că textul dintre ele este un singur şir. Aceste paranteze se utilizează şi când se doreşte transmiterea unui parametru actual, pentru un apel intern de macro (apelul unei macro în altă macro).
Generarea de mesaje multiple, care respectă o anumită regulă: meserr macro n err&n db 'eroare &n’, 0Dh, 0Ah, ‘$' endm diferr macro x m = 0 rept x m = m + 1 meserr %m endm endm Un apel al acestei macroinstrucţiuni, de forma: diferr 3 va genera mesajele: err1 db 'eroare 1’, 0Dh, 0Ah, ‘$' err2 db 'eroare 2’, 0Dh, 0Ah, ‘$' err3 db 'eroare 3’, 0Dh, 0Ah, ‘$'
Un exemplu de utilizare pentru parantezele unghiulare: mesaj7 macro sir db '&sir',0 ;; definire şir de caractere ASCIIZ endm apelul: mesaj7 <sir caractere> va genera db 'sir caractere',0 • Alt operator important pentru macroinstrucţiuni este operatorul literal, semnul exclamării (!). Acest simbol comandă asamblorului ignore interpretarea caracterului următor. Acest simbol poate fi utilizat atunci când este nevoie ca unul din următoarele caractere să fie inclus într-un şir de caractere, într-o MI: ! & > % Dacă dorim să transmitem ca argument pentru o MI un şir de caractere ce conţine şi caracterul '>', atunci el va fi precedat de caracterul !, pentru a evita interpretarea lui '>' ca sfârşit de şir. mesaj7 <a!>b> care va genera mesajul db 'a>b',0
Directive de asamblare condiţionată • Asamblorul permite utilizatorului să realizeze asamblarea doar a unei anumite părţi a liniilor care compun modulul sursă. Este important de reţinut că aceste directive evaluează expresiile lor la momentul asamblării şi nu la cel al execuţiei programului. • Motivele asamblării condiţionate: - un program general trebuie 'adaptat' pentru o anumită aplicaţie, funcţie de parametrii actuali incluzându-se anumite module, sau dimensionându-se zone de memorie, corespunzător aplicaţiei; altfel, prin includerea tuturor modulelor sau prin dimensionarea la maxim a zonelor de memorie, indiferent de aplicaţie, se ajunge la dimensionări neeconomice; - includerea doar a unora dintre instrucţiunile prezente, în textul sursă, datorită unor diferenţe între procesoarele aceleiaşi familii (286, 386, 486, etc.). • Directivele de asamblare condiţionată sunt importante deoarece permit generarea de diferite coduri obiect pentru diferite medii de operare şi diferite situaţii. Pe durata asamblării, programatorul poate alege condiţionat dacă asamblorul să asambleze, de exemplu, versiunea pentru 386 sau pentru Pentium.
Sintaxa pentru directiva IF este următoarea: IF condiţie ; condiţia este o expresie ce poate secvenţa 1 ; fi evaluată, în momentul asamblării [ELSE ; la o constantă 'TRUE' sau 'FALSE' secvenţa 2]; clauza ‘else’ este opţională ENDIF În mod asemănător sunt definite directivele: IFEexp ; dacă expresia este zero se execută secv1 ; altfel se execută secv2 IFBarg ; dacă argumentul este blanc (' ') se ; executa secv1, altfel se execută secv2 IFNB <arg ; adică argumentul <> blanc se execută secv1, ; altfel, argument =' ', execută secvenţa 2. IFDIF <arg1>, <arg2> ; se compară cele două argumente, ; (senzitiv la tipul literelor: mari şi mici), şi ; dacă sunt diferite execută secv1, altfel secv2 IFDIFI <arg1>, <arg2>; este asemănătoare cu dir. anterioară, ; cu deosebirea că ignoră tipul literelor.
IFIDN <arg1>, <arg2> ; se compară cele două argumente, ; (senzitiv la tipul literelor: mari şi mici), şi ; dacă sunt identice exec. secv1, altfel secv2 IFIDNI <arg1>, <arg2> ; este asemănătoare cu dir. anterioară, ; cu deosebirea că ignoră tipul literelor. IFDEF <argument> ; dacă simbolul prezent ca arg. este ; definit execută secv.1, altfel secv.2 IFNDEF <argument> ; dacă simbolul prezent ca arg. nu ; este definit execută secv.1. tip_car macro car ; utilizare: ifb <car> tip_car 'x' ;generează mov dl, ' ' mov dl, 'x' else mov ah, 2 mov dl, car int 21h endif tip_car ; va genera mov ah, 2 mov dl, ' ' int 21h mov ah, 2 endm int 21h
MI recursivă care depune registre în stivă; depunerea va înceta când în lista registrelor apare blancul. push_reg macro r1, r2, r3 ; utilizare: ifnb <r1> push_reg ax, bx, cx push r1 push ax push_reg r2, r3 push bx endif push cx endm MI ce generează diferite instrucţiuni în funcţie de un param. movt macro tip ifidn <tip>, <B> ; utilizare: movt D rep movsd ; sau: movt W exitm ; sau: movt endif ifidn <tip>, <W> rep movsw else rep movsb ; implicit, dacă nu are paramteru endif endm
Directive pentru generarea condiţionată a erorilor În conjuncţie cu directivele de asamblare condiţionată, există un set de directive pentru generarea de mesaje de eroare, în aceleaşi condiţii ca primele. Asamblorul generează mesajul de eroare la întâlnirea unei astfel de directive, dacă este îndeplinită condiţia respectivă. Ele sunt utilizate, cu predilecţie, în cadrul MI. .ERR - generează mesaj de eroare, de exemplu: if var1 lt var2 .err ; va genera mesaj dacă: var1 < var2 endif .ERRE expresie .ERRNZ expresie .ERRB <argument> .ERRNB <argument .ERRDIF <arg1>,<arg2> .ERRDIFI <arg1>,<arg2>