Ciao visitatore, se sei un utente effettua il log-in, altrimenti registrati cliccando Qui.

News Articoli e Recensioni Feedback Sala Giochi Download Tags Chat HwMania Imagehost
HwMania > Software > Programmazione

Programmazione Tutto sulla programmazione dei software.

Rispondi
 
LinkBack Strumenti discussione Modalità visualizzazione
Vecchio 05-05-2007, 22.11.22   #1 (permalink)
No eheheh..furbetto
 
L'avatar di Dj`LoRdZ`
 
Data Registrazione: 29-03-2007
Residenza: Ghost City
Messaggi: 638
Discussioni: 42
Le mie foto: (0)
Feedback: (0)
Invia un messaggio via MSN a Dj`LoRdZ` Manda un messaggio tramite Skype™ a Dj`LoRdZ`
Interfacciamento tra Assembly e Turbo Pascal

Interfacciare l'Assembly con il Turbo Pascal (Guida scritta dalla Kn|GhT CrEw)

Questo tutorial è fuori luogo ma siccome il mio amico Dj`LoRdZ` è più di una volta che mi chiede alcune cose su questo argomento ho deciso di anticipare e di dedicargli questo breve tutorial. Quindi lordz è tutto tuo !!!

Come saprete scrivere programmi stand alone in assembly non è una cosa molto comoda visto anche che oggi esistono dei compilatori che riescono ad ottimizzare il codice in modo sorprendente, quindi invece di scrivere il programma interamente in assembly si preferisce spesso utilizzare un linguaggio ad alto livello che chiama alcune routine critiche scritte in assembly.
Per fare questo col Pascal il vostro programma deve contenere la direttiva $L e la dichiarazione delle procedure e funzioni EXTERNAL, a sua volta il programma assembly deve contenere le direttive PUBLIC e EXTRN.
La direttiva {$L FILEASM.OBJ} indica al programma Pascal di cercare il file FILEASM.OBJ che come avrete già capito deve essere compilato.
Ogni procedura o funzione Assembly che volete che venga vista dal programma Pascal deve essere dichiarata PUBLIC e deve avere un corrispondente sempre nel programma Pascal.
La sintassi di una procedura EXTERNAL in Pascal è simile ad una dichiarazione di una procedura FORWARD e deve stare al livello più esterno del programma o della unit (non può cioè essere dichiarata all'interno di altre procedure):


procedure AsmProc(a:integer;b:real); external;


Questa dichiarazione corrisponderà al seguente frammento di codice Assembly:


Codice:
          CODE    SEGMENT BYTE PUBLIC
          AsmProc PROC NEAR
                  PUBLIC AsmProc
                  ...
                  ...
                  ...
         AsmProc  ENDP
         CODE     ENDS
Solo le label dichiarate con la direttiva PUBLIC nel programma Assembly sono visibili dal Pascal ed esse devono essere dichiarate nel CODE SEGMENT in quanto il Turbo Pascal non permette definizioni PUBLIC nel DATA SEGMENT.

Un modulo Assembly può accedere ad ogni funzione , procedura, variabile o costante solo se dichiarata nel livello più esterno del programma Pascal (quello delle variabili globali).
Supponiamo di aver dichiarato le seguenti variabili in Pascal:

Codice:
	var
         a:byte;
	 b:word;
         d:integer;
	 c:shortint;
	 e:real;
	 l:pointer;
tutte queste variabili sono accessibili dal programma Assembly usando la direttiva EXTRN in questo modo:

Codice:
	EXTRN A:BYTE
	EXTRN B:WORD
	EXTRN C:BYTE
 	EXTRN D:WORD 
	EXTRN E:FWORD   
	EXTRN L:DWORD

per quanto riguarda le procedure e le funzioni facciamo riferimento al seguente esempio:

Codice:
{Codice Turbo Pascal}
unit Esempio1;
 
interface
 procedure Proc1;
 procedure Proc2;

implementation
 var
  A:word;

 procedure AsmProc; near; external;
  {$L ASMPROC.OBJ}

 procedure Proc2;
  begin
   writeln('Siamo in Proc2');
  end;
 
 procedure Proc3; near;
  begin
   writeln('Siamo in Proc3');
  end;
 
 procedure Proc4; far;
  begin
   writeln('Siamo in Proc4');
  end;

 procedure Proc1;
  begin
   writeln('Siamo in Proc1');
   A:=10;
   writeln('Prima di AsmProc A vale ',A);
   AsmProc;
   writeln('Dopo AsmProc A vale ',A);
  end;
end.

;Codice  Assembly

DATA    SEGMENT WORD PUBLIC
        ASSUME DS:DATA
        EXTRN  A:WORD
DATA    ENDS

CODE    SEGMENT BYTE PUBLIC
        ASSUME CS:CODE
        EXTRN  Proc2:FAR
        EXTRN  Proc3:NEAR
        EXTRN  Proc4:FAR
        
AsmProc PROC NEAR
        PUBLIC AsmProc
        CALL   FAR PTR Proc2
        CALL   Proc3
        CALL   FAR PTR Proc4
        mov    cx,ds:A		;Queste 3 instruzioni sottraggono 2 da A
        sub    cx,2    
        mov    ds:A,cx
        ret
AsmProc ENDP
CODE    ENDS
        END

Il programma principale sar...:

Codice:
 program Prova;
  uses Esempio1;
 begin
  proc1;
 end.


Provate a compilare il tutto e ad eseguire il programma, non spenderò ulterior tempo basta vedere l'output del programma per capire cosa succede.

Vediamo ora un altro aspetto molto importante : il passaggio dei parametri. Il Turbo Pascal passa i parametri alle funzioni ed alle procedure salvandoli nello stack nell'ordine in cui li incontra nella dichiarazione, vedremo di seguito come questi vengono salvati:

- PARAMETRI PASSATI PER VALORE -
I parametri passati per valore sono quelli che non possono essere modificati dalla funzione o procedura che li usa, questi vengono trattati in modo diverso a seconda del tipo:

- Tipi scalari (Boolean, Char, Shortint,Byte, Integer, Word, Longint,Subrange
type ed Enumerated types); dipende dalla dimesione della variabile.
Se la variabile occupa 1 byte viene salvata nello stack come se fosse di 2
byte ma la parte più significativa è ignorata.
Se la variabile occupa 2 byte viene pushata nello stack cosi com'è.
Se la variabile occupa 4 byte occuper... due posizioni nello stack: prima
vengono salvati i 2byte più significativi poi gli altri 2

- Real
Sono salvati nello stack e occupano 3 posizioni (6byte) prima viene salvata
la parte più significativa.

- Pointer
Vengono salvati direttamente nello stack come puntatori far (la prima word
contiene il segmento la seconda l'offset).Il programma assembly può usare
le istruzioni LDS o LES per recuperare il valore del puntatore.

- String
Le stringhe a causa della loro lunghezza non vengono salvate nello stack,
in esso si salva il puntatore alla stringa. E' quindi dovere della procedura
chiamata non modificare la stringa referenziata dal puntatore, essa deve
copiarsi la stringa e lavorare sulla copia.

- Record e Array
Se la loro dimensione è di 1, 2 o 4 byte vengono salvati nello stack come i
tipi scalari, se invece la loro dimensione è 3, 5 o maggiore nello stack si
salva il puntatore come nel caso di stringhe.

- Set
Vengono trattati come le stringhe, si salva un puntatore che punta ad una
rappresentazione a 32 bit del set; il primo bit (LSB) corrisponde al primo
elemento del set.

- PARAMETRI PASSATI PER INDIRIZZO -
Tutti i parametri passati per indirizzo (con il var nelle intestazioni delle procedure) passano un puntatore di tipo far che punta alla loro attuale locazione di memoria.


Il Turbo Pascal si aspetta che tutti i parametri nello stack siano rimossi prima di uscire dal sottoprogramma.
Ci sono due modi per sistemare lo stack. Potete utilizzare l'istruzione RETn dove n è il numero di byte dei parametri che sono stati salvati nello stack, oppure si può salvare l'indirizzo di ritorno ed estrarre i parametri uno a uno.

Vediamo ora come si accede ai parametri passati dal Turbo Pascal al programma Assembly.
Quando la routine riceve il controllo in cima allo stack c'è l'indirizzo di ritorno (2 o 4 byte dipende se la routine è near o far) e sotto i parametri che gli sono stati passati.
Ci sono 3 tecniche per accedere a questi parametri :

- Usare il registro BP per accedere allo stack
- Usare un altro registro (base o indice) per prelevare i parametri
- Estrarre l'indirizzo di ritorno e poi i parametri

Le prime due sono più complicate e le vediamo dopo, la terza prevede di salvare l'indirizzo di ritorno in un posto sicuro e poi di mettere i parametri in registri; quest'ultima tecnica funziona bene se la routine in questione non richiede spazio per le variabili locali.
La prima tecnica prevede l'uso del Base Pointer come indice sullo stack nel seguente modo:


Codice:
        CODE    SEGMENT
                ASSUME cs:CODE
        MiaProc PROC FAR             ;procedure MiaProc(i,j:integer); 
external;
                PUBLIC MiaProc
        j       EQU WORD PTR [bp+6]  ;j è sopra il BP salvato e l'ndirizzo
                                     ;di ritorno
        i       EQU WORD PTR [bp+8]  ;i è appena sopra j
                push    bp           ;salva il valore di BP
                mov     bp,sp        ;fa puntare BP allo stack
                mov     ax,i         ;in questo modo accedo alle varibili 
                ...
                ...

Quando si usa il BP per accedere ai parametri il Turbo Assembler prevede un metodo alternativo per calcolare gli offset delle variabili utilizzando la direttiva ARG.
Questa va usata all'interno di una PROC e determina automaticamente l'offset dei parametri relativo a BP. Inoltre calcola anche la dimensione totale dei parametri per poterla usare con la RET.
Siccome i simboli creati con ARG sono locali alla procedura non c'è bisogno di usare nomi unici in procedure diverse.
Qui di seguito vi riscrivo l'esempio di poco fa usando la direttiva ARG:


Codice:
        CODE    SEGMENT
                ASSUME cs:CODE
        MiaProc PROC FAR             ;procedure MiaProc(i,j:integer);external;
                PUBLIC MiaProc
                ARG j:WORD, i:WORD = RetBytes
                push    bp
                mov     bp,sp
                mov     ax,i
                ...
                ...

L'istruzione ARG j:WORD, i:WORD = RetBytes uguaglia automaticamente i a [WORD PTR BP + 6] e j a [WORD PTR BP + 8].
La variabile RetBytes contiene il numero di byte occupati di parametri (in questo caso 4), cos? la procedura può finire con RET RetBytes.
Tutte queste variabili esistono solo all'interno della procedura.
Inoltre la direttiva ARG tiene conto del fatto che la procedura sia FAR o NEAR.
Una cosa a cui si deve fare attenzione è che usando questa direttiva i parametri sono estratti in ordine inverso a come sono dichiarati nella procedura Pascal.
Un'altra precauzione da considerare è che il Turbo Pascal salva le variabili che occupano un solo byte in una posizione dello stack (2byte) ed è compito del programmatore tener conto di questo; ad esempio supponiamo di avere:

function MiaFunc(i,j:char):string; external;

La direttiva ARG deve essere qualcosa del tipo:

ARG j:BYTE:2, i:BYTE:2 =RetBytes RETURNS resultWORD

Il :2 dopo gli argomenti è necessario per dire al Turbo Assembler che ogni carattere viene salvato come un array di 2 byte (a noi interessa solo il byte meno significativo); la parola RETURNS specifica la variabile di uscita che nel caso di stringhe come abbiamo visto è il puntatore ad essa.
Nota: la dimensione della stringa non ha alcune effetto sulla variabile RetBytes.

Un'altra semplificazione messa a disposizione dal Turbo Assembler è la direttiva .MODEL che permette di specificare oltre il modello di memoria da usare il linguaggio da supportare. Sempre sull'esempio di prima:

Codice:
                        .MODEL large, PASCAL
                        .CODE
                MiaProc PROC FAR i:WORD, j:WORD
                        PUBLIC MiaProc
                        mov     ax,i
                        ...
                        ...


Notate che non si devono specificare i parametri in ordine inverso e che alcune altre cose non servono (push bp, mov bp,sp) inoltre viene settato il ritorno al chiamante con POP BP e RETn.

Il secondo modo per accedere ai parametri (si era detto) era quello di usare un altro Base Register (BX) o un Index Register (SI o DI).
Ricordate pero che il segmento di default per questi registri è CS non SS quindi si deve fare attenzione :


Codice:
                CODE    SEGMENT
                        ASSUME cs:CODE
                MiaProc PROC FAR
                        PUBLIC MiaProc
                j       EQU WORD PTR ss:[bx+4]
                i       EQU WORD PTR ss:[bx+6]
                        mov     bx,sp
                        mov     ax,i
                        ...
                        ...


Qui sopra è mostrato come si può utilizzare il registro BX. Siccome non si deve salvare BP questo modo è più efficiente.

Ora che abbaiamo visto come il Turbo Pascal passa i parametri ad una routine Assembly , vediamo come sempre il Turbo Pascal salva i parametri di uscita ad una funzione.
Come per i parametri d'ingresso dipende dal tipo:

- Tipi scalari
Se la dimensione del dato è 1 byte lo mette in AL
Se la dimensione è 2 byte lo mette in AX
Se la dimensione è 4 byte lo mette in DX:AX (con la parte più significativa
in DX)
- Real
I 6 byte del numero reale vengono salvati in 3 registri DX BX AX con la
parte
più significativa in DX e quella meno significativa in AX.
- String
Le stringhe vengono salvate in un'area temporanea allocata dal Pascal prima
della chiamata; un puntatore di tipo FAR a quest'area viene salvato nello
stack prima del primo parametro.(Nota: questo puntatore non fa parte della
lista dei parametri).
- Pointer
I puntatori sono salvati in DX:AX (segmentffset)

L'ultimo argomento che vorrei trattare riguarda l'allocazione di memoria (sia statica che volatile) per le nostre routine Assembly.
Il Turbo Pascal permette all'Assembler di riservare spazio per le variabili statiche nel DATA SEGMENT, per allocare lo spazio si deve usare la solita direttiva DB o DW e cos? via :


Codice:
                DATA    SEGMENT PUBLIC
                MiaInt  DW  ?
                MioChar DB  ?
                ...
                ...
                DATA    ENDS
Tutto questo con 2 restrizioni : primo queste variabili sono private (non possono essere visibili dal programma Pascal), secondo non possono essere pre-inizializzate (quindi MiaInt DW 45 non causa un errore ma MiaInt non verr. inizializzata a 45 quando eseguirò il programma).
Potete comunque aggirare l'ostacolo usando la direttiva EXTRN e dichiarando le variabili nel programma Pascal.
Per quanto riguarda la memoria volatile essa viene allocata sullo stack per tutta la durata della chiamata.
Per capire come funziona non c'è niente di meglio che un bell'esempio in cui si alloca spazio per due interi a e b:


Codice:
                CODE    SEGMENT
                        ASSUME cs:CODE
                MiaProc PROC FAR
                        PUBLIC MiaProc
                        LOCAL  a:WORD, b:WORD = LocalSpace
                                                ;a va in [bp-2] e b in [bp-4]
                i       EQU WORD PTR [bp+6]     ;i sta  sopra BP e l'indirizzo
                                                ;di ritorno
                        push    bp              ;salvo BP
                        mov     bp,sp           
                        sub     sp,LocalSpace   ;crea lo spazio per le 2 word
                        mov     ax,45
                        mov     a,ax            ;a:=45
                        xor     ax,ax           ;a:=0
                        mov     b,ax            ;b:=0
                        ...
                        ...                     ;fate quello che volete fare!!
                        ...
                        mov     sp,bp           ;ripristina l'originale SP
                        pop     bp              ;recupera BP
                        ret     2               ;estrae i 2 byte di i
                MiaProc ENDP
                CODE    ENDS
                        END
L'istruzione LOCAL a:WORD, b:WORD = LocalSpace riserva [BP-2] per a e [BP-4] per b e assegna a LocalSpace il valore 4 che altro non è che la dimensione dell'area per le variabili locali della procedura.

Bene Dj spero di essere stato sufficientemente chiaro e di averti dato qualche utile tips per Interfacciare i tuoi programmi(ni) in grafica 3D con efficienti routine in assembly in modo da far ruotare quel maledetto cubo a velocità supersoniche anche su un 286... :-)))
P.S. passami qualke SunOS ke sono rimasto a secco
Saluto anke tutto la community di Questo forum visto ke il carissimo non che'
ingambissimo lordz ha fatto publicare in questo forum questa mia guida...
Ringrazio a tutti gli admin e tutti quelli che fanno parte di questo bellissimo forum arisentirci...
By DTZer0
__________________
`] BenVeNuTi ALL'InFeRNo[`

