+ All Categories
Home > Documents > PROGRAMMAZIONE MODULARE E LIBRERIE ESTERNE.doc

PROGRAMMAZIONE MODULARE E LIBRERIE ESTERNE.doc

Date post: 28-Oct-2015
Category:
Upload: luca-criniera-rinaldi
View: 53 times
Download: 0 times
Share this document with a friend
Description:
assembly PROGRAMMAZIONE MODULARE E LIBRERIE ESTERNE
31
Lucia Giammario Giammario document.doc 15/03/22 pag. 1 MODULO 4 Programmazione modulare e librerie esterne OBIETTIVI: Conoscere: lo stack e i meccanismi di utilizzo dello stesso le direttive MACRO …ENDM le istruzioni di chiamata / rientro da un sottoprogramma Saper: usare le istruzioni PUSH, POP per salvare / ripristinare un contesto la funzione dei parametri - per valore e per riferimento di indirizzo- distinguere tra salti/ chiamate entro e fuori segmento (NEAR / FAR) utilizzare il modello SMALL utilizzare le direttive di segmento , EQU, DB, DW, ORG utilizzare la funzione delle macro istruzioni usare i registri per passare i parametri usare la pila per passare i parametri scrivere una macro articolare un programma in sottoprogrammi e macro CONTENUTI: 1. Le direttive EXTRN e PUBLIC 2. Creazione e uso di librerie assembler 3. Scambio di dati tra procedure 4. La comunicazione tra le procedure 4.1. Comunicazione attraverso variabili globali 4.2. Comunicazione attraverso registri interni 4.2.1. Passaggio dei parametri per valore 4.2.2. Passaggio dei parametri per referenza 4.3. Passaggio dei parametri con uso dello stack 4.3.1. Passaggio dei parametri per valore 4.3.2. Passaggio dei parametri per referenza 5. Le MACRO: funzioni, dichiarazione e chiamata ( IN ALTRO MODULO) LABORATORIO: Stesura di programmi in sottoprogrammi e macro
Transcript

Lucia Giammario document.doc 17/04/23 pag. 1

MODULO 4 Programmazione modulare e librerie esterne

OBIETTIVI:Conoscere: lo stack e i meccanismi di utilizzo dello stesso le direttive MACRO …ENDM le istruzioni di chiamata / rientro da un sottoprogrammaSaper: usare le istruzioni PUSH, POP per salvare / ripristinare un contesto la funzione dei parametri - per valore e per riferimento di indirizzo- distinguere tra salti/ chiamate entro e fuori segmento (NEAR / FAR) utilizzare il modello SMALL utilizzare le direttive di segmento , EQU, DB, DW, ORG utilizzare la funzione delle macro istruzioni usare i registri per passare i parametri usare la pila per passare i parametri scrivere una macro articolare un programma in sottoprogrammi e macro

CONTENUTI:1. Le direttive EXTRN e PUBLIC2. Creazione e uso di librerie assembler3. Scambio di dati tra procedure4. La comunicazione tra le procedure

4.1. Comunicazione attraverso variabili globali4.2. Comunicazione attraverso registri interni

4.2.1. Passaggio dei parametri per valore4.2.2. Passaggio dei parametri per referenza

4.3. Passaggio dei parametri con uso dello stack4.3.1. Passaggio dei parametri per valore4.3.2. Passaggio dei parametri per referenza

5. Le MACRO: funzioni, dichiarazione e chiamata ( IN ALTRO MODULO)LABORATORIO: Stesura di programmi in sottoprogrammi e macro

Lucia Giammario document.doc 17/04/23 pag. 2

Programmazione modulare e librerie esterne

Quando un programma viene scritto usando un unico file sorgente, l’assemblaggio ed il Link viene effettuato su questo singolo file sorgente.Se però il programma è abbastanza complesso, conviene usare, la metodologia Top Down, preparare cioè oltre al programma principale, dei moduli separati, che vengono corretti e assemblati singolarmente. Questi moduli devono contenere le routine che utilizza il programma principale.Usando questa metodologia di lavoro, si dovranno allora creare tanti singoli file sorgente (.ASM), che verranno assemblati separatamente in modo da produrre tanti file oggetto (.OBJ), che verranno poi sottoposti ad una fase di LINK, per dare origine ad un unico file eseguibile (.EXE).Quando si usa la programmazione modulare occorre che i moduli, che compongono l’intera procedura, si scambino delle informazioni, in altri termini è necessario che il programma chiamante passi al programma chiamato i dati su cui questo deve operare e che il programma chiamato restituisca al chiamante i risultati dell’elaborazione.Occorre pertanto specificare innanzitutto che vi è un legame tra i vari moduli; a tale scopo si utilizzano 2 direttive dette EXTRN e PUBLIC.

