SASM - alfredocentinaro.it https://www.alfredocentinaro.it/category/lezioni/assembler-x86/sasm/ Sito personale di Alfredo Centinaro, ingegnere informatico, insegnante, musicista. Programmazione, appunti, esercizi, sistemi e reti, tpsit, esami di stato, arduino Mon, 08 Jan 2024 23:49:13 +0000 it-IT hourly 1 https://wordpress.org/?v=6.9.4 https://www.alfredocentinaro.it/wp-content/uploads/2022/01/logo_alfredocentinaro-150x150.png SASM - alfredocentinaro.it https://www.alfredocentinaro.it/category/lezioni/assembler-x86/sasm/ 32 32 Esempio 17: media di n numeri da input con ciclo https://www.alfredocentinaro.it/lezioni/assembler-x86/sasm/esempio-17-media-di-n-numeri-da-input-con-ciclo/ Wed, 17 Feb 2021 10:35:48 +0000 https://www.alfredocentinaro.it/2021/02/17/esempio-17-media-di-n-numeri-da-input-con-ciclo/ Un altro esempio per approfondire l’utilizzo dei cicli in asm. Questa volta vediamo un altro classico problema per i programmatori in erba: la media di n numeri inseriti da tastiera con n a sua volta scelto in input dall’utente in input. Il problema in analisi è un classico per chi inizia a programmare con qualsiasi ... Leggi tutto

L'articolo Esempio 17: media di n numeri da input con ciclo proviene da alfredocentinaro.it.

]]>
Un altro esempio per approfondire l’utilizzo dei cicli in asm. Questa volta vediamo un altro classico problema per i programmatori in erba: la media di n numeri inseriti da tastiera con n a sua volta scelto in input dall’utente in input.

Il problema in analisi è un classico per chi inizia a programmare con qualsiasi linguaggio di programmazione ad alto livello. Si presta molto bene anche per approfondire asm e i cicli.

Lettura

La prima parte di lettura del numero di elementi di cui fare la somma è molto semplici per chi è arrivato a questo punto del nostro percorso. Scegliamo un registro generico qualsiasi per ricevere il numero, ad es. rax. Vi ricordo la lettura GET_DEC col parametro 4 per leggere 32bit, 8 per leggere 64bit. Se inseriamo 4 con i registri a 64bit funziona lo stesso ma utilizzeremo meno bit del registro a 64bit.

    PRINT_STRING "Inserisci quanti numeri vuoi sommare"
    GET_DEC 8,rax  ; cin >>  n 

Più interessante è ricordare sempre che i registri sono utilizzati dalla cpu per tutti gli scopi necessari al funzionamento del pc. Ancora prima dell’esecuzione del nostro programma, tali registri possono aver ospitato valori, indirizzi o altro di processi andati in esecuzione prima. Ecco perché, come con qualsiasi linguaggio di programmazione ad alto livello, bisogna sempre inizializzare i registri o le variabili ai valori utili, nella maggior parte dei casi con lo zero. Qui è da mettere zero nei registri rcx che ci servirà da contatore e rdx che ci servirà da accumulatore. Invece di usare la opCode mov registro, 0 ho usato la opCode di xor registro, registro poiché ottiene lo stesso risultato ma con meno cicli di cpu. Lo studente che non gradisce le ottimizzazioni può certamente usare l’altra modalità più intuitiva.

Ciclo

Il ciclo vero e proprio è molto semplice. Ci serve una etichetta esplicativa per contrassegnare il frammento di codice da ripetere per ogni passaggio del ciclo. Il ciclo, di fatto, è il classico do-while. Ho il contatore da incrementare, il registro rdx che accumula le somme dei numeri letti e posizionati sul registro rbx, la condizione per tornare sopra il ciclo con un salto o uscire qualora la condizione venisse meno. In questo caso dal ciclo dobbiamo uscire quando il contatore è arrivato al numero complessivo altrimenti se minore deve saltare all’inizio del ciclo e leggere un altro numero e così via. JL, jump less, è proprio la condizione while(contatore < numero){…}.

ciclo:    
    GET_DEC 8,rbx  ; cin >>  num
    inc rcx ; contatore elementi inseriti i++
    add rdx, rbx
    cmp rcx,rax 
    jl ciclo

