Download - 2015 Cap 8 Programarea Multimodul
Cerinţele unui modul asamblare la legarea cu un alt modul Directiva PUBLIC
- exporta simboluri definite în modulul asamblare în alte module
PUBLIC [limbaj] simbol {,[limbaj] simbol}
PASCAL, C, BASIC, ASSEMBLER, FORTRAN, PROLOG sau NOLANGUAGE
• nume de proceduri• nume de variabile de memorie• etichete definite cu ajutorul directivelor EQU sau =, ale căror valori se reprezintă pe 1 sau 2 octeţi.
Ex: PUBLIC C ProcA
- impune ca simbolul ProcA să fie exportat în celelalte module ca _ProcA, conform regulilor limbajului C.
Cerinţele unui modul asamblare la legarea cu un alt modul Directiva EXTRN
- face vizibile în modulul curent simboluri definite în alte module
EXTRN definiţie {,definiţie}
[limbaj] nume : tip
ABS, BYTE, DATAPTR, DWORD, NEAR, FAR, FWORD, PROC, QWORD, TBYTE, UNKNOWN, WORD
numele simbolului care este definit în alt modul
Ex: EXTRN ProcA: near
Legarea mai multor module asamblare
- fiecare modul are în final o directivă END
- numai directiva END a modulului ce conţine instrucţiunea de la care programul trebuie să-şi înceapă execuţia va conţine specificarea adresei de start.
End start End End
Modul 1 Modul 2 Modul 3
Exemplu
Sir1 db …Sir2 db …SirFinal db … public SirFinal
extrn Concatenare:near
SirFinal = Concatenare(Sir1, Sir2)
extrn SirFinal: byte
Concatenare proc(Sir1, Sir2): byte;
public Concatenare
Declaratii variabile
Declaratii variabile
Declaratii subrutine
Declaratii subrutine
Apeluri subrutine
Modulul main.asm Modulul sub.asm
Programul principal main.asm:
.MODEL SMALL
.STACK 200
.DATASir1 DB 'Buna ', 0Sir2 DB 'dimineata!', '$', 0SirFinal DB 50 DUP (?)PUBLIC SirFinal; se poate înlocui cu GLOBAL SirFinal:BYTE
.CODEEXTRN Concatenare:PROC
Start:mov ax, @datamov ds, ax ; încărcarea registrului dsmov ax, OFFSET Sir1mov bx, OFFSET Sir2call Concatenare;SirFinal:=Sir1+Sir2mov ah, 9mov dx, OFFSET SirFinalint 21h ;tipărirea şirului obţinutmov ah, 4chint 21h
; terminarea programuluiEND Start
Modulul secundar sub.asm:
.MODEL SMALL
.DATAEXTRN SirFinal:BYTE ; se poate înlocui cu GLOBAL SirFinal:BYTE.CODEPUBLIC ConcatenareConcatenare PROC cld mov di, SEG SirFinal mov es, di mov di, OFFSET SirFinal ;es:di <- adresa şirului final mov si, ax ; ds:si <- adresa primului şir Sir1Loop: lodsb ; al <- caracterul curent and al, al ; verifică dacă e zeroul final jz cont stosb ; dacă nu, îl pune în destinaţie jmp Sir1Loop ; reia operaţiile cont: mov si, bx ; ds:si <- adresa celuilalt şir Sir2Loop: lodsb stosb ; încarcă şi zeroul final and al, al jnz Sir2Loop ret ; revenirea din procedurăConcatenare ENDPEND
Programul principal main.asm:
DATA SEGMENTSir1 DB 'Buna ', 0Sir2 DB 'dimineata!', '$', 0SirFinal DB 50 DUP (?)PUBLIC SirFinal
DATA ENDS
CODE SEGMENT EXTRN Concatenare:PROC
(sau EXTRN Concatenare:FAR)Start:
mov ax, datamov ds, axmov ax, OFFSET Sir1mov bx, OFFSET Sir2call FAR PTR Concatenare
(si atunci ramane call Concatenare) ;SirFinal:=Sir1+Sir2
mov ah, 9mov dx, OFFSET SirFinalint 21h ;tipărirea şirului obţinutmov ah, 4chint 21h
END Start
Modulul secundar sub.asm:
ASSUME CS:CODE
EXTRN SirFinal:BYTE PUBLIC Concatenare CODE SEGMENT Concatenare PROC cld mov di, SEG SirFinal mov es, di mov di, OFFSET SirFinal ;es:di <- adresa şirului final mov si, ax ; ds:si <- adresa primului şir Sir1Loop: lodsb ; al <- caracterul curent and al, al ; verifică dacă e zeroul final jz cont stosb ; dacă nu, îl pune în destinaţie jmp Sir1Loop ; reia operaţiile cont: mov si, bx ; ds:si <- adresa celuilalt şir Sir2Loop: lodsb stosb ; încarcă şi zeroul final and al, al jnz Sir2Loop ret ; revenirea din procedură Concatenare ENDPEND
Cele două module vor fi asamblate separat:
TASM MAIN[.ASM]
TASM SUB[.ASM]
Editarea legăturilor se va face:
TLINK MAIN[.OBJ]+SUB[.OBJ]
sau
TLINK MAIN[.OBJ] SUB[.OBJ]
Va rezulta un program executabil main.exe care, lansat în execuţie, va tipări mesajul "Buna dimineata!".
Legarea de module asamblare cu module scrise în limbaje de nivel înalt Cerinţe ale editorului de legături. Intrarea în procedură. Nealterarea valorilor unor regiştri. Transmiterea şi accesarea parametrilor. Alocarea de spaţiu pentru datele locale (opţional). Întoarcerea unui rezultat (opţional). Revenirea din procedură.
Cerinţe ale editorului de legături. Intrarea în procedură. Nealterarea valorilor unor regiştri. Transmiterea şi accesarea parametrilor. Alocarea de spaţiu pentru datele locale (opţional). Întoarcerea unui rezultat (opţional). Revenirea din procedură.
- numele segmentelor sunt impuse de limbajele de nivel înalt cu care se face legătura;
- orice simbol care este definit în modulul scris în limbaj de asamblare şi se doreşte a fi folosit în modulul scris în limbaj de nivel înalt trebuie făcut vizibil în acesta din urmă, utilizând directiva PUBLIC;
- orice simbol care este definit în modulul scris în limbaj de nivel înalt şi care va fi utilizat în modulul scris în limbaj de asamblare trebuie declarat ca extern în acesta din urmă, utilizând directiva EXTRN;
Cerinţe ale editorului de legături. Intrarea în procedură. Nealterarea valorilor unor regiştri. Transmiterea şi accesarea parametrilor. Alocarea de spaţiu pentru datele locale (opţional). Întoarcerea unui rezultat (opţional). Revenirea din procedură.
Directiva de compilare $L (poate să apară oriunde în textul sursă Pascal. )
{$L nume[.obj]}
Fişierul nume.obj să îndeplinească condiţiile:
- toate procedurile şi funcţiile trebuie să se afle într-un segment numit CODE sau CSEG, sau într-un segment al cărui nume se termină cu _TEXT;- toate datele iniţializate trebuie să fie plasate într-un segment numit CONST sau într-un segment al cărui nume se termină cu _DATA;- toate datele neiniţializate trebuie să fie plasate într-un segment numit DATA sau DSEG, sau într-un segment al cărui nume se termină cu _BSS;
Turbo
Assembler *
Turbo
Pascal
Declaraţiilor de tip standard din Pascal le corespund, în limbaj de asamblare, următoarele tipuri:
Integer – WORDReal – FWORDSingle – DWORDPointer – DWORD
Cerinţe ale editorului de legături. Intrarea în procedură. Nealterarea valorilor unor regiştri. Transmiterea şi accesarea parametrilor. Alocarea de spaţiu pentru datele locale (opţional). Întoarcerea unui rezultat (opţional). Revenirea din procedură.
Turbo
Assembler *
Turbo
Pascal
Turbo Pascal- Un subprogram utilizat in programul Pascal dar definit într-un alt modul trebuie să fie declarat cu ajutorul directivei EXTERNAL (numai la nivelul cel mai exterior al programului sau unităţii):
Procedure AsmProc (a:Integer; b:Real); external;
Function AsmFunc (c:Word; d:Byte): Integer; external;
Turbo AssemblerSingurele obiecte care pot fi exportate dintr-un modul scris în limbaj de asamblare într-un program sau unitate Pascal sunt etichetele de instrucţiuni sau nume de proceduri declarate PUBLIC.
CODE SEGMENTAsmProc PROC NEAR
PUBLIC AsmProc...
AsmProc ENDPAsmFunc PROC NEAR
PUBLIC AsmFunc...
AsmFunc ENDPCODE ENDSEND
Cerinţe ale editorului de legături. Intrarea în procedură. Nealterarea valorilor unor regiştri. Transmiterea şi accesarea parametrilor. Alocarea de spaţiu pentru datele locale (opţional). Întoarcerea unui rezultat (opţional). Revenirea din procedură.
Turbo
Assembler *
Turbo
Pascal
Turbo Assembler- Un modul TASM poate accesa orice procedură, funcţie, variabilă sau constantă cu tip declarată la nivelul cel mai exterior al unui program sau al unei unităţi Pascal, inclusiv rutinele din biblioteci. Acest lucru se face cu ajutorul declaraţiei EXTRN
DATA SEGMENTASSUME DS:DATAEXTRN A: BYTEEXTRN B: WORDEXTRN C: BYTE...
DATA ENDSCODE SEGMENT
EXTRN ProcA:NEAREXTRN FuncA:FAR...
; aici pot fi utilizate variabilele a, b, c şi pot fi apelate subprogramele ProcA, FuncACODE ENDS
Turbo Pascal...{variabile globale} Var a: Byte; b: Word; c: ShortInt;...Procedure ProcA;...{$F+}Function FuncA:Integer;...
Cerinţe ale editorului de legături. Intrarea în procedură. Nealterarea valorilor unor regiştri. Transmiterea şi accesarea parametrilor. Alocarea de spaţiu pentru datele locale (opţional). Întoarcerea unui rezultat (opţional). Revenirea din procedură.
- În momentul în care se face un apel de procedură sau funcţie, apelatorul pune mai întâi în stivă adresa de revenire, pe urmă dă controlul subprogramului apelat folosind pentru aceasta o instrucţiune CALL.
- Această adresă de revenire poate să fie o adresă FAR sau o adresă NEAR, în funcţie de modelul de memorie în care este compilat sau asamblat modulul.
- Este foarte important ca instrucţiunea de revenire din subprogram să execute o revenire care să corespundă apelului.
- Dacă se doreşte apelarea dintr-un modul scris în limbaj de nivel înalt (respectiv limbaj de asamblare) a unui subprogram scris în limbaj de asamblare (respectiv limbaj de nivel înalt), editorul de legături care leagă cele două module nu verifică dacă tipul apelului (far sau near) corespunde cu tipul revenirii. Această potrivire cade în sarcina programatorului.
Cerinţe ale editorului de legături. Intrarea în procedură. Nealterarea valorilor unor regiştri. Transmiterea şi accesarea parametrilor. Alocarea de spaţiu pentru datele locale (opţional). Întoarcerea unui rezultat (opţional). Revenirea din procedură.
- Limbajele de nivel înalt impun ca anumiţi regiştri să-şi păstreze la ieşire valoarea cu care intră într-o procedură.
- În acest scop, dacă subprogramul, definit în limbaj de asamblare, modifică unii dintre aceştia, atunci valorile lor de intrare trebuie salvate (eventual în stivă). Ele vor fi restaurate înainte de revenirea din procedură.
- Când este făcut un apel la o funcţie sau procedură trebuie păstrată nealterată valoarea a patru regiştri: SS, DS, BP, SP
- În momentul apelului:SS punctează spre segmentul de stivăDS punctează spre segmentul de date global (numit DATA)BP punctează spre baza stiveiSP punctează vârful stivei.
Turbo Pascal – Turbo Assembler
Cerinţe ale editorului de legături. Intrarea în procedură. Nealterarea valorilor unor regiştri. Transmiterea şi accesarea parametrilor. Alocarea de spaţiu pentru datele locale (opţional). Întoarcerea unui rezultat (opţional). Revenirea din procedură.
- prin referinţă NEAR: în stivă se pune, pe un cuvânt, offset-ul adresei;- prin referinţă FAR: în stivă se pun două cuvinte; mai întâi se pune segmentul, pe urmă se pune offset-ul;- prin valoare: în stivă se pune valoarea parametrului.
Procedure ProcA(i:integer; var j:integer); external;- presupunem ca apelul este de tip NEAR Stiva dupa executia
codului de apel pt ProcAProcA PROC NEAR PUBLIC ProcA j EQU DWORD PTR [BP+4] i EQU WORD PTR [BP+8] PUSH BP ; cod de intrare in ProcA MOV BP, SP ... MOV AX, i ; încarcă în AX valoarea parametrului i LES DI, j MOV ES:[DI], AX ; j:=i …
Turbo Pascal – Turbo Assembler
BP iniţial
offset. adr. revenire
offset j
adr. seg. j
valoarea lui i
…
BP+2
BP+4
BP+6
BP=SP
BP+8
! Turbo Pascal – parametri transmisi prin referinta sunt de tip far
Turbo
Assembler *
Turbo
Pascal
TIP CE SE PUNE ÎN STIVĂ
Char - octet fără semn
Boolean - octet (valoare 0 sau 1)
tip enumerare - octet fără semn, dacă enumerarea are cel mult 256 de valori- cuvânt fără semn, în caz contrar
Real - 6 octeţi în stivă (excepţie !)
tip reprezentat în virgulă flotantă
- 4, 6, 8, 10 octeţi în stiva coprocesorului numeric
Pointer - 2 cuvinte în stivă
String - pointer (far) la valoare
tip mulţime - adresa unei mulţimi care ocupă 32 de octeţi
Array, Record - valoarea în stivă, dacă lungimea este de 1, 2 sau 4 octeţi- pointer la valoare, în caz contrar
Cerinţe ale editorului de legături. Intrarea în procedură. Nealterarea valorilor unor regiştri. Transmiterea şi accesarea parametrilor. Alocarea de spaţiu pentru datele locale (opţional). Întoarcerea unui rezultat (opţional). Revenirea din procedură.
Parametri transmisi prin valoare
Cerinţe ale editorului de legături. Intrarea în procedură. Nealterarea valorilor unor regiştri. Transmiterea şi accesarea parametrilor. Alocarea de spaţiu pentru datele locale (opţional). Întoarcerea unui rezultat (opţional). Revenirea din procedură.
- Dacă valoarea lor nu trebuie să se păstreze între două apeluri consecutive ale procedurii atunci acestea vor fi alocate în segmentul de stivă şi le vom numi date volatile.
- În caz contrar spunem că este vorba despre date statice şi spaţiul pentru ele va fi alocat într-un segment diferit de segmentul de stivă, de exemplu în segmentul de date. Alocarea de spaţiu pentru datele statice se face folosind directivele cunoscute DB, DW, DD ş.a.
- Alocarea unui număr de n octeţi (n fiind număr par) pentru datele locale volatile se poate face cu următoarea instrucţiune:
sub sp, n
“Definire” si alocare pt 2 variabile locale in cadrul unei proceduri externe TP (scrisa in limbaj de asamblare si utilizata in Turbo Pascal)
push bpmov bp, spsub sp, 4minim EQU [bp-2]maxim EQU [bp-4]...mov ax, 1mov minim, axmov maxim, ax…
Întoarcerea unui rezultat
- prin intermediul registrilor, daca valoarea intoarsa este reprezentata pe mai putin de 4 octeti- exceptie: valorile de tip real, având lungimea de 6 octeţi, sunt returnate tot prin
intermediul regiştrilor (în DX:BX:AX).
- dacă valoarea întoarsă este mai lungă există alte metode de transmitere a rezultatului către apelator
- rezultat scalar : • 1 octet în AL• 2 octeţi în AX• 4 octeţi În DX:AX (DX conţine partea high)
- rezultat real : în DX:BX:AX
- rezultat reprezentat în virgulă flotantă: în regiştrii coprocesorului numeric;
- rezultat string : într-o zonă temporară alocată de Turbo Pascal în momentul compilării programului care conţine un apel de astfel de funcţie; un pointer la această zonă este pus în stivă înainte de a începe să pună parametrii. Acest pointer nu face parte din lista de parametri, deci nu afectează numărul de octeţi ce trebuie scoşi din stivă la revenirea din procedură (vezi codul de ieşire);
- rezultat pointer: în DX se pune adresa de segment, iar în AX se pune deplasamentul.
Turbo Pascal – Turbo Assembler
Cerinţe ale editorului de legături. Intrarea în procedură. Nealterarea valorilor unor regiştri. Transmiterea şi accesarea parametrilor. Alocarea de spaţiu pentru datele locale (opţional). Întoarcerea unui rezultat (opţional). Revenirea din procedură.
- refacerea valorilor regiştrilor
- refacerea stivei astfel încât în vârf să conţină adresa de revenire.
MOV SP, BPPOP BP
- dacă limbajul de nivel înalt pretinde apelatorului eliberarea spaţiului ocupat în stivă deparametri, aceasta se face cu instrucţiunea
ret nunde n este numărul de octeţi care sunt ocupaţi de către parametri
ExempluModulul M1 (Turbo Pascal) Modulul M2 (asamblare)
var glob:string; s:string;
function Asmf (s:string):string; far; external;
function CitSir:string;far;
s:=CitSir;s := Asmf(s);
Asmf proc (s:string):string; far; public;extrn CitSir: far
CitSir;
Declaraţii variabile Declaraţii variabile
Definiţii şi declaraţii subrutine
Definiţii şi declaraţii subrutine
Apeluri subrutine Apeluri subrutine
P.pas
program TPandASM;var glob: string; s: string;{$L asmf.obj}
function Asmf (s: string): string; far; external;
function CitSir: string; far;var Strn: string; begin
write ('Sirul: ');readln (Strn);CitSir := Strn;
end;
begins := CitSir;glob := 'abc123';s := Asmf(s);writeln(s);readln;
end.
• directiva de compilare $L
• declararea funcţiei Asmf ca fiind externă; această funcţie este definită în modulul scris în limbaj de asamblare dar va fi folosită în acest modul;
• prezenţa directivei far indică modul de apel al acestui subprogram, şi anume prin specificarea atât a adresei de segment cât şi a deplasamentului în cadrul acestui segment}
• nu este nevoie de prezenţa vreunei directive Turbo Pascal pentru a face această funcţie vizibilă în modulul scris în limbaj de asamblare, deoarece un modul scris în limbaj de asamblare poate accesa orice procedură, funcţie, variabilă sau constantă cu tip declarată la nivelul cel mai exterior al unui program sau al unei unităţi Pascal, inclusiv rutinele din biblioteci, prin folosirea declaraţiei extrn în modulul asamblare
Asmf.asmassume cs:_TEXT, ds:_DATA_DATA segment
extrn glob:byte _DATA ends_TEXT segment
extrn CitSir: farAsmf proc far
public Asmfpush bpmov bp, spsub sp, 100hsub sp, 100hrez equ dword ptr [bp+10]copieSir equ byte ptr [bp-100h]sloc equ byte ptr [bp-200h]push dslds si, [bp+6]mov bx, ssmov es, bxlea di, copieSircld mov cx, 00FFh rep movsb
• pentru a se putea face legătura între acest modul şi modulul scris în Turbo Pascal, modulul scris în limbaj de asamblare trebuie să îndeplinească următoarele condiţii:- toate procedurile şi funcţiile trebuie să se afle într-un segment numit CODE sau CSEG, sau într-un segment al cărui nume se termină cu _TEXT;- toate datele declarate trebuie să fie plasate într-un segment numit CONST sau într-un segment al cărui nume se termină cu _DATA;
• declaraţia variabilei glob, definită în modulul Turbo Pascal
• declaraţia funcţiei CitSir, care a fost definită în modulul Turbo Pascal, dar va fi folosită în modulul curent; tipul subrutinei este far
• funcţia Asmf este definită în acest modul dar va fi folosită în modulul Turbo Pascal
• izolarea stivei
• se alocă în stivă 100h octeţi pentru copia parametrului de tip string transmis prin valoare
• se alocă în stivă 100h octeţi pentru rezultatul de tip string întors de către funcţia CitSir, care va fi apelată în acest subprogram
BP iniţial
offset adr. revenire
seg. adr. revenire
offset s
adr. seg. s
offset rez
adr. seg. rez
BP+0
BP+2
BP+6
BP
BP+10
Adresa de revenire
Adresa şirului transmis ca parametru
Adresa zonei de memorie unde va fi stringul
rezultatîntors de către funcţia Asmf
256 octeţi pentru copia parametrului de tip string
transmis funcţiei Asmf
SP
Efect al codului de intrareîn Asmf, scris explicit de catre programator pentru ca procedura este scrisa in asamblare si codul de intrare nu este generat automat
Efect al codului de apel al funcţiei Asmf, generat automat de catre compilatorul Turbo Pascal pentru ca apelul subprogramului are loc in Turbo Pascal
BP-100h(copieSir)
BP-200h(sloc)256 octeţi pentru
rezultatul de tip string întors de
funcţia CitSir
Fig. 8.2. Organizarea stivei după apelul şi intrarea în funcţia Asmf.
Asmf.asm
push ss
lea ax, sloc
push ax
call CitSir
. . .
offset adr. revenire
seg. adr. revenire
offset sloc
adr. seg. sloc (SS)
. . .
Efect al lui call CitSir
Generat explicit de către programator
Efect al codului de apel al funcţiei CitSir (faţă de apelul funcţiei Asmf, aici lipsesc parametri deoarece CitSir nu are parametri), scris explicit de catre programator pentru ca procedura este apelata in asamblare si codul de apel nu este generat automat
Stackframe-ul rutinei apelante Asmf (vezi figura 8.2.)
• spaţiul pentru şirul rezultat este alocat în stivă, aşadar adresa de segment a şirului rezultat este ss• salvăm în stivă această adresă si deplasamentul• apelul funcţiei CitSir, care citeşte un şir şi îl depune la adresa ss:sloc
Fig. 8.3. Organizarea stivei după apelul rutinei CitSir.
Asmf.asmpop axpop axles di, rezcldmov bx, ss mov ds, bxlea si, copieSirmov ch, 0mov cl, byte ptr [si]inc sipush diinc dicmp cx, 10jb et1mov cx, 10et1:
rep movsbpush sspop ds lea si, slocmov cl, byte ptr [si]inc sicmp cx, 10jb et2
• eliberarea zonei din stivă în care s-a pus adresa şirului rezultat este responsabilitatea apelatorului
• alternativ add sp, 4
• numărul de elemente al şirului transmis ca parametru se află în primul octet al şirului
• în continuare vom copia în şirul rezultat primele 10 caractere din şirul returnat de către funcţia CitSir (şirul sloc)• în acest scop, încărcăm în ds:si adresa de început a şirului sloc
• instrucţiunea movsb se va executa de cx ori; această instrucţiune copiază la adresa es:di (unde se află şirul rezultat) un octet de la adresa ds:si (unde se află copia şirului transmis ca parametru)
Asmf.asmet2:
rep movsblea si, globmov ax, _DATAmov ds, axmov cl, byte ptr [si]inc sicmp cx, 10jb et3mov cx, 10
et3:rep movsbpop axmov bx, disub bx, axdec bxles di, rezmov es:[di], blpop ds
mov sp, bppop bpret 4
asmf endp_TEXT endsend
• restaurăm valoarea pe care ds o avea la intrarea în subrutină
• refacem valorile lui sp şi bp (parte a codului de ieşire din subrutina Asmf• cu această ocazie se eliberează cei 200h octeţi alocaţi pentru stringul întors de CitSir şi pentru copia parametrului transmis către Asmf
• ieşire din funcţie cu scoaterea din stivă a 4 octeţi (este vorba despre scoaterea din stivă a parametrului – 2 octeţi pentru adresa de segment şi 2 octeţi pentru deplasament)
• eliberarea spaţiului din stivă ocupat de parametri face parte tot din codul de ieşire din subrutină
Cod de iesire din functia Asmf, scris explicit de catre programator, deoarece functia este scrisa in asamblare si codul de iesire nu este generat automat