1. Le direttive EXTRN e PUBLIC

La direttiva EXTRN, come mostra la figura 1, serve a specificare che le procedure o le variabili usate nel programma non si trovano nello stesso file sorgente, ma in un altro file, compilato separatamente, dove sono state dichiarate PUBLIC.

Lucia Giammario document.doc 17/04/23 pag. 3

Quando l’assemblatore trova delle labels dichiarate come EXTRN rimanda alla fase di linking la risoluzione dei collegamenti e l’assegnazione degli indirizzi logici.La direttiva EXTRN deve essere la prima istruzione del segmento di codice.

Esempio: Riferendoci alla figura precedente, occorrerà scrivere:EXTRN STAMPA:FAR

La clausola FAR serve a specificare al sistema che l’indirizzo della procedura (IR) deve essere a 32 bit, in quanto occorre considerare sia il registro CS che il registro IP (CS=2 byte + IP=2 byte).

La direttiva PUBLIC serve a specificare che la procedura è accessibile anche da moduli esterni. Pertanto deve essere contenuta nel segmento di codice del file Assembler, che contiene la procedura stessa.

Esempio: Sempre riferendoci alla figura precedente occorrerà scrivere:

PUBLIC STAMPA

Le procedure PUBLIC devono inoltre essere dichiarate, nel programma che le richiama, con la direttiva PROC seguiti dalla clausola FAR;

Lucia Giammario document.doc 17/04/23 pag. 4

Esempio: Sempre riferendoci alla figura precedente occorrerà scrivere:STAMPA PROC FAR

Se si dimentica di specificare EXTRN, il compilatore produce un errore di simbolo non definito.Se si dimentica di specificare PUBLIC, i simboli non vengono riconosciuti ed il linker produce un errore di RIFERIMENTO NON RISOLTO (UNRISOLVED EXTERNAL).

2.CREAZIONE E USO DI LIBRERIE ASSEMBLER

Una libreria di procedure è un insieme di routine già assemblate, che è possibile richiamare da altri programmi. Per far ciò occorre che le procedure siano dichiarate PUBLIC, cioè visibili ed accessibili da altre procedure; il nome della procedura deve essere seguita dalla parola chiave FAR, per indicare al processore che il registro contenente il CODE SEGMENT del programma chiamante deve essere salvato nello STACK, in quanto diverso dal CS del programma chiamato.

Così come ogni altro programma, la libreria deve essere compilata, al fine di produrre il file oggetto (OBJ). Il file oggetto della libreria va quindi linkato con il file oggetto che deve utilizzare la libreria stessa.

Il programma che richiama le procedure della libreria deve contenere, all’inizio del CODE SEGMENT la direttiva EXTRN, seguita dal nome delle procedure della libreria che si intende utilizzare.

Vi deve essere quindi una dichiarazione del tipo:

EXTRN Procedura_1:FAR, Procedura_2:FAR,…, Procedura_n:FAR

Nel richiamare una procedura di libreria, sorge il problema che essa potrebbe modificare i registri della CPU, che contengono lo stato del programma chiamante. Per questo motivo è necessario salvare lo stato dei registri nello Stack, in modo da poterli ripristinare quando la procedura ha completato l’esecuzione. Oltre ai registri occorre salvare l’area dati che utilizza il programma chiamante.Perciò il corpo di una procedura di libreria deve essere preceduta dalle istruzioni:

PUSH DSMOV AX, Nome_Segmento_Dati

Lucia Giammario document.doc 17/04/23 pag. 5

MOV DS, AX

Mentre prima dell’istruzione RET, che ritorna il controllo al programma chiamante occorre l’istruzione:

POP DS

al fine di ripristinare l’area dati utilizzata dal programma chiamante.

Esempio:Da quanto detto, deriva che la struttura di una libreria deve avere il seguente aspetto:

Nome_Segmento_Stack SegmentDW 100 DUP (?)Nome_Segmento_Stack Ends

Nome_Segmento_Dati SegmentDefinizione delle variabili usateNome_Segmento_Dati ENDS

Nome_Segmento_Codice SEGMENT

Libreria:

ASSUME CS:Nome_segmento_Codice,DS:Nome_Segmento_dati,SS:Nome_segmento_StackPUBLIC Procedura_1,Procedura_2, ... Procedura_n