Media

Il frammento successivo si occupa di calcolare la media con la divisione intera. Come visto nelle altre lezioni, bisogna preparare i registri rax e rdx per accogliere il dividendo e il resto rispettivamente. Mentre il divisore può essere posto in un registro qualsiasi. Il quoziente sarà poi sovrascritto in rax stesso.

    mov rax, rdx
    xor rdx, rdx
    div rcx

Il codice completo:

%include "io64.inc"

section .text
global CMAIN
CMAIN:
    mov rbp, rsp; for correct debugging
    PRINT_STRING "Inserisci quanti numeri vuoi sommare"
    GET_DEC 8,rax  ; cin >>  n   
    
    ;inizializzo/pulisco a zero i registri che mi occorrono 
    xor rcx, rcx  ; equivale a mov ecx, 0 ovvero ecx=0
    xor rdx, rdx 
    
ciclo:    
    GET_DEC 8,rbx  ; cin >>  num
    inc rcx ; contatore elementi inseriti i++
    add rdx, rbx
    cmp rcx,rax 
    jl ciclo
    
    ;preparo i registri per la divisione es. 40 / 4
    ;il 40 che stava in dx lo muovo in ax
    ;sbianco dx per il resto
    ;i lrisultato quoziente sarà ancora in ax
    mov rax, rdx
    xor rdx, rdx
    div rcx
    
    NEWLINE
    PRINT_STRING "media= "
    PRINT_DEC 4,rax
    
   
    xor rax, rax
    ret

L'articolo Esempio 17: media di n numeri da input con ciclo proviene da alfredocentinaro.it.

]]>
Asm Cheat Sheet https://www.alfredocentinaro.it/lezioni/assembler-x86/sasm/asm-cheat-sheet/ Sun, 14 Feb 2021 22:49:56 +0000 https://www.alfredocentinaro.it/2021/02/14/asm-cheat-sheet/ Un breve prontuario per gli studenti alle prime armi con assembly. E’ ideato per semplificare la vita soprattutto se si usa SASM come IDE di sviluppo. Se ti è utile, ricordati di cliccare le pubblicità per sponsorizzare questo sito. Visite: 331

L'articolo Asm Cheat Sheet proviene da alfredocentinaro.it.

]]>
Un breve prontuario per gli studenti alle prime armi con assembly. E’ ideato per semplificare la vita soprattutto se si usa SASM come IDE di sviluppo.

Se ti è utile, ricordati di cliccare le pubblicità per sponsorizzare questo sito.

L'articolo Asm Cheat Sheet proviene da alfredocentinaro.it.

]]>
Esempio 16: somma di 5 numeri in input con ciclo https://www.alfredocentinaro.it/lezioni/assembler-x86/sasm/esempio-16-somma-di-5-numeri-in-input-con-ciclo/ Mon, 10 Feb 2020 18:53:45 +0000 https://www.alfredocentinaro.it/2020/02/10/esempio-16-somma-di-5-numeri-in-input-con-ciclo/ Un altro esercizio in SASM riepilogativo con diversi elementi visti. Questa volta usiamo un ciclo per leggere in input cinque valori che poi sommiamo e stampiamo. Vediamo come. Vediamo prima il frammento di codice con SASM. In ingressi sulla parte di destra degli Input simuliamo di inserire i numeri 2, 4, 5, 3, 1 che ... Leggi tutto

L'articolo Esempio 16: somma di 5 numeri in input con ciclo proviene da alfredocentinaro.it.

]]>
Un altro esercizio in SASM riepilogativo con diversi elementi visti. Questa volta usiamo un ciclo per leggere in input cinque valori che poi sommiamo e stampiamo. Vediamo come.

Vediamo prima il frammento di codice con SASM. In ingressi sulla parte di destra degli Input simuliamo di inserire i numeri 2, 4, 5, 3, 1 che sommati danno 15, il risultato che vogliamo ottenere nella parte Output. In SASM utilizziamo l’assembly per CPU X86 a 32bit con i relativi registri eax, ebx, ecx, ecc. Discorsi analoghi se si volessero usare i registri a 64bit rax,rbx,rcx,rdx, ecc

Il codice analogo visto e commentato con EMU8086 (da completare)

