trucchi-com

tutti i trucchi che nessuno sà

 

AREA PERSONALE

 

TAG

 

ARCHIVIO MESSAGGI

 
 << Novembre 2024 >> 
 
LuMaMeGiVeSaDo
 
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30  
 
 

FACEBOOK

 
 

CONTATTA L'AUTORE

Nickname: romoletto640
Se copi, violi le regole della Community Sesso: M
Età: 60
Prov: EE
 

 

INTRODUZIONE ALLA PROGRAMMAZIONE

Post n°18 pubblicato il 03 Giugno 2007 da romoletto640
 

Per molto tempo si pensò che il termine algoritmo derivasse da una storpiatura del termine logaritmo. L’opinione attualmente diffusa è invece che il termine derivi da al-Khuwarizmi, nome derivante a sua volta dal luogo di origine di un matematico arabo, autore di un libro di aritmetica e di uno di algebra: nel libro di aritmetica si parla della cosiddetta numerazione araba (quella attualmente usata) e si descrivono i procedimenti per l’esecuzione delle operazioni dell’aritmetica elementare. Questi procedimenti vennero in seguito chiamati algoritmi e il termine passò ad indicare genericamente qualunque procedimento di calcolo.

L’algoritmo esprime le azioni da svolgere su determinati oggetti al fine di produrre gli effetti attesi. Una azione che produce un determinato effetto è chiamata istruzione e gli oggetti su cui agiscono le istruzioni possono essere costanti (valori che restano sempre uguali nelle diverse esecuzioni dell’algoritmo) e variabili (contenitori di valori che variano ad ogni esecuzione dell’algoritmo). Si potrà dire brevemente che un algoritmo è una elaborazione di dati: i dati, cioè l’insieme delle informazioni che devono essere elaborate, sono manipolati, secondo le modalità descritte dalle istruzioni, per produrre altri dati. Ciò porta l’algoritmo ad essere una funzione di trasformazione dei dati di un insieme A (dati di input) in dati di un insieme B (dati di output).

In questi appunti, dato che ci si pone il fine di una introduzione alla programmazione, più che una definizione rigorosa di algoritmo se ne fornirà una definizione intuitiva. In questo senso si può definire l’algoritmo come “.. un insieme di istruzioni che definiscono una sequenza di operazioni mediante le quali si risolvono tutti i problemi di una determinata classe”.

Per chiarire meglio il concetto di algoritmo è bene fare riferimento ad alcune proprietà che un insieme di istruzioni deve possedere affinché possa chiamarsi algoritmo:

  • La finitezza. Il numero di istruzioni che fanno parte di un algoritmo è finito. Le operazioni definite in esso vengono eseguite un numero finito di volte.

  • Il determinismo. Le istruzioni presenti in un algoritmo devono essere definite senza ambiguità. Un algoritmo eseguito più volte e da diversi esecutori, a parità di premesse, deve giungere a medesimi risultati. L’effetto prodotto dalle azioni descritte nell’algoritmo non deve dipendere dall’esecutore o dal tempo.

  • La realizzabilità pratica. Tutte le azioni descritte devono essere eseguibili con i mezzi di cui si dispone.

  • La generalità. Proprietà già messa in evidenza nella definizione che si è data: un algoritmo si occupa della risoluzione di famiglie di problemi.

 

Tipi di istruzioni

Per quanto osservato nell’ultima proprietà espressa, gli algoritmi operano principalmente su variabili che conterranno i dati sui quali si vuole svolgere una determinata elaborazione. I valori da elaborare devono essere assegnati alle variabili prima di effettuare l’elaborazione. Si pensi infatti ad una variabile come ad un contenitore. Le istruzioni operano sui valori contenuti: se questi non ci sono non ci si può attendere alcuna elaborazione. Ogni variabile è identificata da un nome che permette di distinguerla dalle altre:

  • L’istruzione di assegnamento fa in modo che un determinato valore sia conservato in una variabile. In questo modo si prepara la variabile per l’elaborazione o si conserva nella variabile un valore intermedio prodotto da una elaborazione precedente. Si può assegnare ad una variabile un valore costante come anche il valore risultante da una espressione aritmetica.

  • L’istruzione di input fa in modo che l’algoritmo riceva dall’esterno un valore da assegnare ad una variabile. Nel caso di algoritmi eseguiti da un elaboratore, questi attende che da una unità di input (per esempio la tastiera) arrivi una sequenza di caratteri tipicamente terminanti con la pressione del tasto <Invio>. Il dato verrà assegnato alla variabile appositamente predisposta. Praticamente si tratta di una istruzione di assegnamento solo che stavolta il valore da assegnare proviene dall’esterno.

  • L’istruzione di output fa in modo che l’algoritmo comunichi all’esterno i risultati della propria elaborazione. Nel caso di un elaboratore viene inviato su una unità di output (per esempio il video) il valore contenuto in una determinata variabile.

Esaminiamo adesso due versioni di un algoritmo per il calcolo dell’area di un rettangolo (i nomi delle variabili sono scritti in maiuscolo):

 

Algoritmo A

Algoritmo B



Assegna a BASE il valore 3

Ricevi BASE

Assegna a ALTEZZA il valore 7

Ricevi ALTEZZA

Assegna a AREA valore BASE*ALTEZZA