Procedura_1 PROC FAR Salvataggio registri di lavoro nello Stack Modifica dell’indirizzo del registro Data-SegmentIstruzioni

Ripristino del registro Data-Segment Ripristino dei registri di lavoroRETProcedura_1 ENDP

Procedura_2 PROC FARSalvataggio registri di lavoro nello StackModifica dell’indirizzo del registro data-segment

IstruzioniRipristino del registro Data-Segment

Ripristino dei registri di lavoroRET

Procedura_2 ENDP..

Lucia Giammario document.doc 17/04/23 pag. 6

.Procedura_n PROC FAR...Procedura_n ENDP

Nome_Segmento_Codice ENDSEND Libreria

3. Scambio di dati tra procedure

Il programma chiamante e la libreria utilizzano una diversa area dati, un diverso segmento di codice, ma utilizzano gli stessi registri della CPU. L’utilizzo dei registri potrebbe portare a delle condizioni di errore, per questo motivo di solito si preferisce che lo scambio delle informazioni tra due moduli avvenga attraverso lo Stack.Pertanto prima di chiamare il sottoprogramma, il programma chiamante deve caricare nello Stack tutti i parametri di cui farà uso il sottoprogramma per riprenderli modificati, quando la procedura sarà terminata.Da parte sua la procedura dovrà prelevare i parametri su cui operare dallo Stack e reinserirli modificati, prima di restituire il controllo al programma chiamante. Inoltre, mentre del salvataggio e ripristino del registro CS se ne occupa direttamente il sistema, il salvataggio ed il ripristino del segmento dei dati, nonché il caricamento in DS del riferimento all’area dati della procedura, spetta al programmatore.Lo scambio dei parametri può avvenire con le usuali operazioni di PUSH e POP. Volendo si può utilizzare anche la direttiva EQU per associare al nome della variabile, l'espressione che determina l'indirizzo di allocazione della variabile stessa.La sintassi della direttiva EQU è:

Nome_var EQU espressione

Esempio:

Per associare il parametro DATO al suo indirizzo nello Stack, nella posizione BP+4, basta scrivere:

DATO EQU [BP+10]

In questo modo ogni riferimento allo Stack, alla posizione BP+4 può essere sostituita con DATO. In altri termini le due

Lucia Giammario document.doc 17/04/23 pag. 7

istruzioni che seguono producono lo stesso effetto:

MOV DATO,AX MOV [BP+10],AX

Di seguito vediamo un esempio di creazione di una libreria.

Esempio: Programma per la prova dell'assemblaggio separato di più moduli e loro linking per generare un unico file eseguibile;il programma stampa una stringa esterna di nome ‘messaggio’, richiamando la procedura di posizionamento e di stampa di una stringa, presenti nel file LIBRERIA.

;Programma EXTRN.asm

stack_seg segment para stack 'stack' dw 100 dup(?)stack_seg ends

data_seg segment para public 'data' mess1 db 'Variabile locale dichiarata nel main','$' mess2 db 'ESC per uscire',7,10,13,'$'

extrn messaggio:far ; variabile dichiarata in LIBRERIA extrn valore:word ; variabile dichiarata in LIBRERIA

data_seg ends

code_seg segment para public 'code' assume cs:code_seg,ds:data_seg,ss:stack_seg

extrn erase:far,posiziono:far,stampa:far,wait_tasto:far

start: ;main program (modulo chiamante)

mov ax,data_seg mov ds,ax mov ax,stack_seg mov ss,ax call erase; richiama la procedura ‘erase’ presente in ; LIBRERIA.asm

mov dl,5 mov dh,10

Lucia Giammario document.doc 17/04/23 pag. 8

call posiziono ; richiamo procedura ‘posiziono’ da LIBRERIA

;STAMPA MESSAGGIO mov dx,offset messaggio ;variabile dichiarata in LIBRERIA call stampa ;richiama la procedura ‘stampa’ ;presente in LIBRERIA mov dl,2 mov dh,12 call posiziono mov dx, offset mess1 call stampa mov dl,5 mov dh,14 call posiziono mov dx, offset mess2 call stampa vai: ;Attesa del tasto ESC call wait_tasto ; ;richiama la procedura ‘wait_tasto’ ;presente in LIBRERIA

cmp al,27 jne vai

mov ax,4c00h int 21h

code_seg endsend start

;programma LIBRERIA.ASM

;Modulo Assembler contenente le procedure per :

;cancellare il video;posizionare il cursore;stampare una stringa;attendere un tasto

stack_seg segment para stack 'stack' dw 100 dup(?)stack_seg ends