L'articolo Esempio 16: somma di 5 numeri in input con ciclo proviene da alfredocentinaro.it.

]]>
Esempio 15: Il ciclo while con assembly https://www.alfredocentinaro.it/lezioni/assembler-x86/sasm/esempio-15-il-ciclo-while-con-assembly/ https://www.alfredocentinaro.it/lezioni/assembler-x86/sasm/esempio-15-il-ciclo-while-con-assembly/#respond Mon, 03 Feb 2020 09:58:54 +0000 https://www.alfredocentinaro.it/2020/02/03/esempio-15-il-ciclo-while-con-assembly/ Abbiamo visto come il costrutto if/else si traduca in assembly con una serie di salti al punto corretto di codice da eseguire in base alla condizione valutata. Il ciclo in realtà è molto simile come approccio, tanto che non esiste una parola while vera e propria ma un if else che risalta su se stesso! ... Leggi tutto

L'articolo Esempio 15: Il ciclo while con assembly proviene da alfredocentinaro.it.

]]>
Abbiamo visto come il costrutto if/else si traduca in assembly con una serie di salti al punto corretto di codice da eseguire in base alla condizione valutata. Il ciclo in realtà è molto simile come approccio, tanto che non esiste una parola while vera e propria ma un if else che risalta su se stesso! Vediamo un esempio.

Partiamo da un frammento di codice C++ più intuitivo per lo studente. Un classico ciclo while con un iteratore che fa 5 step stampando il numero di iterazione

//fai un ciclo while che conta fino a 5
int =0;
while(i<5)
{
 i++;
 cout << i <<endl;
}

 cout <<"finito!"

SASM

Il ciclo è molto semplice e non molto utile se non didatticamente: si limita a fare la stampa dei numeri 1,2,3,4,5 in pratica e della scritta “finito”. Il codice assembly è più semplice di quello che potete immaginare. Ne vediamo un esempio con SASM.

Utilizziamo il registro generico dx come contatore/variabile i. Lo inizializziamo a zero con il primo mov. Quindi mettiamo una etichetta: ci serve per delimitare il nostro ciclo while e saltare all’inizio dello stesso. A questo punto incrementiamo di 1 il registro dx, ne stamiamo l valore con la funzione preconfezionata PRINT_DEC ed eseguiamo finalmente il controllo del registro dx col valore 5 e l’istruzione cmp. A questo punto valutiamo il risultato della comparazione: se più piccolo, lower, salta jump all’inizio del ciclo dove c’è l’etichetta ciclowhile, utilizzando JumpLower, jl. Se il jl non è soddisafatto è implicito che si esce dal ciclo e si va alla stampa successiva di fine e relativo reset

%include “io.inc”

section .text
global CMAIN

CMAIN:
mov edx, 0

ciclowhile:
inc edx
PRINT_DEC 4, edx 
cmp edx, 5
jl ciclowhile 

PRINT_STRING “Finito!”

xor eax, eax
ret

EMU 8086

La versione con EMU8086 è del tutto analoga, usando le funzioni che semplificano le operazioni di stampa, ed è la seguente

includeemu8086.inc
.MODEL SMALL

.STACK
.DATA

.CODE
.STARTUP

mov ax, 0

ciclowhile:
inc ax
call PRINT_NUM
PRINTN ”

cmp ax,5
jl ciclowhile

PRINTN ‘Finito!’

;mi dichiaro delle funzioni di stampa e input
DEFINE_SCAN_NUM
DEFINE_PRINT_NUM
DEFINE_PRINT_NUM_UNS

.EXIT
END

In questo caso abbiamo usato come contatore il registro AX, che “sbianchiamo” a zero, tenendo presente che il suo contenuto viene anche stampato in automatico come parametro di default della funzione PRINT_NUM che invochiamo con la annessa andata a capo PRINTN ”. Le condizioni di salto e comparazione sono equivalenti. 