Assegna a AREA valore BASE*ALTEZZA

Comunica AREA

Comunica AREA

Nell’algoritmo A si assegnano alle variabili BASE ed ALTEZZA dei valori costanti, l’algoritmo calcola l’area di un rettangolo particolare e se si vuole applicare l’algoritmo ad un diverso rettangolo è necessario modificare le due istruzioni di assegnamento a BASE e ALTEZZA: l’algoritmo ha perso la sua caratteristica di generalità. Questo esempio non deve portare a concludere che non ha senso parlare di costanti in un algoritmo perché, per esempio, se si fosse trattato di un triangolo il calcolo dell’area avrebbe assunto l’aspetto: Assegna a AREA valore BASE*ALTEZZA/2. La costante 2 prescinde dai valori diversi che possono essere assegnati a BASE e ALTEZZA, essendo parte della formula del calcolo dell’area di un triangolo qualsiasi.

Nell’algoritmo B i valori da assegnare a BASE e ALTEZZA provengono da una unità di input. L’algoritmo ad ogni esecuzione si fermerà in attesa di tali valori e il calcolo verrà eseguito su tali valori: l’elaborazione è sempre la stessa (l’area di un rettangolo si calcola sempre allo stesso modo) ma i dati saranno di volta in volta diversi (i rettangoli hanno dimensioni diverse).

 

Le strutture di controllo

Gli algoritmi, a causa della loro generalità, lavorano utilizzando variabili. Non si conoscono, al momento della stesura dell’algoritmo stesso, i valori che possono assumere le variabili. Ciò se permette di scrivere algoritmi generali può comportare problemi per alcune istruzioni: si pensi al problema apparentemente banale del calcolo del quoziente di due numeri:

	Ricevi DIVIDENDO

Ricevi DIVISORE
Assegna a QUOZIENTE valore DIVIDENDO/DIVISORE
Comunica QUOZIENTE

Il quoziente può essere calcolato se DIVISORE contiene un valore diverso da 0, evento questo non noto in questo momento dipendendo tale valore dal numero proveniente da input. Inoltre è chiaro che, in questa eventualità, sarebbe priva di senso anche l’istruzione di output del valore di QUOZIENTE non essendoci nella variabile alcun valore.

È necessario introdurre, oltre alle istruzioni, degli strumenti che permettano di controllare l’esecuzione dell’algoritmo: le strutture di controllo. La programmazione strutturata (disciplina nata alla fine degli anni 60 per stabilire le regole per la scrittura di buoni algoritmi) impone l’uso di tre sole regole di composizione degli algoritmi:

la sequenza

È l’unica struttura di composizione che si è utilizzata finora. In poche parole questa struttura permette di specificare l’ordine con cui le istruzioni si susseguono: ogni istruzione produce un risultato perché inserita in un contesto che è quello determinato dalle istruzioni che la precedono. Nell’esempio di prima il calcolo di QUOZIENTE, per poter contenere il valore atteso, deve essere eseguito dopo gli input.

la selezione

Questa struttura permette di scegliere tra due alternative la sequenza di esecuzione. È la struttura che ci permette, per esempio, di risolvere in modo completo il problema del calcolo del quoziente fra due numeri:



Ricevi DIVIDENDO
Ricevi DIVISORE
Se DIVISORE <> 0
Assegna a QUOZIENTE valore DIVIDENDO/DIVISORE
Comunica QUOZIENTE
Altrimenti
Comunica ‘Operazione senza senso’
Fine-se

La condizione espressa nella struttura Se permette di scegliere, in relazione al valore di verità o falsità, quale elaborazione svolgere. La sequenza contenuta nella parte Altrimenti potrebbe mancare se si volesse soltanto un risultato laddove possibile: in tale caso se la condizione DIVISORE ? 0 risultasse non verificata, non si effettuerebbe alcuna elaborazione.


l’iterazione

La struttura iterativa permette di ripetere più volte la stessa sequenza di istruzioni finché non si verifica una determinata condizione. Si voglia, a titolo di esempio, scrivere un algoritmo che calcoli e visualizzi i quadrati di una serie di numeri positivi. Si tratta in altri termini di effettuare la stessa elaborazione (calcolo e visualizzazione del quadrato di un numero) effettuata su numeri diversi (quelli che arriveranno dall’input):



Ricevi NUMERO
Mentre NUMERO > 0
Assegna a QUADRATO valore NUMERO*NUMERO
Comunica QUADRATO
Ricevi NUMERO
Fine-mentre

Dentro la struttura iterativa (la parte compresa fra le parole Mentre e Fine-mentre) sono specificate le istruzioni per il calcolo del quadrato di un numero: l’iterazione permette di ripetere tale calcolo per tutti i numeri che verranno acquisiti tramite l’istruzione di input inserita nell’iterazione stessa. La condizione NUMERO>0 viene chiamata condizione di controllo del ciclo e specifica quando deve terminare l’elaborazione (il valore introdotto da input è non positivo): si ricorda che l’algoritmo deve essere finito e non si può iterare all’infinito. Il primo input fuori ciclo ha lo scopo di permettere l’impostazione della condizione di controllo sul ciclo stesso e stabilire, quindi, quando terminare le iterazioni.