data_seg segment para public 'data'

Lucia Giammario document.doc 17/04/23 pag. 9

messaggio db 'Variabile dichiarata in LIBRERIA, ma richiamata da EXTERN$'valore dw 'Variabile dichiarata in LIBRERIA, ma richiamata da EXTERN$'

public messaggio, valore

data_seg ends

code_seg segment para public 'code' assume cs:code_seg,ds:data_seg,ss:stack_seg

start: public erase,posiziono,stampa,wait_tasto erase proc far ;procedura per cancellare lo schermo

mov ah,06 mov al,00 mov cx,0 mov dh,24 mov dl,79 mov bh,07 int 10h ret

erase endp

posiziono proc far ;procedura di posizionamento del cursore

mov bh,0 mov ah,02h int 10h

ret posiziono endp

stampa proc far ;procedura per la stampa di una stringa mov ah,09 int 21h ret stampa endp

wait_tasto proc far ;procedura di attesa di pressione di un tasto

mov ah,00 int 16h

Lucia Giammario document.doc 17/04/23 pag. 10

ret

wait_tasto endp

code_seg endsend start

4. La comunicazione tra le procedure

Si è già detto che quando un programma ne richiama un altro è necessario che esso passi delle informazioni al programma chiamato, e che quest’ultimo restituisca dei risultati. Scopo della prossima sezione sarà perciò mettere a fuoco come avviene lo scambio di informazioni tra i vari moduli. I dati che le procedure si scambiano prendono il nome di parametri.Vi sono tre modi in cui il programma principale e una procedura possono scambiarsi questi parametri :

1. attraverso variabili globali;2. attraverso i registri interni della macchina; 3. attraverso lo Stack.

4.1.Comunicazione attraverso variabili globali

Le variabili globali, sono celle di memoria comuni ai due programmi; affinché una variabile sia visibile da una procedura esterna occorre dichiararla PUBLIC. La procedura esterna, a sua volta, per utilizzare la variabile deve averla dichiarata come EXTRN .Non è sicuramente il metodo migliore di scambio dei parametri, in quanto si potrebbe modificare inavvertitamente il contenuto delle celle comuni.Esempio:

EXTERN valore:word

4.2.Comunicazione attraverso i registri interni

Questo metodo è valido per le procedure interne, ma si rivela poco sicuro se le procedure sono esterne in quanto inavvertitamente si potrebbe modificare il valore di tali registri durante l’esecuzione della procedura; il passaggio dei parametri attraverso i registri interni può avvenire sia per valore che per referenza.

4.2.1.Passaggio dei parametri per valore

Lucia Giammario document.doc 17/04/23 pag. 11

In questo tipo di comunicazione il programma chiamante deve porre nei registri il valore su cui la procedura deve operare.La procedura chiamata, a sua volta, prima di restituire il controllo al programma chiamante, deve porre nei registri il risultato.

Esempio:

Per chiarire questo tipo di passaggio di parametri,supponiamo che le variabili Num1 e Num2 contengano due numeri, e di voler effettuare la loro somma, usando il passaggio dei parametri per valore, tramite registri.

Il programma principale deve contenere le istruzioni per specificare che sarà richiamata una procedura esterna e per caricare nei registri, prima della chiamata della procedura, il valore delle variabili, come mostrato di seguito:

EXTRN somma:FAR

MOV BL, Num1 MOV BH, Num2 CALL somma

Il sottoprogramma in tal caso, avendo già i valori nei registri può effettuare la somma, come mostrato di seguito:

Somma PROC FARADD BH, BLRET

Somma ENDP

Al programma principale non resta che prelevare la somma dal registro BH.

4.2.2.Passaggio dei parametri per referenza

In questo tipo di comunicazione il programma chiamante deve porre nei registri gli indirizzi delle variabili su cui la procedura deve operare.La procedura chiamata a sua volta , prima di restituire il controllo al programma chiamante deve porre nei registri l’indirizzo delle celle di memoria che contengono il risultato.

Lucia Giammario document.doc 17/04/23 pag. 12

Esempio:

Per chiarire questo tipo di passaggio di parametri supponiamo che le variabili Num1 e Num2 contengano due numeri, e di voler calcolare il quoziente ed il resto della divisione tra Num1 e Num2.

Il programma principale dove contenere le istruzioni per specificare che sarà richiamata una procedura esterna e per caricare nei registri, prima della chiamata della procedura, l’indirizzo delle variabili, come mostrato di seguito:

EXTRN Dividi:FAR