L'articolo Esempio 15: Il ciclo while con assembly proviene da alfredocentinaro.it.

]]>
https://www.alfredocentinaro.it/lezioni/assembler-x86/sasm/esempio-15-il-ciclo-while-con-assembly/feed/ 0
Esempio 14: if else in assembly https://www.alfredocentinaro.it/lezioni/assembler-x86/sasm/esempio-14-if-else-in-assembly/ Tue, 21 Jan 2020 09:18:10 +0000 https://www.alfredocentinaro.it/2020/01/21/esempio-14-if-else-in-assembly/ Vediamo più nel dettaglio il costrutto if/else in assembly e approfondiamo il concetto di “salto” Già nell’esempio 13 abbiamo visto il funzionamento dell’if, costrutto che in assembly si traduce con una costruzione inversa della condizione con l’uscita dalla if attraverso un salto di codice verso una label, una etichetta che contraddistingue una riga di codice ... Leggi tutto

L'articolo Esempio 14: if else in assembly proviene da alfredocentinaro.it.

]]>
Vediamo più nel dettaglio il costrutto if/else in assembly e approfondiamo il concetto di “salto”

Già nell’esempio 13 abbiamo visto il funzionamento dell’if, costrutto che in assembly si traduce con una costruzione inversa della condizione con l’uscita dalla if attraverso un salto di codice verso una label, una etichetta che contraddistingue una riga di codice fuori dalla condizione. L’else per certi versi rafforza questa necessita. Riprendiamo l’esempio precedente modificandolo un po’ trasformandolo in un “trova massimo tra due numeri letti in input”.

cin >>x;
cin >>y;

if (x <= y)
{
 cout<<"x più piccolo";
 //devi saltare fuori per non fare l'else
}
else
{
 cout<<"x è più grande";
}

In SASM scriviamo questo frammento:

%include “io.inc”

section .data

max dd 0

section .text

global CMAIN

CMAIN:

mov ebp, esp ;for correct debugging

GET_DEC 4, eax ;la nostra x

GET_DEC 4, edx ;la nostra y

cmp eax, edx

jg else

PRINT_STRING “x è più piccolo di y”

mov [max], edx

jmp fuoridallif ;forzo l’uscita per non eseguire il blocco else:

else: ;else è un’etichetta non una parola chiave!

PRINT_STRING “x è più grande di y”

mov [max], eax

fuoridallif:

NEWLINE

PRINT_DEC 4, max

xor eax, eax

ret

Proviamo ad analizzare frammento per frammento.

Dichiariamoci una variabile da 32 (o 64 bit) bit che chiamiamo max, dove inseriremo il risultato finale. Le prime due righe GET_DEC si occupano di leggere due numeri dalla finestra laterale di input. Scriviamoci sullo stesso rigo due numeri di esempio con uno spazio tra i due. A questo punto dobbiamo inserire un blocco condizionale, il classico if.

L’operatore if in assembly si indica con cmp, contrazione della parola “compare”, che prende due valori, ovvero per noi i registri eax, edx che contengono  le nostre x ed y, rispettivamente. Ora bisogna cercare di imporre una condizione come il <= dell’esempio in c. Come notato nella lezione/post precedente, il trucco dell’assembly è quello di imporre una condizione “inversa” ovvero se voglio controllare x<=y devo verificare x > y per imporre il salto al codice opportuno. Ed infatti con l’operatore jg, jumper greater, salta se più grande all’etichetta che abbiamo chiamato else:. Se non viene eseguito il salto, l’assembler scende al codice immediatamente sotto che corrisponde al caso “x più piccolo”, che stampa una stringa a video e mette nella variabile max il valore del registro opportuno. A questo punto dobbiamo risaltare per non eseguire il codice sotto corrispondente all’else ed andiamo col comando jmp, jump all’etichetta fuoridallif. Se dal jg siamo saltati all’etichetta else, andiamo a stampare il messaggio sotto ed aggiornare il valore della variabile max. Il codice fuori quindi dal costrutto if/else, che sia eseguito dal salto o dall’uscita dell’else, semplicemente stampa una linea vuota con NEWLINE e il contenuto della variabile max.

Lo stesso esercizio visto con EMU8086 con i registri a 16bit è del tutto analogo. Ricordiamo che la funzione per semplificare la lettura da tastiera inserisce il numero letto direttamente nel registro CX, quindi bisogna aver premura di spostare il valore in un altro registro per leggere il successivo, che altrimenti andrebbe a sovrascrivere il primo. Le funzioni per if/else sono uguali a quelle commentate precedentemente. Tenete presente che il valore max che ci mettiamo da parte nella variabile, per essere stampato, deve essere riportato nel registro AX che è il parametro di default che viene preso dalla istruzione PRINT_NUM. 