In generale si può dire che la struttura di una elaborazione ciclica, controllata dal verificarsi di una condizione, assume il seguente aspetto:



Considera primo elemento
Mentre elementi non finiti
Elabora elemento
Considera prossimo elemento
Fine mentre

Le strutture di controllo devono essere pensate come schemi di composizione: una sequenza può contenere una iterazione che, a sua volta, contiene una selezione ecc.. Rappresentano in pratica i mattoncini elementari di una scatola di montaggio le cui diverse combinazioni permettono la costruzione di architetture di varia complessità.

Accumulatori e contatori

L’elaborazione ciclica è spesso utilizzata per l’aggiornamento di totalizzatori o contatori. Per chiarire meglio il concetto di totalizzatore, si pensi alle azioni eseguite dal cassiere di un supermercato quando si presenta un cliente con il proprio carrello pieno di merce. Il cassiere effettua una elaborazione ciclica sulla merce acquistata: ogni oggetto viene esaminato per acquisirne il prezzo. Lo scopo della elaborazione è quello di cumulare i prezzi dei prodotti acquistati per stabilire il totale che il cliente dovrà corrispondere.

Dal punto di vista informatico si tratta di utilizzare una variabile (nell’esempio potrebbe essere rappresentata dal totalizzatore di cassa) che viene aggiornata per ogni prezzo acquisito: ogni nuovo prezzo acquisito non deve sostituire il precedente ma aggiungersi ai prezzi già acquisiti precedentemente. Tale variabile:

  1. dovrà essere azzerata quando si passa ad un nuovo cliente (ogni cliente dovrà corrispondere solamente il prezzo dei prodotti che lui acquista)

  2. si aggiornerà per ogni prodotto esaminato (ogni nuovo prezzo acquisito verrà cumulato ai precedenti)

  3. finito l’esame dei prodotti acquistati la variabile conterrà il valore totale da corrispondere.

La variabile di cui si parla nell’esempio è quella che, nel linguaggio della programmazione, viene definita un totalizzatore o accumulatore: cioè una variabile nella quale ogni nuovo valore non sostituisce ma si accumula a quelli già presenti in precedenza. Se la variabile si aggiorna sempre di una quantità costante (per esempio viene sempre aggiunta l’unità) viene chiamata contatore.

In generale si può dire che l’uso di un totalizzatore prevede i seguenti passi:

	Inizializzazione totalizzatore 

Inizio ciclo aggiornamento totalizzatore
...
Aggiornamento totalizzatore
Fine ciclo
Uso del totalizzatore

L’inizializzazione serve sia a dare senso all’istruzione di aggiornamento (cosa significherebbe la frase: aggiorna il valore esistente con il nuovo valore se non ci fosse un valore esistente ?), sia a fare in modo che l’accumulatore stesso contenga un valore coerente con l’elaborazione da svolgere (nell’esempio di prima il nuovo cliente non può pagare prodotti acquistati dal cliente precedente: il totalizzatore deve essere azzerato, prima di cominciare l’elaborazione, affinché contenga un valore che rispecchi esattamente tutto ciò che è stato acquistato dal cliente esaminato).

L’aggiornamento viene effettuato all’interno di un ciclo. Se infatti si riflette sulla definizione stessa di totalizzatore, è facile prendere atto che avrebbe poco significato fuori da un ciclo: come si può cumulare valori se non si hanno una serie di valori ?

Quando i valori da esaminare terminano, il totalizzatore conterrà il valore cercato. Nell’esempio di prima tutto ciò si tradurrebbe: finito l’esame dei prodotti acquistati, si potrà presentare al cliente il totale da corrispondere.

Si voglia, a titolo di esempio di utilizzo di un accumulatore, risolvere il seguente problema: data una sequenza di numeri positivi, se ne vuole calcolare la somma.



Inizializza SOMMA con valore 0
Ricevi NUMERO
Mentre NUMERO > 0
Aggiorna SOMMA sommando NUMERO
Ricevi NUMERO
Fine-mentre
Comunica SOMMA

Il totalizzatore SOMMA è inizializzato, prima del ciclo, al valore nullo poiché deve rispecchiare la somma dei numeri introdotti da input e, quindi, non essendo ancora stata effettuata alcuna elaborazione su alcun numero tale situazione viene espressa assegnando il valore neutro della somma.

L’output di SOMMA alla fine del ciclo indica il fatto che si può utilizzare (in questo caso per la conoscenza del valore contenuto) il totalizzatore quando il suo contenuto è coerente con il motivo della sua esistenza: SOMMA deve accumulare tutti i valori e ciò avverrà quando tutti i numeri da considerare saranno stati elaborati, cioè in uscita dal ciclo.

 
 
 

assembler per principianti

Post n°17 pubblicato il 02 Giugno 2007 da romoletto640
 

Esempi

N. 1

;98-10.ASM

.model small

.stack 100h

.DATA

.CODE

main:

MOV AX,@DATA

MOV DS,AX

MOV AX,0 ;0000

MOV AH,12D ;0C00

MOV AL,12H ;0C12

MOV AL,0H ;0C00 0h = 00h

MOV AL,12H ;0C12

MOV AL,0b ;0C00 0b = 0h

MOV AH,4Ch

INT 21h

end main

END.

N. 2

;exam2.asm

;02/10/2001

;shows * on the computer screen

.model small