LEA SI,Num1 ;carica nel registro SI l’indirizzo di Num1LEA DI, Num2 ;carica nel registro DI l’indirizzo di Num2

CALL Dividi

Il sottoprogramma invece dove caricare nei registri AL e BL i valori, i cui indirizzi sono contenuti rispettivamente nei registri SI e DI, effettuare la divisione, e riportare il quoziente ed il resto nelle variabili, come mostrato di seguito.

Dividi PROC FAR

MOV AL, BYTE PTR [SI]MOV BL, BYTE PTR [DI]DIV BL MOV BYTE PTR [SI], ALMOV BYTE PTR [DI],AH RETDividi endp

5.3.Passaggio di parametri con uso dello Stack

Questo metodo si rivela più sicuro nella chiamata di procedure esterne in quanto non è possibile modificare inavvertitamente i valori, essendo depositati nella pila. Il passaggio dei parametri, prevede anche qui diverse alternative.

5.3.1.Passaggio dei parametri per valore

Il caso più semplice è quando vi sono solo parametri di input per la procedura e le variabili non sono strutturate; in tal caso basta

Lucia Giammario document.doc 17/04/23 pag. 13

infatti che il programma chiamante metta il valore di tali variabili nello Stack, da cui il programma chiamato andrà poi a prelevarli.

Se lo scambio dei parametri avviene sia in input che in output e la variabile è ancora semplice, bisogna porre maggiore attenzione, in quanto è necessario che la procedura chiamata a sua volta, prima di restituire il controllo al programma chiamante, depositi nello stack i risultati, in modo tale che quando il controllo torna al programma chiamante, questo possa prelevare dallo stack i risultati.

Esempio:

Per chiarire questo concetto rivediamo ancora la somma dei numeri Num1 e Num2, usando però il passaggio dei parametri per valore, tramite stack.

Il programma principale deve contenere le istruzioni per specificare che deve essere richiamata una procedura esterna, per caricare nello stack, prima della chiamata della procedura, il valore delle variabili, come mostrato di seguito:

EXTRN somma:FAR

MOV BX, Num1 PUSH BX MOV BX, Num2 PUSH BX

CALL sommaPOP BX

Il sottoprogramma ‘Somma’ oltre a salvare il registro BP nello stack, deve caricare in BP il valore del puntatore attuale allo stack (SP).

Dopo aver assegnato a BP il valore di SP si ha che:BP+2 punta a IPBP+4 punta a CSBP+6 punta a NUM2BP+8 punta a NUM1Per cui la routine troverà i parametri corretti in [BP+6] e [BP+8].

Dopo questa operazione si possono caricare nei registri i parametri in ingresso, effettuare la somma, portare il risultato nello stack e ripristinare il puntatore allo stack. La routine assume pertanto il seguente aspetto:

Lucia Giammario document.doc 17/04/23 pag. 14

Somma PROC FARPUSH BPMOV BP,SPMOV AX,[BP+6]

MOV BX,[BP+8]ADD BX

MOV [BP+6],AXPOP BPRET

Somma ENDP

Quando viene chiamata la routine Somma, che a sua volta salva nello stack il registro BP, lo stack si presenta come nella figura 2.

5.3.2.Passaggio dei parametri per referenza

In questo tipo di comunicazione il programma chiamante deve porre nello stack gli indirizzi delle variabili su cui la procedura deve operare.Se lo scambio dei parametri avviene sia in input che in output è necessario che la procedura chiamata a sua volta , prima di restituire il controllo al programma chiamante depositi nello stack gli indirizzi delle celle di memoria che contengono il risultato. Questo procedimento diventa fondamentale per le stringhe e per i vettori, ed in generale se la variabile è strutturata. Per le variabili strutturate è infatti indispensabile passare sempre l’offset, o meglio l’indirizzo completo DS:OFFSET.

Quando le procedure si scambiano sia parametri in ingresso, che in uscita, lo spazio occupato dai parametri di output è di solito quello precedentemente occupato dai parametri di input.Quando una procedura ha invece più parametri occorre risolvere il problema dello spazio in cui collocare i parametri di uscita. Un metodo potrebbe consistere nel fare tante PUSH in ingresso quanti saranno i parametri d’uscita in modo da avere lo spazio sufficiente per salvare tali parametri.

Esempio:

Lucia Giammario document.doc 17/04/23 pag. 15

Supponiamo di avere come parametro di input I1, e come parametri di output O2 ed O3; utilizzando questa metodologia, lo Stack, subito dopo la chiamata della procedura assumerà l’aspetto mostrato nella figura che segue.