includeemu8086.inc
.MODEL SMALL

.STACK
.DATA

max dw 0

.CODE
.STARTUP

call SCAN_NUM

mov ax, cx ; AX sarà la nostra x

call SCAN_NUM

mov dx, cx ; AX sarà la nostra y

cmp ax, dx

jg else

PRINTN ‘x è più piccolo di y’

mov [max], dx

jmp fuoridallif ;forzo l’uscita per non eseguire il blocco else:

else:

PRINTN “x è più grande di y”

mov [max], ax

fuoridallif:

PRINTN ”

mov ax, max

call PRINT_NUM 

;mi dichiaro delle funzioni
DEFINE_SCAN_NUM
DEFINE_PRINT_NUM
DEFINE_PRINT_NUM_UNS

.EXIT
END

L'articolo Esempio 14: if else in assembly proviene da alfredocentinaro.it.

]]>
Esempio 12: somma di due numeri letti in input https://www.alfredocentinaro.it/lezioni/assembler-x86/asm-16bit/esempio-12-somma-di-due-numeri-letti-in-input/ Sun, 26 Nov 2017 16:47:29 +0000 https://www.alfredocentinaro.it/2017/11/26/esempio-12-somma-di-due-numeri-letti-in-input/ Vista la stampa, vediamo come si fa la fase di input da tastiera. Anche qui, c’è una combinazione fissa di valore/registro da impostare per “richiedere” alla CPU di procedere ad una operazione specifica di lettura. ; esempio 12; leggi due numeri da tastiera, fai la somma, stampa risultato .STACK .DATAaddendo1 db ?addendo2 db ?     ... Leggi tutto

L'articolo Esempio 12: somma di due numeri letti in input proviene da alfredocentinaro.it.

]]>
Vista la stampa, vediamo come si fa la fase di input da tastiera. Anche qui, c’è una combinazione fissa di valore/registro da impostare per “richiedere” alla CPU di procedere ad una operazione specifica di lettura.

; esempio 12
; leggi due numeri da tastiera, fai la somma, stampa risultato

.STACK
.DATA
addendo1 db ?
addendo2 db ?    

.CODE
.STARTUP

;attende un input
MOV AH, 08h
INT 21h ;il carattere viene salvato in AL  
SUB AL, 30h ; tolgo l’offset del carattere/numero
MOV addendo1, AL    

MOV AX,0000h ;pulisco il registro da eventuali errori: in c++ la gestisci la memoria?  

;attende un input
MOV AH, 08h
INT 21h ;il carattere viene salvato in AL   
SUB AL, 30h ; tolgo l’offset del carattere/numero
MOV addendo2, AL     

MOV AX, 0000h
MOV BL, addendo1
ADD BL, addendo2            

;stampo il carattere            
MOV AH,02h   
MOV DX,BX    ; copio il carattere in AL a DL per stamparlo
ADD DX,30h   ; aggiungo l’offset ascii per stampare il carattere equivalente numero
INT 21h

.EXIT
END

Se volessimo semplificare la notazione con le funzioni predefinite di lettura e scrittura a schermo avremmo:

include ‘emu8086.inc’

.STACK
.DATA

.CODE
.STARTUP

;somma di due numeri inseriti da tastiera
PRINTN ‘inserisci il primo numero’
call SCAN_NUM  ;scan_num restituisce la lettura dentro CX
mov ax, cx ;metto da parte dentro un registro, ad esempio cx

PRINTN ‘inserisci il secondo numero’
call SCAN_NUM
add ax, cx

PRINTN ‘il totale dei quattro numeri =’
call PRINT_NUM

;mi dichiaro delle funzioni
DEFINE_SCAN_NUM
DEFINE_PRINT_NUM
DEFINE_PRINT_NUM_UNS

.EXIT
END

La versione SASM, sempre semplificata, con registri a 32bit

