program1
Assaggio: Costruiamo una applicazione windows utilizzando nvda
Donato taddei su uictech, 07\02\2013, h. 22.08.

Prerequisiti: nessuno.
Per questo messaggio non è richiesto aver installato nvda, nè tanto meno conoscerlo.
Se vi è interesse o consenso ditelo che continuo in questo tono, e soprattutto l'invito è a chi sa 
di approfondire, articolare, riproporre in altra salsa i concetti qui esposti, come una sorta di 
gioco del domino.

Qualche domanda:
vi è mai capitato, aprendo un programma da "esplora risorse" di vedere come programmi grossi come 
diciamo potrebbe essere outlook express, con una frega di funzionalità, abbiano un eseguibile, il 
file *.exe di pochi kilobytes?

Altra domanda:
Avete mai sentito parlare di dll?
Pensate che siano dei programmi?
La risposta è: sì e no.
Sì: l'acronimo dll sta per "dynamically linkable library" vale a dire una libreria che viene 
caricata dinamicamente al momento dell'esecuzione del programma che la utilizza.
Pertanto le dll possono essere definite come dei files contenenti collezioni di Segmenti di codice 
compilato che assolvono a determinate funzioni e che quindi sono costituite a loro volta da un 
complesso di variabili e istruzioni che eseguono un dato compito, una funzionalità e che dunque 
chiameremo sinteticamente funzioni.
Una dll contiene quindi una collezione di funzioni.
Quindi più software di così.
Anzi diciamo che le dll sono la "struttura portante" del software non solo del sistema operativo ma 
delle singole applicazioni.