.stack

.code

mov ah,2h ;moves the value 2h to register ah

mov dl,2ah ;moves the value 2ah to register dl

mov cx,10

ciclo:

int 21h ;21h interruption

loop ciclo

mov ah,4ch ;4ch function, goes to operating system

int 21h ;21h interruption

END ;finishes the program code

N.3

;led1

;programma che accende 8 led in successione collegati in output alla porta ;parallela

.model small

.stack 100h

.DATA

.CODE

MOV AX,@DATA

MOV DS,AX

mov dx,378h ; indirizzo della porta parallela

mov al,00000001b ; inizia dal primo led acceso

mov cx,0ffffh ; conta il numero di cicli

ripeti: out dx,al ; output

mov bx,0 ; ritardo

inic1: mov ah,200

inic2: dec ah

jnz inic2

dec bx

jnz inic1

rol al,1 ; prepara il prossimo output

loop ripeti

MOV AH,4Ch

INT 21h

END

N. 4

 

;98-10.ASM

.model small

.stack 100h

.DATA

.CODE

main:

MOV AX,@DATA

MOV DS,AX

mov ax,0ffffh

add ax,0001h

mov ax,0001h

sub ax,0003h

mov ax,0ffffh

add ax,0ffffh

mov ax,0002h

sub ax,0002h

mov ah,00h

sub ah,02h

mov ah,20h

sub ah,20h

mov ah,00h

add ah,0ffh

mov ah,00h

add ah,11h

add al,04h

MOV AH,4Ch

INT 21h

end main

END.

 

N. 5

;exam2.asm

;02/10/2001

;stampa un quadrato di asterischi 10*10

.model small

.stack

.code

mov ah,2h ;moves the value 2h to register ah

mov dl,2ah ;moves the value 2ah to register dl

mov cx,10 ;assigned loop value

lab1:

int 21h ;21h interruption

mov dl,32

int 21h

mov dl,2ah

loop lab1 ;loop

mov dl,10

int 21h

mov dl,13

int 21h

mov cx,8

lab3:

mov dl,2ah

int 21h

mov dl,32

int 21h

mov dl,2ah

mov bx,cx

mov cx,16

lab4:

mov dl,32

int 21h

loop lab4

mov cx,bx

mov dl,2ah

int 21h

mov dl,10

int 21h

mov dl,13

int 21h

loop lab3

mov dl,2ah

mov cx,10

lab2:

int 21h

mov dl,32

int 21h

mov dl,2ah

loop lab2

mov ah,4ch ;4ch function, goes to operating system

int 21h ;21h interruption

END ;finishes the program code

N. 6

;stampa stringa colorata e di dimensione superiore (forse)

.model small

.stack 100h

.DATA

stringa db 'sistemi$'

.CODE

;-----------------------------------------------------

inizio:

MOV AX,@DATA

MOV DS,AX

ret

;-----------------------------------------------------

fine:

MOV AH,4Ch

INT 21h

ret

;-----------------------------------------------------

stampacol:

mov bh,0

mov bl,2

int 10h

mov ah,09

lea dx,stringa

int 21h

ret

;-----------------------------------------------------

;stampadim:

;ret

;-----------------------------------------------------

main:

call inizio

call stampacol

; call stampadim

call fine

end main

END.

 

 

N. 7

 

.model small

.stack 100h

.DATA

.CODE

MOV ah,02h

mov dl,2ah

mov bh,0 ; controllo numero asterischi

riga:

inc bh ; stabilisce quanti asterischi devono essere stampati sulla riga corrente

mov bl,0

aster:

int 21h ; stampa un asterisco

inc bl

cmp bl,bh ; termina quando sono stati stampati bh asterischi

jne aster

mov dl,10

int 21h

mov dl,13

int 21h

mov dl,2ah

cmp bh,5

jne riga ; stampa un'altra riga

MOV AH,4Ch

INT 21h

END

t_asterischi.asm
stringacolore.asm
quadrato di asterischi.asm
prova.asm
led.asm
Asterischi
da http://megarchivio.cjb.net

 
 
 

assembler per principianti

Post n°16 pubblicato il 02 Giugno 2007 da romoletto640
 

Cap. 7 Un esempio

A proposito di utility, che ne dite di un esempio di programmino in assembler che può anche tornare utile in qualche modo? Dunque partiamo:

Vi piacerebbe un programma di pochi bytes che vi da' la data del giorno di Pasqua per l'anno che voi desiderate?. Ci proviamo?. OK, let's go.

Org 0100 ;Istruzione per il compilatore è un .COM

Jmp start ; salta a start

Ag DB ? ;variabile ag con valore indefinito tipo byte

Bg DB ?

Cg DB ?

Hg DB ?

Dg DB ?

Fg DB ?

Kg DB ?

Eg DB ?

Gg DB ?

Mg DB ?

Anno DW ? ;variabile di tipo word

Nocom DB 'Inserire un anno per calcolare la data di Pasqua$'

Noanno DB 'Inserire un anno a 4 cifre (es. 1998)!$'

Messaggio DB 'Il giorno di Pasqua cade il: '

Giorno DB '00/'

Mese DB '00$'

Start:

mov al,[080]; ;all'indirizzo 80 la lunghezza del comando.

cmp al,5 ; se è diverso da 5, non abbiamo inserito la data