Al termine della procedura i parametri di uscita O2 ed O3 si trovano rispettivamente nella cella occupata da I1 e nella cella lasciata libera di proposito.

Chiariamo meglio questi concetti attraverso i seguenti esempi.

Esempio:

Rivediamo ancora il calcolo del quoziente e del resto dei numeri Num1 e Num2, usando il passaggio dei parametri per indirizzo, tramite stack.

Il programma principale come al solito deve contenere le istruzioni per specificare che sarà richiamata una procedura esterna e per caricare nello stack, prima della chiamata della procedura, l’indirizzo delle variabili, come mostrato di seguito:

EXTRN Dividi:FAR . . .

LEA SI, Num1 LEA DI, Num2

Lucia Giammario document.doc 17/04/23 pag. 16

PUSH SI PUSH DI

CALL Dividi POP SI POP DI

Il sottoprogramma deve come al solito salvare il registro BP nello stack e caricare in BP il valore del puntatore attuale allo stack (SP), quindi caricare nei registri l’indirizzo dei parametri in ingresso, effettuare la divisione, portare il risultato nelle variabili e ripristinare il puntatore allo stack, come mostrato di seguito:

Dividi PROC FAR

PUSH AXPUSH BXPUSH BPMOV BP,SPMOV SI,WORD PTR [BP+12]MOV DI,WORD PTR [BP+10]MOV AL,BYTE PTR [SI]MOV BL,BYTE PTR [DI]MOV AH,00HDIV BLMOV BYTE PTR [SI],ALMOV BYTE PTR [DI],AHPOP BPPOP BXPOP AXRETDividi ENDP

Nella figura che segue vediamo come si presenta lo stack quando viene chiamata la routine Dividi.

Lucia Giammario document.doc 17/04/23 pag. 17

Si noti che: Gli indirizzi delle variabili Num1 e Num2 sono stati caricati

nei registri indice SI e DI, con l’istruzione LEA. Prima di chiamare la procedura Dividi, gli indirizzi di Num1 e

Num2 sono stati caricati con l’istruzione PUSH, nello stack. La chiamata della procedura Dividi fa si che vengano salvati i

registri CS e IP. La procedura Dividi deve quindi salvare i registri su cui

lavora (AX,BX) ed il registro BP; inoltre deve spostare in BP il contenuto di SP (=BP-12), in modo da poter accedere correttamente ai parametri.

Con MOV SI,WORD PTR [BP+12] in SI dovrà essere messo l’indirizzo di Num1.

Con MOV DI,WORD PTR [BP+10] in DI dovrà essere messo l’indirizzo di Num2.

Dopo la divisione, quoziente e resto vengono posti in Num1 e Num2, attraverso le istruzioni MOV BYTE PTR [SI],AL e MOV BYTE PTR [DI],AH.

Esempio:

Si supponga di immettere da tastiera una stringa lunga al più 20 caratteri, caricata nella variabile di nome STRINGA, dichiarata nel programma principale; inoltre si supponga di caricare sempre da tastiera nella variabile CAR un carattere qualsiasi.Si vuole scrivere una procedura che ricevuti come parametri d’ingresso la stringa ed il carattere, restituisca come parametro di uscita il n° di volte che il carattere compare nella stringa.

Poiché lo Stack lavora su 16 bit, occorre prima passare il carattere in un registro a 16 bit e poi, come mostra la figura a lato, caricare il contenuto del registro nello Stack. Pertanto il programma principale dovrà contenere le seguenti istruzioni:

MOV AX,OFFSET STRINGA;passaggio per indirizzo, essendo una stringaPUSH AXMOV AL,[CAR]; il passaggio avviene per valore, essendo la variabile ;semplice e di solo inputXOR AH,AH PUSH AX

Lucia Giammario document.doc 17/04/23 pag. 18

CALL CONTA ;chiamata di procedura per contare le occorrenze del caratterePOP AX ;al ritorno da CONTA, si preleva il n° di occorrenze del ;carattere e si pone nel registro AX

Dopo la chiamata della procedura Conta, lo Stack si è modificato, come mostra la figura che segue:

In linea di massima invece, la procedura esterna CONTA potrebbe essere impostata come segue:

CONTA PROC FARPUSH BP ;salva nello stack il registro BP, usato nel programma ;principale, MOV BP,SP ;BP diventa il nuovo indice dello STACK

Dopo che la procedura ha eseguito queste due operazioni, il valore di BP è stato modificato, e di conseguenza anche gli indirizzi dipendenti da BP, che adesso assumono i valori che si possono vedere di seguito, nella figura 6:

[BP] contiene l’indirizzo iniziale dello stack [BP+2] e [BP+4] contengono IR, cioè l’indirizzo di ritorno (CS+IP)[BP+6] contiene il carattere[BP+8] contiene offset della stringa

MOV BX,[BP+8]; carica in BX l’offset della stringaXOR SI,SI ; azzera SI, per puntare all’inizio della ;stringa

MOV AX,[BP+6]; carica in AX il carattere

Lucia Giammario document.doc 17/04/23 pag. 19

XOR CX,CX ; azzera il contatore per contare le occorrenze del carattereCICLO: CMP [BX+SI],’$’; si suppone che la stringa termini con il ; carattere ‘$’

JE FINECICLO CMP[BX+SI],AL JNE AVANZA INC CX

AVANZA: INC SI

CMP SI,20 JNE CICLOFINECICLO: MOV[BP+8],CX ; carichiamo nello Stack il parametro ; d’uscita da passare al programma ; principale; POP BP ; estraggo la casella affiorante RET 2 ; estraggo IR e i 2 byte successivi ; contenenti il carattere, in modo che la ;casella affiorante contenga il risultato, cioè CX.CONTA ENDP

PUSH BP ; istruzione obbligatoria.MOV BP,SP ; BP diventa l’indice sullo STACK

Notare che il parametro d’uscita è stato posizionato nello Stack in modo tale che dopo l’istruzione RET, possa affiorare sullo Stack per essere prelevato dal programma principale.

Esempio:

Scrivere una Procedura per immettere una sequenza di caratteri in una variabile strutturata di nome STRINGA, lunga al più 80 caratteri. Il caricamento termina quando l’utente inserisce INVIO. La stringa deve essere chiusa con il carattere ‘$’.Il programma principale deve passare alla procedura l’indirizzo di STRINGA e la sua lunghezza massima. La procedura deve restituire in output il numero effettivo di caratteri introdotti.Scrivere una seconda procedura che ricevuta in ingresso la

Lucia Giammario document.doc 17/04/23 pag. 20

variabile STRINGA la divida in due sottostringhe, di nome MAIU e MINU, entrambe terminante con ‘$’; la prima deve contenere i caratteri maiuscoli (MAIU), la seconda i caratteri minuscoli (MINU). La procedura deve restituire in output le lunghezze delle due nuove stringhe.

Il programma principale potrebbe essere impostato come segue:

;DICHIARAZIONE:

STRINGA DB 8+1 dup (‘$’)MINU DB 80+1 dup (‘$’)MAIU DB 80+1 dup (‘$’)

;PROGRAMMA PRINCIPALE:

;Preparazione alla procedura CARICA

MOV AX,OFFSET STRINGAPUSH AXMOV AL,80 XOR AH,AH PUSH AX CALL CARICAPOP CX ; CX contiene la lunghezza reale di “STRINGA”

;Preparazione alla procedura GENERA

MOV AX,OFFSET STRINGAPUSH AXPUSH CX ;lunghezza reale di “STRINGA”MOV AX,OFFSET MINUPUSH AXMOV AX,OFFSET MAIUPUSH AX CALL GENERA POP AX ; salva in AX la lunghezza di MAIUPOP BX ; salva in BX la lunghezza di MINU

; Procedura CARICA; la procedura carica mette nella stringa i caratteri immessi da tastiera.

; Procedura GENERA ; la procedura genera crea le due nuove stringhe.

Lucia Giammario document.doc 17/04/23 pag. 21

GENERA PROC FARPUSH BP ; Istruzioni obbligatorieMOV BP,SP ;MOV SI,[BP+12] ;salva in SI l’offset di STRINGAMOV DI,[BP+6] ;salva in Di l’offset di MAIUMOV BX,[BP+8] ;salva BX l’offset di MINUMOV CX,[BP+10] ;salva la lunghezza reale di STRINGAJCXZ USCITA

A questo punto lo Stack assume l’aspetto in figura 7:

RIPETI:MOV AL,[SI];mette in AL il contenuto della cella puntata da SICMP AL,32JE FINESTRINGACMP AL,97JB MAIUSCOLOMOV [BX],ALINC BX ; incrementa il puntatore a MINU JMP AVANZA

MAIUSCOLO:MOV [DI],ALINC DI ; incrementa il puntatore a MAIU

AVANZA:INC SI

LOOP RIPETIFINESTRINGA:SUB DI,[BP+6] ;sottrae l’offset di DI a quello iniziale di ;MAIU e trova così la lunghezza di MAIU