No:
Non sono dei programmi in quanto nel linguaggio comune col termine programma ci si riferisce quasi 
sempre al sistema che ci permette di interagire col computer per compiere una data operazione, (i 
menu, le finestre, le caselle, le icone, i drivers, le combinazioni di tasti ecc.
Ogni programma ha quindi una serie di componenti: dll, file, finestre, che tecnicamente vengono 
chiamate "risorse" associate al programma.
Chiamasi "interfaccia" quel componente che permette l'interazione con l'utente, ovvero permette 
all'utente di dare ordini al computer e di gestirne i risultati dell'elaborazione.

Altra domanda:
Cosa succede quando diamo invio per aprire un file eseguibile o, il che è lo stesso, quando 
lanciamo un programma dal relativo menu?
Si dice che Attiviamo un evento, quello appunto di lanciare il tal programma, che viene 
intercettato dal sistema operativo che così si accorge di cosa vogliamo e provvede si dice 
tecnicamente ad "allocare le relative risorse.
Che significa?
Significa che il sistema operativo caica nella memoria il programma e tutto quanto di cui ha 
bisogno per funzionare (al solito files, finestre, icone, drivers ecc.) essendo la memoria 
centinaia di volte più veloce rispetto per esempio agli hard disk, in modo tale che il programma 
possa lavorare completamente in memoria e non aver bisogno di altro.
Ma quale memoria domanderete, visto che sapete tutti che esiste una memoria reale e una virtuale?
Se c'è memoria libera in quella reale, viceversa parte in quella reale e parte in quella virtuale e 
tanto più la memoria reale sarà occupata da altri programmi tanto più sarà la parte caricata in 
memoria virtuale, con relativo degrado delle prestazioni, perchè la memoria virtuale in realtà è 
basata sulla scrittura del suo contenuto sull'hard disk che appunto abbiamo detto essere molto più 
lento della memoria.
Chiaro allora perchè a caricarci programmi tropo pesanti o troppi programmi si rallenta il sistema?

Prima di cedere il controllo della macchina al programma il sistema operativo gli assegna un 
nemerino detto identificatore di processo (processId) col quale identificarlo univocamente, perchè 
ad esempio potremmo avere lanciato più istanza dello stesso programma contemporaneamente: per 
esempio aprendo due differenti finestre del browser, che sarà sempre IE o Firefox o Chrome, 
Attraverso il nemerino identificatore di processo il sistema saprà da quale finestra del browser 
proviene una determinata richiesta e conseguentemente indirizzare alla stessa il risultato della 
richiesta.

Tornando al caricamento del nostro programma Infine si dice che "gli cede il controllo", vale a 
dire che carica nei registri il punto di inizio del programma e questi comincia il suo lavoro.

Tornando al fatto che i file exe sembrano spesso straordinariamente piccoli rispetto alle loro 
funzionalità ciò è perchè di solito questi, come primissima cosa che fanno è richiamare, cioè 
caricare in memoria, le dll di cui hanno bisogno e in cui è contenuto la stragrandissima 
maggiorannza di quello che fanno.
Sarà quindi tra i primissimi compiti del programmatore specificare al sistema operativo le dll di 
cui il programma ha bisogno.

Altra domanda:
avete mai fatto caso che ad esempio piccole utility a riga di comando sembrano comportarsi 
diversamente dal resto dei programmi?
Quando le lanciate fanno il loro mestiere e finiscono automaticamente dopo aver prodotto i 
risultati, ma se invece lanciate il browser o il programma di posta o media player bisogna 
ammazzarlo con alt+f4, altrimenti rimane lì, sempre a vostra disposizione.
Ci sono quindi due tipi di programmi:
- quelli che una volta lanciati fanno quello che devono fare e passano subito la mano
- e quelli che una volta lanciati non terminano, non passano la mano.

Occupiamoci di questi ultimi.
Cosa fa il nostro programma di posta dopo che lo abbiamo aperto e lasciato lì aperto dopo aver 
scaricato la posta, mentre per esempio siamo occupati in un'altra finestra a scrivere il messaggio 
di risposta, a navigare o a parlare al telefono?

Risposta:
Niente. si gratta le bale in attesa che ci venga in mente di inviare la posta, di chiuderlo, di 
bloccare un certo mittente ecc..
Però, a differenza di quanto per esempio avveniva col dos quando veniva tassativamente eseguito un 
programma alla volta e il successivo poteva essere lanciato solo dopo che il precedente avesse 
finito e liberato la memoria, qui siamo come si dice in un ambiente "multitasking" vale a dire che 
la memoria è condivisa da tutti i programmi che sono in esecuzione in un dato momento.

Allora quale di questi sarà eseguito?
Tutti, un po per uno.

ma quanto poco e con quale ordine?
Intanto avranno precedenza quelli con una priorità più alta, poi quelli che consumano meno risorse, 
ma toccherà un po per uno a ciascuno.

Come realizza ciò il sistema operativo?

Come un maestro di musica che indica con la bacchetta il memento di attacco a ciascun orchestrale.
O meglio ancora: manda un sms al programma. (c'è posta per te).
Il programma lo riceve, vede dal mittente chi glielo ha mandato, cosa vuole (per esempio una sua 
finestra gli fa sapere che è stato premuto un certo pulsante, un certto driver gli comunica che ha 
finito di suonare un certo file, è stata fatta una determinata scelta da un menù, ecc.) fa quando 
gli si richiede e ritorna al sistema operativo che cede il controllo al prossimo in attesa.
Chiameremo "evento" ogni modifica dell'ambiente software: l'apertura di una finestra, la pressione 
di un tasto, l'ingrandimento di una finestra, la selezione di un pulsante radio, l'avveenuta 
connessione o disconnessione da internet o da un dispositivo, insomma ogni modifica dell'ambiente 
causata dall'utente o da altro programma, locale o remoto.
Diremo allora che siamo su un sistema "ev ent-driven", guidato dagli eventi che in esso si 
manifestano, eventi che normalmente generano a loro volta "eventi di risposta come per esempio la 
chiusura di una finestra, la chiusura e scaricamento dalla memoria di un programma, o qualsiasi 
altra cosa in risposta a un determinato evento.
Dunque il nucleo centrale di un qualsiasi programma di questo secondo tipo, la funzioone principale 
che ha avuto per prima il controllo al momento del lancio e che in molti linguaggi viene appunto 
chiamata "main", anzicchè essere come quelli del primo tipo (le utility a riga di comando di cui 
sopra) che sono costituiti da una sequenza di operazioni seguiti dalla fine del programma stesso e 
relativo scaricamento dalla memoria, questi sono costituiti da una funzione chiamata solitamente 
WinMain nel linguaggio c, che, effettuate le operazioni preliminari come caricamento di dll, 
inizializzazioni ecc. si limita a processare gli sms a lei diretti ripassando il controllo al 
sistema operativo fino a che non riceve un sms di chiusura causato per esempio dalla pressione di 
alt+f4, e in tal caso farà le operazioni finali come rilascio della memoria, scaricamento di file 
sull'hard disk, e toglierà il disturbo.
Da quanto detto emerge che il lavoro del programmatore in una applicazione di questo tipo, consiste 
nel predisporre la risposta adeguata a tutti gli sms che possono essere inviati al programma dai 
dispositivi, dalle finestre, dalle altre applicazioni che segnalano un evento.
Ho detto sms perchè in effetti questi messaggi del sistema operativo sono il più breve possibile 
ergo short:
contengono
- il nemerino del processo che ha inviato il messaggio,
il nemerino che è stato assegnato all'interno di quel processo a ciascuna risorsa utilizzata dal 
programma come la finestra in cui è stato attivato quel tal pulsante, o il numerino relativo a un 
dato file aperto, o il numerino associato ad una icona o ad un oggetto grafico, che poi è lo stesso 
numerino che jaws vi dice quando attivate i grafici,
_ il messaggio vero e proprio, sempre un numerino da cui si capisce ad esempio se è stato premuto 
un tasto o cliccato il mouse, o è passato un dato tempo
- altri due numerini supplementari utilizzati per esempio per specificare quale tasto è stato 
premuto o quale operazione è stata richiesta.

Come anticipato python e nvda qui non c'entrano.
Tuttavia al solo scopo di dare una idea, sapete come si fa a caricare una dll in python?
windll.kernel32

e avremo caricato in memoria una copia la dll kernel32.dll contenente molte funzioni base del 
sistema operativo:

Adesso vogliamo ottenere un numerino da associare a un determinato componente, per esempio una dll, 
utilizzando la funzione GetModuleHandleA contenuta in kernel32.dll:

print windll.kernel32.GetModuleHandleA

Se poi vogliamo verificare che non ho detto sciocchezze, perchè detto così sarebbe troppo facile, 
nonostante le leggende metropolitane sulle indentazoini del pitone,

apro il menu di nvda scelgo strumenti e poi console python

e scrivo queste tre righe.

from ctypes import *
windll.kernel32
windll.kernel32.GetModuleHandleA

vedrò il numerino associato alla dll e quello restituito dalla funzione GetModuleHandleA

E come assaggio può bastare.
Se Andrea o altri pù esperti vorranno integrare, chiarire, approfondire, insomma continuare il 
domino faranno cosa utile e a me gradita.
Francesco Melis:
A commento di quanto detto da Donato aggiungo qualche nota relativa ai
dubbi e curiosità che potrebbero sorgere.
Intanto un incoraggiamento a Donato a continuare ed ai suoi "discepoli"
ad avere costanza e non scoraggiarsi.
Quando compare qualche citazione che non si capisce, dai sù! non ci
vuole molto a fare una ricerchina su internet per chiarirsi qualche
concetto poco conosciuto.
Tanto tempo fa a me venne un dubbio.
Posto che il sistema operativo è un software come tutti gli altri,
quantunque speciale, essendo il software fondamentale senza il quale non
potrebbero girare gli altri programmi, mi chiesi come mai quando il
processore sta eseguendo un programma applicativo che richiede molte
risorse di calcolo, cioè ci mette molto a terminare, il sistema
operativo che in quel momento non è in esecuzione può requisire la CPU
al programma applicativo, eseguire se stesso e passare l'esecuzione ad
un altro processo in attesa?
Cioè, a livello di linguaggio macchina, (che tra l'altro è la parte
dell'informatica che a me interessa maggiormente), quando è in
esecuzione un programma, la Cpu esegue le sue istruzioni e non ha la
minima percezione, (è troppo stupida), che quelle istruzioni non sono
del sistema operativo. Come mai un programma o modulo che dir si voglia,
dovrebbe smetterla di eseguire le sue istruzioni e lasciare il controllo
ad altri?
Lo stesso sistema operativo, quando manda in esecuzione un programma fra
i vari che può avere allocato in memoria Ram, come fa ad intervenire se
la cpu che dovrebbe eseguire le sue stesse istruzioni è impegnata con le
istruzioni di un altro processo?
La tecnica che viene usata sfrutta le possibilità offerte dallo stesso
harware. Esiste una sorta di sveglia nell'hardware delle macchine
chiamata "watch dog timer" che tradotta dovrebbe essere più o meno
"temporizzatore del cane da guardia".
Bene, le cose funzionano più o meno così.
Quando il sistema operativo lancia un programma associa ad esso, o al
modulo, il descrittore che ha ben descritto Donato, cioè, detto alla
buona, "la sua carta di identità". Dopo di che carica una sveglia
hardware (il watch dog timer" con il tempo che ritiene di destinare a
quel programma. Mettiamo tanto per fare un esempio numerico 1
millisecondo. Come dire: "svegliami fra un millesimo di secondo". Dopo
di che il sistema operativo si distacca nel senso che cede la cpu
facendo eseguire ad essa la prima delle istruzioni del programma
applicativo. Trascorso il millesimo di secondo della carica della
sveglia il sistema operativo sarebbe bello che morto e non potrebbe mica
riintervenire se non avvenisse qualcosa che lo risvegliasse. Ci pensa la
sveglia che una volta suonata manda un segnale hardware alla cpu
chiamata "interrupt" che richiama la sua attenzione interrompendola e
qualificandosi come "la sveglia". La cpu non può ignorare questa
chiamata hardware poiché stavolta è corrente elettrica che gli arriva ad
un piedino e lei è progettata per rispondere a questa chiamata. La cpu
allora, automaticamente, è costretta ad eseguire una routine di gestione
dell'interruzione la quale salva il contesto operativo nel quale si
trovava il processo in esecuzione in quel momento per poterlo riprendere
più tardi esattamente da dove era arrivato, e finalmente richiama in
esecuzione le istruzioni del sistema operativo.
Bene, una volta ripreso il controllo della cpu, risvegliatosi, il
sistema operativo va a vedere le sue carte e cartoncelle (descrittori
dei processi) e vede a chi tocca di mandare in esecuzione fra i vari
processi in attesa. Basandosi sui descrittori che egli conosce
perfettamente quindi manda in esecuzione un altro processo secondo una
sua politica di priorità.
La cosa fantastica è che i sistemi operativi seri sono in grado di
gestire delle "priorità dinamiche" cioè in altri termini che anche i
processi con bassa priorità, che potrebbero essere sistematicamente
prevaricati da altri processi a priorità più elevata, con il trascorrere
del tempo cambiano la loro priorità aumentando di livello fino a
portarsi alla priorità che consente loro di essere presi in
considerazione dal sistema operativo per essere mandati in esecuzione.
***
Donato Taddei:
per fare una ripassatina veloce di alcuni concetti ribaditi da Francesco nella sua integrazione al 
mio messaggio di diri nonchè per
fissare meglio concetti affrontati in precedenza come i numeri binari
ho ripescato su pcciechi un mio messaggio pensate del 2001 che proponeva uno scritto del 1998 in 
cui veniva brevemente presentato il linguaggio assembler Intel perchè l'assembler, per definizione, 
è il linguaggio che più si avvicina al linguaggio macchina.
Dunque può fornire quache elemento sul funzionamento a più basso livello dell'hardware.
Ho tagliato qualcosa e fatto qualche piccola annotazione per attualizzare il tutto.

Poi ho da assegnare un compitino a qualche volenteroso, per esempio Francesco.
Ieri abbiamo detto che il sistema operativo, all'atto di lanciare un programma, anzi prima di 
lanciarlo, crea il relativo processo con la funzione pensate un po che fantasia "CreateProcess" e 
che indi passa il controllo alla funzione principale del programma che nei programmi c si chiama 
WinMain:
bene queste sono delle funzioni cui vengono passati dei dati sotto forma di parametri e 
restituiscono strutture di dati come quelle sommariamente descritte da me ieri.
Il compitino consiste nello specificare più precisamente questi dati e di farlo, ciò è tassativo, 
in maniera indipendente dal linguaggio perchè un'altra cosa va chiarita:
se un programma usa funzioni contenute nella dll kernel32.dll per esempio per cancellare un file, 
la struttura dei dati da passare come parametri alla funzione DeleteFileA dove la a finale sta per 
ascii poichè per la maggior parte delle funzioni esiste una versione ascii compatibile ed una 
unicode compatibile della stessa funzione
Dicevamo che quando un programma invoca, chiama, una funzione contenuta nella dll i dati passati 
come parametri alla funzione e la struttura dei dati restituiti in output dalla stessa sono sempre 
quelli indipendentemente dal fatto se il programma che la usa sia scritto in c, in delphi, in 
visualbasic o altro, e non potrebbe essere diversamente perchè si statta sempre della stessa dll, 
il file è sempre lo stesso.
Procedendo in tal modo si fanno due servizi buoni:
si dà la possibilità a chi si sta impelagando in uno specifico linguaggio di non rimanerne 
completamente invischiato e a volte disorientato e soprattutto si dà la possibilità a chi ancora 
non si è imbarcato o non intende imbarcarsi di trarre profitto da questi thread, evitando la molto 
probabile torre di babele conseguente al fatto che ciascuno parla con la terminologia specifica del 
proprio linguaggio.
Se si riesce ad approcciare il problema nella maniera più eclettica possibile sarà un vantaggio per 
tutti.
Don

l'assembler intel :introduzione ai concetti generali di programmazione
di donato taddei

alle volte si impara anche da un pazzo o da uno scemo!

Questo scritto e' del 1998 ma niente paura: la logica Booleanasu cui sono

basati gli attuali e i futuri computerse' nata nell'800!

---------------------------------------

l'assembler intel in 4 sedute di Donato Taddei

Introduzione

bit, byte, sistemi di numerazione:

binaria, ascii, esadecimale.

Clock, registri, stack, interrupt, segment prefix (psp)

Nessuno si sogna di volervi insegnare l'assembler!

sarei oltre tutto la persona meno indicata a farlo:

io infatti programmo in c.

Questo scritto si propone di dare una "infarinatura" sui concetti e gli

elementi caratteristici di questo linguaggio, il piu' vicino all'hardware,

tale da permettervi teoricamente di scrivere voi un programmino in

assembler, alla fine di queste sedute, servendovi del materiale a corredo:

-il set completo delle istruzioni assembler intel

-"programmer technical reference for msdos and ibm pc".

Questo scritto si propone altresi' di soddisfare la curiosita' di chiunque

voglia farsi magari solo una pallida idea della materia.

nei capitoli seguenti, tratti da PCGPE,

"personal computers games programmers encyclopedia", da me tradotti,

si assume che voi sappiate cosa sia un interrupt,

e amenita' del genere.

percio' nel prosieguo di questo capitolo verranno tratteggiati alcuni concetti

basilari

Cos'e' il sistema binario? cos'e' la memoria? come si rappresentano i dati?

Qual'e' il cuore di un computer?

Cosa sono i registri, lo stack e gli interrupt?

l'industria dei computers si e' potuta sviluppare grazie all'applicazione

su vasta scala di tecnologie connesse ai semiconduttori:

si tratta di derivati del silicio, uno degli elementi piu' diffusi sulla

crosta terrestre, che si comportanoin modo particolare quando sono

attraversati da una corrente elettrica:

normalmente sono conduttori fino a caricarsi; raggiunto un quantum

divengono isolanti, interrompendo il flusso;

si dice cioè che "scattano": Esempio classico, il transistor.

bit, bytes e sistemi di rappresentazione:

binaria, ascii, esadecimale.

La memoria di un computere' costituita da una enorme serie di bit, cioè' di

punti magnetici che possono essere magnetizzati o no, caricati o no, on o off.

un singolo bit, quindi, puo' assumere solo due stati 1 (carico) e 0.

Quando un bit viene sollecitato dal passaggio di una corrente cambia il suo

stato: se e' scarico si carica, passando da 0 a 1;

viceversa si scarica, passando da 1 a 0.

L'unico sistema di numerazione che utilizza le cifre 1 e 0 per rappresentare

tutti i numeri e' quello in base 2, detto appunto sistema di

numerazione binario. Per inciso va detto che molti matematici e studiosi

ritengono che il sistema binario sia il piu' antico sistema di numerazione

in quanto permette un approccio qualitativo e non quantitativo nella

rappresentazione dei fenomeni: si'-no, bene-male, e' cioè basato sulle

antinomie: 4.000 anni fa i cinesi utilizzavano rappresentazioni binarie

con tratti interi o spezzati (come ancora si ritrova in allegorie orientali),

per rappresentare esplosioni combinatorie per scopi di previsione e di

divinazione.

La rappresentazione binaria delle cifre decimali da 0 a 9 in ordine crescente e':

0, 1, 10 11,100, 101, 110, 111, 1000, 1001.

Da ciò segue che bisogna utilizzare una sequenza di bit via via crescente

col crescere dei numeri: 2 elevato a n (dove n e' il numero di bit considerati)

esprime il numero di possibili rappresentazioni:

2 alla prima = 2, alla seconda = 4, alla terza = 8, alla quarta = 16, alla ottava = 256, alla

sedicesima = 65536, alla 32 = 4.294.836.225, etc.

Per rappresentarele lettere dell'alfabeto, i numeri, la punteggiatura,

i simboli matematici, le lettere dell'alfabeto greco, etc.

si e' stabilito di consideraregruppidi 8 bits per volta:

8 bits permettono256 possibilita' dirappresentazione.

Questi sono dette bytes, sono le celle di memoria elementari, contengono

normalmente un carattere.

Ad ogni caratterrecorrisponde quindi un numero binario da 0 a 255,

la rappresentazione ascii (american standard computer interchange information)

non e' altro che la rappresentazione decimale di tale numero binario:

ad esempio, un byte contenente il carattere "A" e' una sequenza binaria

01000001, corrispondente al valore decimale (o ascii) 65.

Dunque per rappresentare in ascii (decimale) molti caratteri sono

necessarie tre cifre: es. 122 per il carattere "z".

Fin dall'inizio pero' si e' preferito ricorrere a una rappresentazione piu'

compatta che riduce a 2 soli simboli la rappresentazione di un byte di memoria:

questa e' basata su un sistema di numerazione in base 16, perciò detta

esadecimale, in cui oltre alle normali cifre da 0 a 9 vengono anche utilizzate

le lettere a, b, c, d, e e f per i numeri da 10 a 15.

Cosi':1= 1, a = 10, f = 15, 10 = 16,20 = 32, 80 = 128,ff = 255,

100 = 256, 200 = 512, 400 = 1024 fff = 4095, 1000 = 4096,

a000 =40960, ffff = 65535, f0000 = 65536.

Nellinguaggio assembler si fa spesso ricorso alla rappresentazione

esadecimale perchè, essendo in base 16 = 2 alla quarta, permette di riferirsi

a un gruppo di 4 bits, cioè a un semibyte (8 / 2 bits).

quando si utilizza una notazione esadecimale si pospone una "h":

cosi' il carattere "a" (ascii 65, come visto sopra), si rappresenta in assembler come 41h.

Il timer o clock e i registri.

Il cuore pulsante del computer e' costituito dal timer o clock.

Attenzione! non si trattadell'orologino che vedete disegnato sullo

schermo in molte applicazioni;

quello viene aggiornato, cambia, 18.2 volte al secondo.

Il clock hardware invece scatta da decine a centinaia di milioni di volte al

seconto, determinandola velocita' del processore.

Quando si dice che un processore e' a 166 MHZ (megahertz) si dice che il suo

clock e i suoi circuiti logici scattano 166 milioni di volte al secondo.

E per chi legge nel 2013 vale la stessa identica cosa per i gigahertz degli attuali processori.

Ad ogni tic del timer il controllo ritorna al processore.

Il processoresi accorge di quello che deve fare o che ha fatto esaminando il

contenuto di speciali circuiti detti registri.

Nell'architetturaintel vi sono due sets di registri: un set a 16 bit (2 bytes),

e uno a 32 bit, usato sostanzialmente per la modalita' protetta

(es. ms windows95). e ovviamente, per chi legge nel 2013 tutti i window succwessivi.

Potete trovare una descrizione di tali registri

nel "programmers technical reference for msdos and ibm pc.

Nel linguaggio assembler, come anche del resto nei linguaggi di alto livello

come il c o il pascal, e' possibile variare e manipolare il contenuto

dei registri riferendosi loro con dei nomi simbolici:

(qualcuno sicuramente ricorda R1, ... r16 dell'assembler 360 ibm ad esempio!)

-normalmente usati dalle routines del sistema: ax, bx, cx, dx;

-contengono dati relativi al segmento: cs, ds, es, ss;

-indici: si, di (source index e destination index);

-puntatori: bp, ip, sp (stack pointer);

-contiene notizie sullo stato delle operazioni fatte: flags.

per riferirsi al set di registri a 32 bytes si premette una "e" al nome:

eax, ebx, esi, ebp.

Per chi legge nel 2013 vi sarà capitato di vedere generalmente nelle segnalazini di erore o nei log 
di trovare robe tipo eax, ebx, ecc.:

non è altro che la trascrizine del contenuto di tali registri al memento del verificarsi 
dell'errore sicchè ci ci capisce, per es. la microsoft cui queste segnalazioni vengono 
eventualmente girate.

per quanto riguarda il set a 16 bit e' anche possibile riferirsial singolo

byte,di sinistra o di destra:

cosi ah, bh, ch, dh indicano rispettivamente il byte di sinistra (high, alto)

dei registri ax, bx, cx, dx

mentre al, bl, cl, dl si riferiscono al byte di destra (low, basso).

Ma questa è roba che si usava ai tempi del comando debug del dos prima che anche questo passasse ad 
usare registri a 32 bit, come nel caso delle moderne versioni del command.com e cmd.exe.

Nei registri si trovano gli indirizzi di memoria in cui

sono memorizzati i dati e il codice, vale a dire la sequenza delle azioni

che il processore deve eseguire.

Ma cosa sono queste azioni?

Un programma e' costituito da una sequenza di istruzioni macchina,

costituite da un codice operazione e dai relativi operandi:

cosi' l'istruzione assembler

mov ax, 1 (metti 1 nel registro ax)

vienetradotta dal compilatorein una sequenza binaria:

il codice mnemonico "mov" viene tradotto nel corrispondente codice binario

che attiva una sequenza di operazioni sui circuiti il cui risultato e' quello

appunto di impostare 1 nel registro ax.

ogni istruzione macchina si sviluppa in una precisa sequenza di operazioni

sui circuiti hardware che impiega alcuni cicli di macchina,

scanditi dai tics (scatti) del timer.

Come potete vedere nel set di istruzioni, dove vengono riportati

i cicli di macchina a fronte di ciascuna istruzione, si va da 3-4 fino a 10,

in funzione della complessita' delle istruzioni stesse.

Qui va solo detto che si parla impropriamente dell'assembler come linguaggio

macchina: nel linguaggio macchina le istruzioni sono composte da un codice

binario e dai relativi operandi;

invece l'assembler e' un vero e proprio linguaggio di programmazione:

-utilizza codici mnemonici per richiamare i relativi codici operazione;

-permette di riferirsi a indirizzi di memoriamediante nomi simbolici;

-permettedi associare nomi simbolici a sequenze di istruzioni

(si parla allora di macroistruzioni o macros).

- permette di includere nel sorgente altri segmenti di codice,

standard o precostruite (librerie);

- permette di scrivere un programma in moduli separati e di

richiamare routines esterne.

Malgrado in un semplice programma assembler vi sia corrispondenza

1 a 1 tra le istruzioni del sorgente e le relative istruzioni in

linguaggio macchina,l'output di una compilazione assembler non e' ancora

eseguibile:sara' il successivo passaggio al linker che lo rendera'

eseguibile, risolvendo i collegamenti con i moduli esterni e con le

routines del sistema operativo.

Lo stack.

L'architettura dei computers intel implementa uno "stack" hardware che

contiene gli indirizzi che puntano alle istruzioni che devono essere

eseguite: il registro SP (stack pointer punta alla istruzione da eseguire,

il cui indirizzo sitrova nello "stack", che pure contiene gli operandi,

i dati su cui si deve effettuare l'operazione.

Sotto questo profilo sono fondamentali due istruzioniassembler: PUSH e POP.

La prima "push" spinge nello stack, all'indirizzo puntato in quel momento

dal registtro SP, l'istruzione da eseguire con i relativi registri in cui sono

memorizzati i dati e i relativi indirizzi di memoria.

Inoltre lo stack pointer (registro SP) viene incrementato in modo da poter

caricare la prossima istruzione.

l'istruzione "pop" effettua l'operazione contraria, decrementando lo

stack pointer, punta alla istruzione precedentemente eseguita.

Gli interrupt.

Quando si accende un computer la prima operazione che viene eseguita

automaticamente e' il caricamento del sistema operativo.

Oltre all'interprete dei comandi esso contiene una serie di routines

in linguaggio macchina che effettuano le operazioni base del sistema,

richiamabili dall'interno dei programmi.

Tali routines sono dette "interrupt":

esse infatti, terminata l'esecuzione, interrompendo il flusso del programma,

ritornano al sistema operativo, con un codice di errore

(errorlevel, normalmente nel registro ax).

il primo k della memoria (1024 bytes) , dopo il caricamento del sistema,

contiene un set di indirizzi (256), ciascuno di 4 bytes,

appunto di tali routines. Percio' e' noto come "vettore di interruzione".

l'istruzione assembler int 5h cede il controllo all'indirizzo

contenuto nel quinto elemento del vettore di interruzione,

vale a dire al byte 20 (5 * 4). Di solito in questa locazione di memoria

si trova l'indirizzo della routine che stampa il contenuto del video.

Se un programma imposta in questa locazione un'altra routine che per esempio

suona un allarme, quando si premera' il tasto "printscreen"

udrete l'allarme, invecedistampare il video.

Quanti sono gli interrupt?

Come detto il vettore di interruzione contiene 256 indirizzi, ma non tutti

sono utilizzati. I programmatori hanno quindi la possibilita' di definire

degli interrupt a loro piacere, ed anche di ridefinirequelli che il

sistema ha caricato all'accensione.

Gli interrupt possono essere divisi in quattro categorie:

-interrupt di sistema: il timer, (interrupt 8h, "printscreen 5h, exx,

sono sempre attivi

- rom bios interrupt:

gestiscono la comunicazione con le periferiche:

il video 10h, le porte seriali 14h, la tastiera 16h, la stampante 17h,

i floppyes, l'hard disk etc.

- dos interrupt: sostanzialmente l'interrupt 21hcui si possono richiedere

quasi tutti i servizi, fatti da altri interrupt.

-altri interrupt vari.

Prima di chiamare un interrupt bisognera' impostare correttamente il contenuto

di alcuni registri: si rimanda al "programmer technical reference", gia citato,

per la documentazione del loro uso.

Gli indirizzi o le locazioni di memoria.

Abbiamo visto che per riferirsi agli indirizzi di memoria il sistema

utilizza i registri. Abbiamo visto che il set normale di registri e'

a 16 bit = 2 bytes.

Con 2 bytes si puo' rappresentare un numero binariomassimo: 2** 16 = 65536.

A differenza di altri sistemi operativi quelli Microsoft dividono la memoria

in segmenti ciascuno di 65536 bytes (64 kbytes, 64 * 1024).

Quando all'interno di un programma ci si vuole riferire a una locazione di

memoria e' possibile farlo in due modi:

-in modo relativo, a partire dall'inizio del segmento,

contenuto nel registro SS (start segment):

per far cio' basta utilizzare un solo registro che al massimo puo'

contenere in binario 65536.

-in modo assoluto, servendosi di una coppia di registri,

di cui il primo contiene il numero che identifica il segmento e il

secondo contiene l'indirizzo relativo al suo interno (offset).

Al riguardo vanno fatte due osservazioni molto importanti:

1) - ai registri (segmento) (cs, ss, es, ds) si puo' accedere solo attraverso

altri registri, e quindi per impostare 512 nel registro es

si fara:

mov ax, 200h

mov es, ax

2) - quando e' stato creato l'assembler intel si riteneva che la memoria

utilizzata dai computer non potesse superare il mega: cosicche' bastavano

20 bits per ciascun indirizzo. Ovviamente oggi le cose non stanno piu'

cosi' mail problema rimane:

l'inizio di ciascun segmento viene allineato al paragrafo;

ogni paragrafo occupa 16 bytes di memoria.

negli indirizzamenti assoluti attraverso coppia di registri

(segment:offset), quindi, il registro segment conterra' il numero di

paragrafi, a partire dall'inizio della memoria, vale a dire :

indirizzo assoluto del primo byte del segmento diviso 16.

se ad esempiosi vuole utilizzare la coppia es:di per puntare

al dodicesimo byte del segmento che inizia all'indirizzo assoluto

2048 (800h),

si fara':

mov di, 12

mov ax, 128 ;2048 / 16

mov es, ax

IL PSP "program segment prefix".
Torna all'indice