jz ok

mov dx, offset Noanno ;punta alla stringa di errore

mov ah, 9 ;per il DOS 9 in ah significa stampa

int 33 ;chiama il DOS

mov ax, 04c00 ;per il DOS 04c in ah significa esci dal progr.

int 33 ;chiama il DOS

 

Ok: ;questa è l'etichetta a cui saltare

xor bx, bx ;azzera bx

xor ah, ah ;ed anche ah

mov cx, 1000

mov al, [082] ;in al la cifra dei millenni (1 nel nostro caso)

sub al, 48 ;convertila nell'intervallo 0-9

mul cx ;moltiplica per cx

mov bx, ax ;e spostala in bx

xor ah, ah ;azzera di nuovo ah

mov al, [083] ;leggi le centinaia

sub al, 48 ;convertila

mov cx, 100 ;moltiplicatore in cx

mul cx ;esegui la moltiplicazione

add bx, ax ; ed aggiungila alle migliaia

xor ah, ah ; ripeti tutto per le decine

mov cx, 10

mov al, [084]

sub al, 48

mul cx

add bx, ax

mov al, [085]

sub al, 48

xor ah, ah

add ax, bx ;il risultato finale in ax

mov anno, ax ;salvalo in anno

;ora eseguiamo il calcolo vero e proprio

mov dx, 0

mov cx, 19

div cx ;anno /19 quoziente in ax e resto in dx

mov ag, dl

mov dx, 0

mov ax, anno

mov cx, 4

div cx ;anno/4 come sopra

mov bg, dl

mov ax, anno

mov dx, 0

mov cx, 7 ;anno/7

div cx

mov cg, dl

mov al, ag ;hg=19*ag+24

mov ah, 0

mov cl, 19

mul cl

add ax, 24

mov hg, al

mov dx, 0 ;dg=hg mod 30

mov cx, 30

div cx

mov dg, dl

mov al, bg ;kg=5+2*bg+4*cg+6*dg

add al, al

add al, 5

mov bl, al

mov al, cg

mov ah,0

mov cl, 4

mul cl

add bl, al

mov al, dg

mov cl, 6

mul cl

add bl, al

mov kg, bl

mov al, bl ;eg=kg mod 7

mov ah, 0

mov cl, 7

mul cl

mov eg, ah

mov bl, dg ;mg=dg+eg

add ah, bl

mov mg, ah

cmp ah, 9 ;se mg>9 allora vai a L1

ja L1

mov al, 22

mov ah, mg

sub al, ah

mov giorno, al

mov mese, 3 ;marzo

jmp fine

L1:

mov al, mg

sub al, 9

mov fg, al

cmp al, 26

jne L2

mov giorno, 19

move mese, 4 ;aprile

jmp fine

L2:

mov al, fg

cmp al, 25

jne L5

mov ah, dg

cmp ah, 28

je L3

mov giorno, al

mov mese, 4

jmp fine

L3:

mov giorno, 18

mov mese, 4

jmp fine

L5:

mov al, fg

mov giorno, al

mov mese, 4

Fine:

mov bx, offset giorno ;trasforma i numeri in caratteri

mov ah, 0

mov al, gg

mov dx, 0

mov cx, 10

div cx

add dl, 48

add al, 48

mov [bx], al

inc bx

mov [bx], dl

mov bx offset mese

mov al, mese

mov ah, 0

mov dx, 0

mov cx, 0

div cx

add dl, 48

add al, 48

mov [bx], al

inc bx

mov [bx], dl

mov dx, offset messaggio

mov ah, 9

Int 33

Exit:

mov ax, 04c00

int 33

Fine del listato.

Come potete vedere in assembler è molto più complicato e lungo scrivere dei programmi, anche piccoli, per questo ho detto subito che serve per piccole routine dove occorre il controllo sulle operazioni da fare oppure una grande velocità, he si perché in assembler l'esecuzione del programma è velocissima, oserei dire che questo programmino viene eseguito quasi istantaneamente (BOOOOM).

Vi sarete chiesti perché c'è un carattere '$' alla fine delle stringhe da stampare, ebbene è un indicatore che indica al DOS la fine della stringa, infatti non viene neanche stampato.

Bene dopo tutto questo tormentone, vi sembrerà di avere in mano il vostro processore, ma ecco che arriva la randellata:

Ebbene il sistema di programmazione che abbiamo considerato si chiama 'Modo reale'. In che senso? Nel senso che opera in modo aperto verso il sistema, è l'unico programma in esecuzione sul vostro computer, ed inoltre può fare della memoria quello che gli pare. Non vi sembra una cosa potenzialmente pericolosa? pensate con un programmino del genere potrei cancellare il DOS e costringere l'utente a resettare il computer. In fondo i primi virus ci sguazzavano in queste cose.

Ebbene la Intel, dal 80386 in poi ha costruito una nuova serie di processori che oltre a possedere delle nuove istruzioni più potenti consentivano al sistema operativo (leggi Windows 95 o altro) di operare in modalità protetta.

