260 likes | 715 Views
PROGRAMAREA LOW LEVEL ÎN LIMBAJUL PASCAL. I nserare de cod maşină în sursa unui program Borland Pascal I nserare de instrucţiuni scrise în limbaj de asamblare într-un program Pascal ( asamblor ul inline a l mediului Borland Pascal 6.0). INSERAREA DE COD MAŞINĂ ÎN TEXTUL SURSĂ PASCAL.
E N D
PROGRAMAREA LOW LEVELÎN LIMBAJUL PASCAL Inserare de cod maşină în sursa unui program Borland Pascal Inserare de instrucţiuni scrise în limbaj de asamblare într-un program Pascal (asamblorul inlineal mediului Borland Pascal 6.0).
INSERAREA DE COD MAŞINĂ ÎN TEXTUL SURSĂ PASCAL • Instrucţiunea inline inline ( element_inline{ / element_inline }) Exemplu: inline (<$1234/>$44) generează trei octeţi de cod: $34, $44, $00.
INSERAREA DE COD MAŞINĂ ÎN TEXTUL SURSĂ PASCAL Următorul exemplu de instrucţiune inline generează cod maşină pentru a copia un anumit număr de cuvinte la o adresă specificată. Procedura descrisă UmplereCuvinte va memora Contor cuvinte cu valoarea Data în memorie, începând cu primul octet de la adresa conţinută în variabila Dest. Procedure UmplereCuvinte (var Dest; Contor, Data:Word); begin inline( $C4/$BE/Dest/ { LES DI, Dest[BP] } $8B/$8E/Contor/ { MOV CX, Contor[BP] } $8B/$86/Data/ { MOV AX, Data[BP] } $FC/ { CLD } $F3/$AB); { REP STOSW } end;
INSERAREA DE COD MAŞINĂ ÎN TEXTUL SURSĂ PASCAL • Directiva inline • aceeaşi sintaxă ca şi instrucţiunile inline • permite scrierea de proceduri şi funcţii care în momentul invocării sunt expandate într-o secvenţă dată de instrucţiuni în cod maşină(~macrourile în limbaj de asamblare) • când se invocă o procedură sau funcţie inline, compilatorul generează codul dictat de directiva inline în loc de a genera cod de apel. • Eventualii parametri sunt puşi în stivă • deoarece astfel de proceduri şi funcţii sunt, de fapt, macrouri, nu se generează în mod automat cod de intrare şi cod de ieşire. Function LongMul(x,y:Integer):LongInt; inline( $5A/ { POP DX ; DX:=y } $58/ { POP AX ; AX:=x } $F7/$EA); { IMUL DX ; DX:AX := x*y } Corectie fata de exemplul de la pagina 311 din cartea de curs!!!
ASAMBLORUL INLINE AL LUI BORLAND PASCAL 6.0 • Asamblorul inline al lui Borland Pascal 6.0 permite inserarea de cod asamblare direct în sursa programelor Pascal • Instrucţiunea asm asmInstrucţiune_Asm { SeparatorInstrucţiune_Asm } end Exemplu: asm mov ax, A; xchg ax, B; mov A, ax end; O instrucţiune asm trebuie să asigure integritatea regiştrilor BP, SP, SS şi DS
ASAMBLORUL INLINE AL LUI BORLAND PASCAL 6.0 • Instrucţiunile asamblorului [ Etichetă: ] { Prefix } [ Mnemonică [ Operand { ,Operand } ] label Start, Stop; ... begin asm Start: ... jz Stop @1: ... loop @1 end; asm @1: ... jc @2 ... jmp @1 @2: end; goto Start; Stop: end; • etichete Pascal(definite în secţiunea de declaraţii label a programului Pascal) • etichete locale(vizibile doar în cadrul instrucţiunii asm care le defineşte; ca şi sintaxă, ele încep cu simbolul "@”)
ASAMBLORUL INLINE AL LUI BORLAND PASCAL 6.0 • Instrucţiunile asamblorului [ Etichetă: ] { Prefix } [ Mnemonică [ Operand { ,Operand } ] asm rep movsb { copiază CX octeţi de la adresa DS:SI la adresa ES:DI } SEGES lodsw { încarcă în AX un cuvânt de la ES:SI şi nu de la DS:SI } SEGCS mov ax,[bx] { echivalentă cu mov ax, cs:[bx] } SEGES { se referă la instrucţiunea în limbaj de asamblare care urmează } mov WORD PTR [DI],0 { devine mov WORD PTR ES:[DI], 0 } end; • REP,REPE/REPZ,REPNE/REPNZ • SEGCS, SEGDS, SEGES, SEGSS
ASAMBLORUL INLINE AL LUI BORLAND PASCAL 6.0 • Instrucţiunile asamblorului [ Etichetă: ] { Prefix } [ Mnemonică [ Operand { ,Operand } ] • codurile de operaţii ale instrucţiunilor8086/8087 şi 80826/80287 • directivele de asamblare: DB, DW şi DD (aceste date vor fi generate în segmentul de cod) VarByte DB ? VarWord DW ? ... mov al, VarByte mov bx, VarWord ... var VarByte: Byte; VarWord: Word; ... asm ... mov al, VarByte mov bx, VarWord ... end; ... Asamblorul inline al lui Borland Pascal 6.0 nu suportă astfel de declaraţii de variabile. Construcţia precedentă poate fi descrisă astfel:
ASAMBLORUL INLINE AL LUI BORLAND PASCAL 6.0 • Instrucţiunile asamblorului [ Etichetă: ] { Prefix } [ Mnemonică [ Operand { ,Operand } ] • expresii - combinaţii de constante, regiştri, simboluri şi operatori, cuvinte rezervate: AH, CL, FAR, SEG, AL, CS, HIGH, SHL, AND, CX, LOW, SHR, AX, DH, MOD, SI, BH, DI, NEAR, SP, BL, DL, NOT, SS, BP, DS, OFFSET, ST, BX, DWORD, OR, TBYTE, BYTE, DX, PTR, TYPE, CH, ES, QWORD, WORD şi XOR. Var ch:Char; ... asm mov ch,1; { se referă la registrul CH } mov &ch,1; { se referă la variabila ch } end;
ASAMBLORUL INLINE AL LUI BORLAND PASCAL 6.0 • Expresii • evaluează toate expresiile ca valori întregi pe 32 de biţi • nu suportă valori reale şi nici şir de caractere (exceptând constantele şir de caractere) • Constantele hexazecimale pot să fie scrise şi în sintaxa Pascal (precedate de simbolul "$") • Referirea la o variabilă înseamnă deplasamentul acestei variabile în segmentul ei de bază (şi nu conţinutul ei, cum este în Pascal). Var x: Integer; ... asm mov ax, x+4; { memorează în registrul AX valoarea unui cuvânt memorat la 4 octeti de x si nu valoarea lui x plus 4! } mov bx,x; { memorează în registrul BX valoarea lui x } end;
ASAMBLORUL INLINE AL LUI BORLAND PASCAL 6.0 • Expresii • Identificatorii recunoscuţi de către asamblorul inline sunt: etichete Pascal, constante Pascal, nume de tipuri Pascal, variabile Pascal, proceduri şi funcţii Pascal şi simbolurile speciale: @Code, @Data şi @Result. • În expresiile destinate asamblorului inline NU pot să apară: • proceduri şi funcţii standard; • numele de tablouri Mem, MemW, MemL, Port, PortW; • constante şir de caractere mai lungi decât 4 octeţi; • constante reale şi mulţime; • proceduri şi funcţii inline; • etichete care nu au fost declarate în blocul curent; • simbolul @Result, în afara unei funcţii asm mov ax, SEG @Data mov ds, ax {memorează în registrul DS adresa de segment a segmentului curent de date} end; Procedure X; var c: Integer; ... asm mov ax,c { se generează codul mov ax, [BP-2] } end; ...
ASAMBLORUL INLINE AL LUI BORLAND PASCAL 6.0 Function Suma(x,y:Integer):Integer; begin asm mov ax, x add ax, y mov @Result, ax {pune valoarea din AX în locul de unde apelantul va lua rezultatul întors de funcţie} end; end; Function Suma(var x,y:Integer):Integer; begin asm les bx, x { consideră că x este o adresă far, pe care o încarcă în ES (segmentul) şi în BX (offset-ul)} mov ax, es:[bx] { memorează în AX valoarea găsită la adresa ES:[BX], adica valoarea parametrului x } les bx, y { consideră că y este o adresă far, pe care o încarcă în ES (segmentul) şi în BX (offset-ul)} add ax, es:[bx] { adună la AX valoarea găsită la adresa ES:[BX], adică valoarea parametrului y } mov @Result, ax { pune valoarea din AX în locul de unde apelantul va lua rezultatul întors de funcţie } end; end;
ASAMBLORUL INLINE AL LUI BORLAND PASCAL 6.0 Tipul unei expresii asm mov al,[100h] { pune în registrul AL un octet de la adresa ds:[100H]; tipul asociat - se deduce din dimensiunea registrului AL - este 1} mov bx,[100h] { se pune în BX un cuvînt de la adresa ds:[100H]; tipul asociat - se deduce din dimensiunea lui BX - este 2 } end; asm inc WORD PTR [100h] imul BYTE PTR [100h] end; Dacă totuşi tipul nu se poate deduce, asamblorul cere o conversie de tip explicită. Tipul unei referinţe la memorie poate fi modificat cu ajutorul operatorului de conversie PTR. Uneori, o referinţă la memorie nu are un tip asociat, acesta deducându-se din tipul celorlalţi operanzi
ASAMBLORUL INLINE AL LUI BORLAND PASCAL 6.0 • Proceduri şi funcţii assembler • Procedurile (funcţiile) assembler sunt proceduri (funcţii) scrise complet în asamblare inline, fără a fi necesară partea begin... end. • Ele se definesc cu ajutorul directivei assembler Function LongMul(x,y:Integer):LongInt; assembler; asm mov ax,x imul y end; • Utilizarea directivei assembler are ca efect realizarea de către compilator a câtorva optimizări la generarea codului de intrare în subrutină: • NU generează cod pentru copierea in variabile locale a parametrilor valoare de dimensiune > 4 octeti, acesti parametri trebuie tratati ca si cum ar fi transmisi prin referinta • NU alocă o variabilă pentru întoarcerea rezultatului unei funcţii, exceptie facand functiile care intorc string • NU generează cadru de stivă pentru procedurile şi funcţiile care nu au parametri şi nici variabile locale; • Funcţiile întorc rezultatul după cum urmează: • Integer, Char, Boolean, enumerare: • 1 octet - în AL • 2 octeţi - în AX • 4 octeţi - în DX:AX • Real - în DX:BX:AX • Single, Double, Extended, Comp - în ST(0) • Pointer - în DX:AX • String - în locaţia temporară punctată de @Result
Proceduri şi funcţii assemblerExemplu: Funcţia ce operează asupra stringurilor este realizată cu ajutorul instrucţiunilor asamblorului inline, o variantă descrisă fără directiva assembler şi o variantă descrisă cu directiva assembler. Funcţia întoarce ca valoare un şir de caractere care reprezintă scrierea cu majuscule a şirului de caractere care este parametrul funcţiei. Parametrul funcţiei este transmis prin valoare. Varianta 1 Function UpperCase( Str:String): String; begin asm cld lea si, Str les di, @Result SEGSS lodsb stosb xor ah, ah xchg ax, cx jcxz @3 @1: SEGSS lodsb cmp al, 'a' jb @2 cmp al, 'z' ja @2 add al, 'A'-'a' @2: stosb loop @1 @3: end; end; Varianta2 Function UpperCase( Str:String): String; assembler; asm push ds cld lds si, Str les di, @Result lodsb stosb xor ah, ah xchg ax, cx jcxz @3 @1: lodsb cmp al, 'a' jb @2 cmp al, 'z' ja @2 add al, 'Ă'-'a' @2: stosb loop @1 @3: pop ds end;
ACCESAREA REGIŞTRILOR ŞI APELAREA DE ÎNTRERUPERI IN Borland Pascal 6.0 type registers = record case Integer of 0: (AX, BX, CX, DX, BP, SI, DI, DS, ES, Flags : Word); 1: (AL, AH, BL, BH, CL, CH, DL, DH : Byte); end; definit în unitul dos Program Pascal care afişează pe ecran un text, folosind pentru aceasta funcţia DOS 9h: uses dos; const mesaj: String= 'Hello, everybody ! $'; var reg: Registers; begin reg.AH:= 9; { încarc în AH valoarea 9 } reg.DS:= Seg(mesaj); { încarc în DS:DX adresa far a şirului care va fi tipărit } reg.DX:= Ofs(mesaj[1]); Intr($21,reg); { apelarea întreruperii 21h } end; procedura oferita de unitul dos
SCRIEREA DE RUTINE DE TRATARE A ÎNTRERUPERILOR ÎN LIMBAJUL PASCAL • salvarea lui CS şi a lui IP în stivă; • salvarea în stivă a registrului de flag-uri; • interzicerea apariţiei altor întreruperi; • salt far la locaţia punctată de vectorul de întrerupere corespunzător. Proceduri interrupt în Pascal procedure MyInt(rFlags, rCS, rIP, rAX, rBX, rCX, rDX, rSI, rDS, rES, rBP:Word); interrupt; begin ... end; • nu poate să fie apelată dintr-o altă procedură • trebuie să fie declarată far • parametrii corespund regiştrilor procesorului • Indiferent de lista parametrilor unei proceduri interrupt, compilatorul produce (automat) cod la intrarea în rutina pentru salvarea tuturor regiştrilor pe stivă • corespunzător, la ieşirea din rutină se restaurează automat aceşti regiştri şi se generează (tot automat) o instrucţiune iret
SCRIEREA DE RUTINE DE TRATARE A ÎNTRERUPERILOR ÎN LIMBAJUL PASCAL Proceduri interrupt în Pascal push ax push bx push cx push dx push si push di push ds push es push bp mov bp, sp mov ax, seg @Data mov ds, ax pop bp pop es pop ds pop di pop si pop dx pop cx pop bx pop ax iret Cod de intrare Cod de iesire
SCRIEREA DE RUTINE DE TRATARE A ÎNTRERUPERILOR ÎN LIMBAJUL PASCAL Proceduri interrupt în Pascal • pentru a seta un anumit vector de întrerupere la o adresă specificată (instalarea unui nou handler – vezi functia DOS 25h) • procedura definită în cadrul unit-ului DOS. SetIntVec (NrInt, Vector) valoare de tip byte putând lua valori între 0 şi 255 si reprezentând numărul întreruperii adresa la care se va seta vectorul de întrerupere corespunzător lui NrInt • care întoarce adresa memorată într-un anumit vector de întrerupere (obtinerea adresei vechiului handler – vezi functia DOS 35h) • procedura definită în cadrul unit-ului DOS GetIntVec (NrInt, Vector) • Terminate and Stay Resident (vezi funcţia DOS 31h). Keep (cod_revenire)
SCRIEREA DE RUTINE DE TRATARE A ÎNTRERUPERILOR ÎN LIMBAJUL PASCAL Proceduri interrupt în Pascal Exemplu: program care modifică rutina de tratare a înteruperii 9, afişând la fiecare apăsare a tastei 'A' mesajul 'Aţi apăsat tasta A'. {$M $800,0,0 } { 2K stack, no heap } uses Crt, Dos; var c:char; OldHand : Procedure; {$F+} procedure MyHand; interrupt; var i:Byte; begin i := Port[$60]; { se citeşte un octet din portul $60 al controlerului tastaturii} inline ($9C); { PUSHF - salvăm flagurile pe stivă } OldHand; if (i=65) then Writeln('Ati apasat tasta A') end; {$F‑} begin GetIntVec($9,@OldHand); SetIntVec($9,Addr(MyHand)); Keep(0); { Terminate, stay resident } end.