Lucia Giammario document.doc 17/04/23 pag. 22

SUB BX,[BP+8] ;sottrae l’offset di BX a quello iniziale di ;MINU e trovo così la lunghezza di MINUMOV [BP+12],DI ; mette nella pila la lunghezza di MAIUMOV [BP+10],BX ; mette nella pila la lunghezza di MINUPOP BP ;toglie dallo Stack la casella affiorante, cioè ;quella di BPRET 4 ;RET toglie dallo Stack la casella di IR mentre ;il 4 toglie le caselle di “MAIU” e “MINU”GENERA ENDP

Di seguito viene presentato un semplice esercizio completamente svolto relativo al passaggio dei parametri.

Esercizio Svolto:

;Scrivere un programma che dopo aver assegnato due numeri; alle variabili NUM1 E NUM2 effettui: ;;1) la chiamata di una procedura, che ricevuti i due parametri,;ne effettua la divisione e restituisce il quoziente ed il resto;nei parametri iniziali. Il passaggio dei parametri deve avvenire;attraverso registri e per valore. ;;2) la chiamata di una procedura, che ricevuti i due parametri,;ne effettua il prodotto e lo restituisce in uno dei parametri iniziali.; Il passaggio dei parametri deve avvenire attraverso registri e; per referenza. ;;3) la chiamata di una procedura, che ricevuti i due parametri,; ne effettua la differenza e la restituisce in uno dei parametri iniziali.; Il passaggio dei parametri deve avvenire attraverso lo stack e per ;valore.;;4) la chiamata di una procedura, che ricevuti i due parametri,;ne effettua la somma e la restituisce in uno dei parametri ;iniziali. Il passaggio dei parametri deve avvenire attraverso lo ;stack e per referenza.

stack_seg segment para stack 'stack' dw 100 dup(?) stack_seg ends

Lucia Giammario document.doc 17/04/23 pag. 23

data_seg segment para public 'data';..................Dichiarazione delle variabili................ num1 dw (?)num2 dw (?)

data_seg endscode_seg segment para public 'code' assume cs:code_seg,ds:data_seg,ss:stack_segstart: mov ax,data_seg mov ds,ax mov ax,stack_seg mov ss,ax; Inizio Programmainizio:;......................Passaggio dei parametri tramite registri;..................................e per valore....................mov num1,21mov num2,6mov ax,num1 mov bx,num2call dividimov num1,ax;.......................Passaggio dei parametri tramite.........;.......................registri e per indirizzi................mov num1,7mov num2,3lea di,num1lea si,num2call moltiplicazione;........................Passaggio dei parametri tramite.......;........................lo stack e per valore.................mov ax,num1push axmov ax,num2push axcall sottrazionepop axmov num1,ax;.......................Passaggio dei parametri tramite lo.......;...................... stack e per indirizzi...................mov num1,6mov num2,3lea di,num1push dilea di,num2push dicall addizione;*******************************************************************;ritorno al dos mov ax,4c00h

Lucia Giammario document.doc 17/04/23 pag. 24

int 21h

;Procedure;* * * * * * * * * * * * * * * * * * * * ** * * * * * * * * * * * * ;*Procedura dividi ;*Funzione:procedura per effettuare la divisione con passaggio dei ;* parametri tramite registri e per valore ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * dividi proc neardiv bxretdividi endp

;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ;*procedura moltiplicazione;* funzione:procedura per effettuare il prodotto con passaggio ;* dei parametri tramite registri e per referenza;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * moltiplicazione proc nearmov ax,[di]mov bx,[si]mul bxmov [di],axmov [si],bxretmoltiplicazione endp;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ;* procedura sottrazione ;* funzione: procedura per effettuare la sottrazione con passaggio ;* dei parametri tramit lo stack e per valore * ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * sottrazione proc nearpush bpmov bp,spmov ax,[bp+4]mov bx,[bp+6]mov num2,bxsub ax,bxmov [bp+6],axpop bpret 2sottrazione endp;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *;* procedura addizione *;* funzione: procedura per effettuare la somma con passaggio *;* di parametri attraverso lo stack e per referenza * ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * addizione proc nearpush bpmov bp,spmov si,[bp+6]

Lucia Giammario document.doc 17/04/23 pag. 25

mov di,[bp+4]mov ax,[si]mov bx,[di]add ax,bxmov [si],axmov [di],dxpop bpret 2 addizione endp

;istruzioni finali code_seg endsend inizio

Lucia Giammario document.doc 17/04/23 pag. 26


Recommended