Dj`LoRdZ` non è connesso   Rispondi citando
Link Sponsorizzati
Rispondi

  • Submit Thread to Digg Digg
  • Submit Thread to del.icio.us del.icio.us
  • Submit Thread to StumbleUpon StumbleUpon
  • Submit Thread to Google Google
  • Preferiti

    Tags
    assembly , interfacciamento , pascal , tra , turbo


    Utenti attualmente attivi che stanno leggendo questa discussione: 1 (0 utenti e 1 visitatori)
     
    Strumenti discussione
    Modalità visualizzazione

    Regole di scrittura
    Non puoi inviare Nuove Discussioni
    Non puoi Rispondere
    Non puoi inserire Allegati
    Non puoi modificare i tuoi Messaggi

    BB code is Attivato
    Le faccine sono Attivato
    Il codice [IMG] è Attivato
    Il codice HTML è Attivato
    Trackbacks are Disattivato
    Pingbacks are Attivato
    Refbacks are Attivato

    Vai al forum

    Discussioni simili
    Discussione Autore discussione Forum Risposte Ultimo messaggio
    L'MSI mette il Turbo Midnight-34 News 3 07-11-2008 15.59.24
    Accelero TWIN TURBO Midnight-34 News 1 03-07-2008 13.01.02
    Pascal ---> dubbio URGENTISSIMO ombre8-8 Programmazione 2 19-05-2008 17.33.02
    HIS HD 3870 IceQ 3 Turbo Midnight-34 News 0 03-01-2008 14.40.04
    OCZ Turbo-Cool 860 Midnight-34 News 1 19-12-2007 14.23.00



    Powered by vBulletin versione 3.8.0 Beta 2
    Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.