L'articolo Esempio 12: somma di due numeri letti in input proviene da alfredocentinaro.it.

]]>
Esempio 03: somma di due numeri con ADD https://www.alfredocentinaro.it/lezioni/assembler-x86/asm-16bit/esempio-03-somma-di-due-numeri-con-add/ Mon, 23 Oct 2017 16:05:02 +0000 https://www.alfredocentinaro.it/2017/10/23/esempio-03-somma-di-due-numeri-con-add/ Un semplice esempio per capire come si esegue la somma di due numeri. L’esempio aiuta a capire l’opCode ADD ma anche come l’assembly ragioni a basso livello tra assegnazione e somma. Usiamo le variabili per dichiarare i due numeri e quindi procediamo con i registri per svolgere la funzione. Un esempio concreto di quanto i ... Leggi tutto

L'articolo Esempio 03: somma di due numeri con ADD proviene da alfredocentinaro.it.

]]>
Un semplice esempio per capire come si esegue la somma di due numeri. L’esempio aiuta a capire l’opCode ADD ma anche come l’assembly ragioni a basso livello tra assegnazione e somma.

Usiamo le variabili per dichiarare i due numeri e quindi procediamo con i registri per svolgere la funzione. Un esempio concreto di quanto i linguaggi a basso livello siano “scomodi” per effettuare operazioni che con linguaggi ad alto livello faremmo in una sola riga di codice. Qui dobbiamo ricordarci di aggiungere la sezione .STACK per consentire la inizializzazione delle variabili.

; esempio 03
; somma   9 + 1
.MODEL small ;non rimuovere
.DATA
    ADDENDO1  dw 9D
    ADDENDO2  dw 1D
    SOMMA       dw ?    

.CODE
.STARTUP

MOV BX, ADDENDO1    ; sposto il primo numero in Bx parte bassa
ADD BX, ADDENDO2    ; ci sommo il secondo numero
MOV SOMMA, BX         ; sposto nella variabile

.EXIT
END

Lo stesso esempio con SASM è riportato nella seguente schermata. Apriamo la finestra “Lancia debugger”->”Visualizza memoria”. Digitiamo a mano il nome delle variabili che vogliamo monitorare. I valori li abbiamo inseriti in esadecimale, mentre il valore indefinito ? non è ufficialmente supportato. Come si può vedere i valori gestiti attraverso le variabili possono essere passati solo mediante il loro indirizzo [var], che è teoricamente più corretto del concetto di variabile in FASM. Non esistono variabili, ma solo porzioni di memoria dedicate a contenere valori, mentre il valore fisico è gestito solo ed unicamente dai registri.

frammento di codice asm

L'articolo Esempio 03: somma di due numeri con ADD proviene da alfredocentinaro.it.

]]>
Esempio 01: le variabili https://www.alfredocentinaro.it/lezioni/assembler-x86/sasm/esempio-01-le-variabili/ Mon, 23 Oct 2017 15:31:23 +0000 https://www.alfredocentinaro.it/2017/10/23/esempio-01-le-variabili/ Un altro semplice esempio in cui dichiariamo una variabile con un valore iniziale per spostarla quindi in un registro dove potremo usarla. In assembly le operazioni devono essere eseguite esclusivamente attraverso i registri! Prima di tutto, per gestire le variabili, dobbiamo riservarci uno spazio di memoria. In assembly, le variabili altro non sono infatti che ... Leggi tutto

L'articolo Esempio 01: le variabili proviene da alfredocentinaro.it.

]]>
Un altro semplice esempio in cui dichiariamo una variabile con un valore iniziale per spostarla quindi in un registro dove potremo usarla. In assembly le operazioni devono essere eseguite esclusivamente attraverso i registri!

Prima di tutto, per gestire le variabili, dobbiamo riservarci uno spazio di memoria. In assembly, le variabili altro non sono infatti che ridenominazione di spazi di memoria raggiungibili col proprio nome o l’indirizzo. Questo è facilmente fattibile all’interno della sezione .data dove vengono dichiarate le variabili inizializzate e per le quali è necessario specificare quanto spazio occupano ma non il tipo:

db -> 8 bit (1 byte)

dw-> 16 bit (1 word)

dd->  32 bit (1 doubleword se supportato dall’architettura)

dq-> 64 bit (1 quadword, ovvero 2 doubleword se supportato dall’architettura)

Nel seguente  codice un esempio di utilizzo e dichiarazione.