Cioè? Be la modalità protetta è una cosa alquanto complicata, essa prevede che solo il sistema operativo può effettuare determinate operazioni, inoltre i registri di segmento non possono più indirizzare direttamente i segmenti, ma solo indicare il segmento desiderato al processore, sarà questi poi a verificare se il programma che ha chiesto l'accesso alla memoria è autorizzato a farlo o no, se avete windows 95 sicuramente vi sarà capitato con qualche programma di ricevere il seguente messaggio "Questo programma ha eseguito un'operazione non valida e sarà terminato", ebbene quel programma ha tentato di accedere ad un segmento di memoria su cui non era stato autorizzato da Windows.

Questo fatto comporta molte cose, che più programmi possono essere contemporaneamente in esecuzione, ognuno nel suo spazio assegnatogli, che non potrà interferire con altre applicazioni né tanto meno cancellare Windows.

Ed il nostro programmino?: Bè, Windows gli assegnerà una finestra in modo virtuale, ossia una parvenza di reale, e lui non si accorgerà di niente e farà il suo dovere. A presto!!!

P.S. Per compilare i programmi assembler avete bisogno ovviamente di un compilatore. Con una ricerca sul web potrete trovarne decine in formato shareware o freeware, oppure se disponete di visual C++ il compilatore è già compreso nel pacchetto. Buon divertimento.

Corso di assembler per principianti scritto da Gennaro Cifariello.

Da http://corsoassembler.dadacasa.supereva.it/default.htm?p

 
 
 

assembler per principianti

Post n°15 pubblicato il 02 Giugno 2007 da romoletto640
 

Cap. 6 LISTA DELLE ISTRUZIONI

ADD XX,YY

A proposito di numeri, se sono compresi tra 0 e 255, ossia la capacità di una cella di memoria si chiamano BYTE, se sono invece, tra 0 e 65535, ossia 16 bit si chiamano WORD.

ADC XX,YY

AND XX,YY

CALL (NEAR/FAR) XX

CLC

CLD

CLI

Lo so, lo so, vi state chiedendo che diavolo sono questi interrupt. Detto fatto.

Gli interrupt sono delle interruzioni che il sistema invia alla CPU, pensateci un po' su, il vostro programma sta facendo le sue cose, ma l'orologio del computer continua a funzionare, oppure il vostro programma non sta leggendo la tastiera, ma voi premete CTR-ALT-CANC ed il computer si resetta lo stesso, come mai?. Semplice, alcuni dispositivi come l'orologio, la tastiera, ecc. sono in grado di mandare dei segnali alla CPU del tipo 'Hey, smettila di fare quello che stai facendo, e fai un attimo quest'altra cosa, poi puoi riprendere da dov'eri rimasta.

Pensate ad un computer che gestisce una centrale nucleare, voi lo state usando per giocare a tetris ed intanto il nocciolo è in fusione e sta mandando a fuoco il resto del mondo, bene gli allarmi possono mandare un interrupt alla CPU e questa metterà da parte il vostro tetris mentre spegnerà il nocciolo e salverà il mondo.

Con l'istruzione CLI dite alla CPU di lasciar perdere gli interrupt e badare solo al vostro tetris, che vada pure a fuoco tutta la terra.

CMC

Corso di assembler per principianti

INT

IRET

JA

JB

JBE

JC YY

JCXZ YY

JE YY

JG YY

JGE

JMP SHORT

JMP NEAR

JMP FAR SS:AA

LODSB

LODSW

LOOP

LOOPE

LOOPNE

MOV XX,YY

MUL b

OR XX,YY ;Ricordate l'operazione OR vero?.

POP XX ;E

Immaginiamo di aver scritto un videogioco e di avere memorizzato in AX la posizione della nostra navetta spaziale, in CX il numero di vite che ancora abbiamo, in DX la navetta nemica, insomma abbiamo occupato tutti i registri.

Ad un certo punto del programma abbiamo bisogno di scrivere sullo schermo che si sta avvicinando un grosso asteroide e ci serve, per farlo, il registro AX, come si fa?.

Se lo usiamo subito così, perderemo la posizione della nostra navetta e ci perderemo negli abissi siderali, dunque bisognerebbe appoggiarlo da qualche parte, usare AX e dopo recuperare il vecchio valore.

Secondo voi, dove potremmo appoggiarlo? una cella di memoria? giusto, ma se volessi qualcosa di più pratico ed immediato? ma certo, una catasta, lo STACK, come ho fatto a non pensarci prima? è il posto ideale.

Dunque, eravamo rimasti allo stack, e come si fa' a mettere AX sullo stack?, ma con PUSH AX, naturalmente, e dopo quando vorremo recuperarlo basterà fare POP AX, tenete presente che se nel frattempo effettuate una CALL od una PUSH di un altro registro non potete eseguire la POP perché la CALL spinge sullo stack l'indirizzo corrente prima di saltare al nuovo e, quindi, il vostro valore di AX passerebbe in seconda posizione, mentre la POP recupera sempre l'ultimo valore aggiunto allo stack, ovviamente se eseguo PUSH AX e dopo POP BX otterro' l'effetto di spostare il valore di AX in BX, ma in questo caso era preferibile MOV BX,AX, con lo stesso risultato.

Comunque l'esempio fatto è un po' forzato perché in genere i valori che vengono usati dal programma vengono memorizzati in celle di memoria prefissate chiamate variabili (perché il loro valore può cambiare nel corso di esecuzione del programma).