; esempio 01
; scrive un valore in memoria 5
; lo trasferisce in DX

.MODEL small
.STACK 256
.DATA
    VARIABILE DW ?

; le variabili sono dichiarate con
; NOMEVAR DIMESINONEVAR VALOREINIZIALE    
; NOMEVAR è a scelta
; DIMENSIONEVAR può essere DB o DW B->Byte->8 bit  W->Word->2Byte->16 bit
; VALOREINIZIALE può essere un numero decimale es. 29
;         o esadecimale es. 2Bh o 0Ah
;         o binario es. 11101010b       

.CODE
.STARTUP

MOV VARIABILE, 5D
MOV DX, VARIABILE

.EXIT
END

;

Lo stesso esercizio in SASM, ragionando a 32bit. Qui per motivi tecnologici e di sintassi, non possiamo definire una variabile ? ma dobbiamo assegnare un valore iniziale, zero ad esempio.

L’esercizio è arrichito dai comandi per prendere in ingresso una valore e stampare il risultato nelle apposite finestrelle previste dall’IDE.

 %include “io.inc”

; ris= x+2y-3z con x,y,z assegnati
 

section .data

x dd 0
y dd 11110000b
z dd 0Ah
 

; ris = 126 + 2(11110000b) – 3(0Ah)
ris dd 0

section .text
global CMAIN

CMAIN:

mov ebp, esp ; for correct debugging
;write your code here
 
GET_DEC 4, x

mov edx, [x]
add edx, [y]
add edx, [y]

sub edx, [z]
sub edx, [z]
sub edx, [z]
 
mov [ris], edx
PRINT_DEC 4, ris

xor eax, eax
ret

L'articolo Esempio 01: le variabili proviene da alfredocentinaro.it.

]]>
Scrivere il primo programma assembly https://www.alfredocentinaro.it/lezioni/assembler-x86/sasm/scrivere-il-primo-programma-assembly/ https://www.alfredocentinaro.it/lezioni/assembler-x86/sasm/scrivere-il-primo-programma-assembly/#respond Sat, 21 Oct 2017 20:34:57 +0000 https://www.alfredocentinaro.it/2017/10/21/scrivere-il-primo-programma-assembly/ Scrivere un programmino assembly è molto semplice, come detto basterebbe un semplice editor di testo con cui salvare i file. E’ un linguaggio non case sensitive, ovvero che si scriva in stampatello o minuscolo è indifferente. I file che prepariamo possono anche non avere estensione o una testuale qualsiasi, ma per coerenza e visibilità migliore ... Leggi tutto

L'articolo Scrivere il primo programma assembly proviene da alfredocentinaro.it.

]]>
Scrivere un programmino assembly è molto semplice, come detto basterebbe un semplice editor di testo con cui salvare i file.

E’ un linguaggio non case sensitive, ovvero che si scriva in stampatello o minuscolo è indifferente. I file che prepariamo possono anche non avere estensione o una testuale qualsiasi, ma per coerenza e visibilità migliore li nominiamo con estensione .asm, ovvero ad esempio “mioprogramminoesempio.asm”. Per quanto riguarda la notazione, esistono due tipi di notazione assembly. Quella di seguito è detta  compatta ed è preferibile, a nostra opinione, poiché con delle istruzioni in pseudo-codice o pseudo-operazioni si risparmiano alcuni passaggi necessari alla preparazione dell’ambiente di esecuzione e l’uscita ed arresto dello stesso. Il codice, si faccia attenzione, è testato sul emulatore EMU8086 e SAMS. Altri emulatori/assemblatori potrebbero richiedere altre notazioni. Online ci sono anche svariati IDE x86 ma non hanno perfetta compatibilità e richiederebbero altre considerazioni che vogliamo semplificare usando le istruzioni x8086 in quella che viene detto “Intel Code”, che si distingue dalla versione AT & T. Vediamo una ossatura di ogni nostro esercizio e, di seguito, una spiegazione delle singole voci.

Versione con IDE EMU8086 e assembler FASM

; titolo
; descrizione
.MODEL SMALL

.STACK

.DATA

.CODE
.STARTUP

.EXIT
END  

Commenti

Come in ogni linguaggio che si rispetti esistono porzioni di codice ignorabili dal compilatore ma che servono a noi umani a meglio comprendere quello che scriviamo. Come in C/C++ si commenta codice o testo utile con // o /* */, in assembly si usa ; (punto e virgola) per commenatre una singola riga. Contrariamente al C, la terminazione di una riga istruzione non necessita di ; se non appunto per inserire un commento. In genere in EMU8086 sono colorati di verde proprio per differenziare dal codice eseguibile nero, blu e rosso.

Pseudoistruzione  .MODEL SMALL

Indica al compilatore il modello di memoria da usare. Un po’ come dire “quanta memoria serve per il programma”. Suona strano ma small è per memorie di 64KByte, Medium fino ad 1 MByte tantissimo per l’epoca mentre oggi fa ridere! A seconda del modello, ci sono delle limitazioni sui registri e le loro applicazioni ma esulano un po’ dai nostri obiettivi e si rimanda quindi ad una spiegazione più dettagliata qui. E’ opzionale per i nostri esercizi dove non inseriamo variabili, ma tanto vale dichiararlo sempre.

Area dello Stack .STACK

E’ una zona tipicamente gestita dal compilatore ed in genere non è accessibile direttamente dal programmatore tranne che con l’assembly con particolari istruzioni. Contiene in genere le locazioni di memoria per le variabili globali ed altri parametri che hanno a che fare con procedure, funzioni, indirizzi di variabili a puntatore. E’ opzionale per i nostri esercizi a meno che non ci siano variabili dichiarate. Conviene inserirlo sempre, eventualmente aggiungendo la dimensione da riservare es. .STACK 256 o .STACK 100h

Area Dati .DATA

E’ un’area di memoria sia di lettura che di scrittura a differenza delle altre, e contiene le variabili globali che possono essere usate dal programma durante il suo ciclo. Il programmatore alloca staticamente una certa quantità di memoria per contenere svariati tipi di dato, una sorta di contenitore universale in pratica. E’ opzionale per i nostri esercizi a meno che non ci siano variabili dichiarate. Conviene inserirlo sempre.

Area Codice .CODE

E’ la parte dove inserire le istruzioni da eseguire durante l’esecuzione del programma ovvero a runtime.

Pseudoistruzione .STARTUP

E’ una semplificazione che nasconde sotto una serie di istruzioni che preparano il software ad essere eseguito:

mov ax, @data

mov ds, ax

mov es, ax

Evitiamo di commentarle, sono fisse, andrebbero sempre inserite a patto di contrarle appunto con la notazione .STARTUP

Pseudoistruzione .EXIT

Non è un mistero, come .STARTUP cela una contrazione delle operazioni fisse:

mov ax, 4c00h

int 21h

che chiudono il software e ritornano il controllo al sistema operativo.

 Versione con IDE EMU8086 e assembler FASM semplificto

Esiste anche la possibilità di non utilizzare la suddivisione in “aree” e utilizzare un template estremamente ridotto:

;titolo
;descrizione
org 100h

ret

dove viene semplificata l’area “di stack” con l’istruzione org 100h e l’uscita dal programma semplificata con l’istruzione ret finale.

 Versione SAMS con assembler NASM

 

SAMS semplifica un po’ la vita del programmatore. Prima di tutto supporta i registri a 32bit, dando un tocco di modernità e parte già utilizzandoli nel suo template di apertura che è il seguente.

%include “io.inc”

section .text

global CMAIN

CMAIN:

;write your code here

 

xor eax, eax

ret

 

La prima riga è la piccola perla di questo IDE: ha già una piccola libreria con le funzioni di input/output preconfezionate. Come scoprirà il lettore, tali funzioni sono alquanto noiose da ricordare e necessitano di diverse istruzioni. Il resto ha ancora le sezioni ma vedete la differenza con la dicitura section, mentre il .code e . startup son o rimpiazzati da global CMAIN. Anche l’uscita .exit end è rimpiazzata dal ret con una pulizia preventiva del registro accumulatore eax, già in formato 32bit.

L'articolo Scrivere il primo programma assembly proviene da alfredocentinaro.it.

]]>
https://www.alfredocentinaro.it/lezioni/assembler-x86/sasm/scrivere-il-primo-programma-assembly/feed/ 0