A ciascuna cella possiamo assegnare un nome qualsiasi e riferirci ad essa con questo nome, per esempio la cella che contiene le vite del nostro gioco potremo chiamarla vite ed ogni volta che ci ammazzano possiamo fare 'DEC vite' che decrementa le vite e controllare il valore se è arrivato a zero (game over).

Ricordate che tutte le operazioni di lettura e scrittura diretta in memoria avvengono nel segmento DS a meno che non specifichiate un segmento diverso di volta in volta.

Notate il nome dei registri di segmento:

CS

DS

ES

SS

Dal 386 in poi esistono anche i segmenti FS e GS simili ad ES.

Volete un esempio sull'uso delle variabili?. Eccolo:

Pippo DB 10 ;Inizializza una variabile ad un byte (DB),chiamala pippo e dagli il valore 10.

Beppe DW 10000 ;Inizializza una variabile a due byte (DW) chiamala beppe e mettici 10000.

Ugo DB 'Ciao mondo' ;Inizializza una serie di byte (10) chiamali ugo e ponici i valori ASCII della frase''.

Successivamente, se il programma ha necessità di aumentare pippo di 1 per portarlo a 11, farà:

MOV AL,

INC AL

MOV pippo,AL

Proseguiamo con la lista? Ok, stavo solo chiedendo.

RCL XX

RCR XX

 

RET

RETF

ROL ; Come RCL, ma l'ottavo bit rientra direttamente al primo posto senza coinvolgere il carry.

ROR

STC

STD

STI

TEST XX,YY

Ovviamente ci sono tante altre istruzioni che ho tralasciato perché un po' più complicate o non utili per i nostri scopi.

Infatti, se ricordate, abbiamo detto che l'assembler è utile più che altro per quelle piccole utility di poco conto che non chiedono grandi risorse, ma almeno un po' di velocità, oppure questo corso può servire a capire qualcosa quando leggerete un listato assembler.

; testa i valori XX e YY ed aggiorna i flag. In pratica avviene un AND virtuale tra XX e YY.
; Poni ad 1 il flag degli interrupt. Interrupt abilitati.
; Poni ad 1 il flag di direzione, SI e DI verranno incrementati dopo istruzioni tipo LODSB o STOSB.
; Poni a 1 il flag di carry.
; Come sopra, ma verso destra.
;Come sopra, ma preleva dallo stack anche il valore del segmento di ritorno, si usa dopo una CALL FAR.
;Ritorna al programma chiamante dopo una CALL.
;Come sopra, ma verso destra. Stavolta il carry entra all'ottavo posto.
; (Rotate with carry left) ruota a sinistra con riporto. Mettiamo che XX sia il registro AL ad 8 bit. Dunque AL=10110001b, ruotare a sinistra significa, prendi il primo bit a destra (1) e spostalo al secondo posto, prendi il secondo e spostalo al 3° e così via, alla fine prendi l'ottavo e spostalo nel flag di carry, poi prendi il vecchio valore del flag di carry e mettilo al primo bit di Al. Ovviamente gli spostamenti avvengono sempre sui valori originali dei singoli bit.
;poni in pippo AL, ora pippo=11
;incrementa AL AL=AL+1 (11)
pippo ; Carica in AL il contenuto di pippo (ricordate che i valori byte ad 8 bit vanno caricati nei registri ad 8 bit, vero?
; (Stack Segment) segmento dello stack.
; (Extra Segment) a vostra disposizione per altri segmenti.
; (Data Segment) segmento dei dati.
; (Code Segment) segmento del codice.
questo?. Bé, per spiegarlo farò un piccolo esempio:
;Moltiplica AX per b. Risultato in AX
;Copia il valore di XX in YY, alla fine sia XX che YY conterranno il valore di XX, che può essere un registro, una cella di memoria od un valore numerico
; Come sopra, ma solo se flag di zero=0 e CX è maggiore di 0
; Decrementa CX, salta se cx è maggiore di 0 e flag di zero=1
; Decrementa CX, se non è zero salta di b bytes.
;Carica la word puntata da DS:(SI) in AX, incrementa SI.
; Carica il byte puntato da DS:(SI) in AL, incrementa SI.
; Salta in un altro segmento (SS) indirizzo AA.
;Salta e basta di w bytes (+-32737)
;Salta e basta di b bytes avanti o indietro (+-127)
; (Jump Greater Equal) come sopra, anche uquale. Ovviamente esistono anche le condizioni opposte ossia ,NZ (non zero), Less (minore), NE (not equal), ecc.
; (Jump Greater) salta se il primo operando è più grande del secondo. Considera il segno flag S
; (Jump Equal) salta se zero=1
;(Jump CX Zero) salta se CX=0, ve l'avevo detto che CX è il registro principe per contare all'indietro.
;(Jump Carry) salta se carry=1
;(Jump Below Equal) salta se carry=1 e zero=1
; (Jump Below) salta se carry=1, il risultato è minore. ;Salta all'indirizzo relativo YY, se il flag di carry è 0 ed il flag di zero è 0. Salto relativo significa che YY viene considerato positivo o negativo, come si diceva nella lezione precedente, e sommato o sottratto all'indirizzo corrente. Il programma riprenderà da qui. ; Fine dell'interrupt, ritorna pure dove eri. ;Richiama l'interrupt numero b, comodo per simulare la fusione del nocciolo senza rischiare il mondo. ;Complementa il flag di carry, ossia giralo a rovescio. ;Azzera il flag di interrupt, così la CPU non eseguirà gli interrupt. ; Azzera il flag di direzione. ; Clear carry flag, azzera il flag di carry ;Chiama un altro pezzo di programma che può trovarsi sullo stesso segmento (NEAR) oppure lontano (FAR), XX è l'indirizzo. ; Conoscete già la funzione AND, vero? ;Come per ADD, ma aggiunge 1 se il flag di carry è settato ad 1. ; Ovvero aggiungi ad XX che può essere un registro il dato YY che può essere un altro registro od un valore numerico.

 
 
 

assembler per principianti

Post n°14 pubblicato il 02 Giugno 2007 da romoletto640
 

Cap. 5 Algebra booleana

 

Abbiamo visto che il processore conosce solo il sistema binario (0 e 1) per cui bisogna ragionare con questo sistema per riuscire a capire il risultato di tutto quello che chiediamo al nostro processore (d'ora in poi chiamerò il processore CPU cioè Central Processin Unit, unità centrale di processo).

Il sistema binario possiede una sua logica chiamata algebra booleana, che è simile alla nostra algebra, ma che agisce su solo due cifre invece che le nostre 10 (0-9).

L'addizione si esegue in modo uguale, per esempio:

1011b +

0110b =

10001b

ovvero 1+1=0 con riporto di 1 non esistendo il 2.

Stesso dicasi per le altre operazioni.

Ma l'algebra booleana possiede altre funzioni più interessanti e non disponibili con altri sistemi.

Per esempio la funzione AND che dati due numeri esegue il confronto bit per bit del primo numero col secondo. Per esempio:

1001b AND

1100b =

1000b

Ovvero solo se entrambi i bit sono a 1 il risultato è 1, negli altri casi è 0. A che serve?. Calma ci arriviamo subito.

Supponete di avere ottenuto il risultato di un calcolo e che questo sia 10110110b, ora non mi serve il risultato complessivo, ma solo i primi 4 bit, bene basta fare AND 00001111b ed avrò estratto solo i primi 4 bit.

Un'altra funzione interessante è l'OR che funziona come AND, ma dà risultato 1 se almeno uno dei due bit è a 1.

Un OR più drastico è lo XOR che richiede che uno ed uno solo dei due bit sia ad 1 per dare 1 altrimenti ritorna 0.

Questo è quasi tutto quello che c'è da sapere sull'algebra booleana, per quello che ci riguarda. Vogliamo, ora, fare una lista delle istruzioni disponibili? Lo temevo che avreste detto di si.

La lista non sarà completa, ma comprenderà solo quelle istruzioni di uso più frequente e meno difficile, per altre informazioni vi consiglio di procurarvi un bel tomo della Intel sui suoi processori.

Prima devo spiegare la funzione di un registro che ho nominato precedentemente, e voi vi state ancora chiedendo a che serve. Giusto? Questo è il registro F, che è l'iniziale di FLAG, in inglese bandiera, ebbene il nome è proprio appropriato perché il registro F si comporta come una bandiera che può essere alzata o abbassata a seconda delle condizioni, anzi 16 bandiere perché il registro F è a 16 bit, ed ogni bit rappresenta una situazione.

Si va bene, ma quale situazione? Per rispondere farò ora un piccolo esempio.

Prendiamo il seguente pezzo di codice:

MOV CX,2 'carica 2 nel registro CX

DEC CX 'decrementa il registro CX di 1, CX=CX-1

DEC CX ' decrementa di nuovo il registro

Cos'è successo dopo il secondo decremento? Che CX è diventato zero, la CPU giustamente se ne accorge e pone a 1 il bit corrispondente in F che si chiama bit di zero, quindi se io volessi controllare se un'operazione ha dato zero come risultato mi basta controllare questo flag, esiste anche il flag di carry che segnala se in una sottrazione c'è stato prestito, un altro chiamato flag di overflow che segnala se l'operazione ha ecceduto la capacità del registro, il flag di segno che segnala se il sedicesimo bit è ad 1, poiché in alcuni casi i registri vengono considerati a 15 bit e negativi o positivi, e quindi il sedicesimo bit è zero se positivo e 1 se negativo.

Esiste anche il flag di direzione che indica se i registri SI e DI devono incrementarsi o decrementarsi in seguito ad alcune istruzioni di lettura scrittura in memoria.

 
 
 
Successivi »
 
 
 

INFO


Un blog di: romoletto640
Data di creazione: 29/05/2007
 

CERCA IN QUESTO BLOG

  Trova
 

ULTIME VISITE AL BLOG

precious445benny1984fredom010pantera_blanca2NevegGgiallAea.joobleRjegu73developer68OLIO5wallygator54istrice82hiram9mrk2005rospetta000erconte5
 

CHI PUÒ SCRIVERE SUL BLOG

Solo l'autore può pubblicare messaggi in questo Blog e tutti gli utenti registrati possono pubblicare commenti.
 
RSS (Really simple syndication) Feed Atom
 
 

I MIEI LINK PREFERITI

 

© Italiaonline S.p.A. 2024Direzione e coordinamento di Libero Acquisition S.á r.l.P. IVA 03970540963