PC Assembly Language | Cerca per titolo, autore, parola chiave | ||||||||
PC Assembly Language Paul A. Carter, Novembebre 16, 2019. Ho insegnato informatica per 10 anni alla University of Central Oklahoma, tenendo corsi introduttivi alla programmazione Assembly. Frustrato dal fatto di insegnare la programmazione real mode a 16 bit, passai alla programmazione protected mode a 32 bit. Incontrai immediatamente un ostacolo: non esistevano testi sulla programmazione protected mode a 32 bit. Così decisi di scriverne uno io. Gli altri libri sul linguaggio assembly per PC ancora insegnano come programmare il processore 8086 che i primi PC usavano nel 1981! Il processore 8086 supporta solo la modalita’ remota. In questa modalita’, ogni programma puo’ indirizzare ogni memoria o periferica di un computer. Questa modalita’ non e’ adatta per un sistema operativo multitasking sicuro. Questo libro invece discute su come programmare il processore 80386 e i successivi in modalita’ protetta (la modalita’ che usano Windows e Linux). Questa modalita’ supporta le caratteristiche che i moderni sistemi operativi si aspettano come la memoria virtuale e la protezione della memoria. Il libro, inoltre, mostra come interfacciare assembly al codice C, offrendo un valido aiuto ai programmatori C che desiderano comprendere come funziona C dietro le quinte. Tutti gli esempi di questo libro utilizzano il NASM (Netwide) assembler. Questo libro, come già detto, tratta della programmazione in protected mode a 32 bit e richiede, di conseguenza, un compilatore a 32 bit protected mode. È possibile utilizzare gli esempi di codice in un sistema operativo a 64 bit, ricordandosi, però, che il programma verrà eseguito a 32 bit e non potrà servirsi di alcuna funzionalità a 64 bit. I PC tipo IBM contengono una CPU della famiglia Intel 80x86 (o un loro clone): Le CPU di questa famiglia hanno tutte le stesse caratteristiche incluso il linguaggio macchina di base. 8088,8086: Queste CPU, dal punto della programmazione sono identiche. Queste sono le CPU che erano usate nei primi PC. Forniscono diversi registri a 16 bit: AX, BX, CX, DX, SI, DI, BP, SP, CS, DS, SS, ES, IP, FLAGS. Riescono a supportare fino ad un Megabyte di memoria ed operano in modalita’ reale. In questa modalita’ un programma puo’ accedere ad ogni indirizzo di memoria, anche indirizzi utilizzati da altri programmi! Inoltre la memoria del programma e’ stata divisa in segmenti. Ogni segmento non puo’ essere piu’ grande di 64K. Le prime CPU 8086 fornivano 4 registri generali a 16 bit: AX, BX, CX e DX. Ognuno di questi registri puo’ essere scomposto in 2 registri da 8 bit. Per esempio, il registro AX puo’ essere scomposto nei due registri AH e AL. Ci sono poi 2 registri indice a 16 bit: SI e DI. Spesso sono usati come puntatori ma possono anche essere usati come i registri generici, per le stesse operazioni. A differenza di questi ultimi pero’, non possono essere decomposti in registri da 8 bit. I registri BP e SP, entrambi a 16 bit, sono usati come puntatori allo stack del linguaggio macchina e sono chiamati Base Pointer e Stack Pointer, rispettivamente. I registri a 16 bit CS, DS, SS e ES sono definiti registri di segmento. Il loro scopo principale e’ infatti quello di indicare quale memoria è usata dalle varie parti del programma. CS sta per Code Segment (segmento del Codice), DS sta per Data Segment (segmento dei dati), SS sta per Stack Segment (segmento dello stack) ed ES sta per Extra Segment. ES e’ usato principalmente come un registro di segmento temporaneo. Il registro puntatore dell’Istruzione (IP - Instruction Pointer) è usato insieme al registro CS per tenere traccia dell’indirizzo del’istruzione successiva che deve essere eseguita dalla CPU. Normalmente, quando l’istruzione è terminata, il registro IP è modificato per puntare alla successiva istruzione in memoria. Il processore 80386 e i successivi hanno esteso i registri. Per esempio il registro AX a 16 bit, è stato esteso a 32 bit. Per essere compatibile con il passato, AX ancora indica il registro a 16 bit, mentre EAX si riferisce ora al registro a 32 bit. AX rappresenta i 16 bit bassi di EAX, cosi’ come AL rappresenta gli 8 bit bassi di AX ( e EAX). Non c’e’ modo per accedere direttamente ai 16 bit alti di EAX. Gli altri registri estesi sono EBX, ECX, EDX, ESI ed EDI. Molti degli altri registri sono estensi nello stesso modo. BP diventa EBP; SP diventa ESP; FLAGS diventa EFLAGS e IP diventa EIP. C’è da notare che, diversamente dai registri indice e generali, in modalità protetta a 32 bit, questi registri vengono usati solo nella loro versione estesa. I registri segmento sono ancora a 16 bit nell’80386. Ci sono inoltre due nuovi registri: FS e GS. Il loro nome non indica nulla, ma come ES sono dei registri segmento temporanei. Memoria In modalità reale la memoria è limitata ad un solo megabyte (220 byte). Indirizzi di memoria validi vanno da (in Hex) 00000 a FFFFF (1048575). Questi indirizzi richiedono un numero a 20 bit. Ovviamente, un numero di questa dimensione non può stare in nessuno dei registri a 16 bit dell’8086. Intel ha risolto il problema utilizzando due valori da 16 bit per rappresentare l’indirizzo. Il primo valore è chiamato selettore. I valori del selettore devono essere memorizzati nei registri di segmento (Code Segment, Data Segment, Stack Segment, Extra Segment). Il secondo valore da 16 bit è chiamato offset (scostamento). L’indirizzo fisico referenziato dalla coppia (32 bit): selettore:offset è ricavato dalla formula: 16 ∗ selettore + offset Moltiplicare per 16 in esadecimale è semplice, basta aggiungere 0 a destra del numero. Per esempio, l’indirizzo fisico referenziato da: 047C:0048 è calcolato così: 047C0 + 0048 =04808 Questa segmentazione degli indirizzi ha degli svantaggi:
Nella modalità protetta a 16 bit degli 80286, i valori del selettore sono interpretati in maniera completamente differente rispetto alla modalità reale. In modalità reale, il valore del selettore è un paragrafo di memoria fisica. In modalità protetta, il valore di un selettore è un’indice in una descriptor table. In modalità protetta, i segmenti non hanno una posizione fissa nella memoria fisica, anzi: non hanno nemmeno alcun bisogno di essere in memoria! In modalità protetta, ad ogni segmento è assegnata una entry nella tavola dei descrittori. Questa entry contiene tutte le informazioni che il sistema ha bisogno di sapere sul segmento. Queste includono: se il segmento è attualmente in memoria; se in memoria, dove; permessi di accesso (es., sola lettura). L’indice di questa entry del segmento è il valore del selettore che viene memorizzato nei registri di segmento (Code Segment, Data Segment, Stack Segment, Extra Segment). La modalità protetta usa una particolare tecnica chiamata memoria virtuale. L’idea che sta alla base di questa tecnica é quella per cui il codice e i dati vengono tenuti in memoria solo quando sono in uso. I dati ed il codice che non in uso sono tenuti temporaneamente sul disco fisso, finché non diventano necessari di nuovo. Nella modalità protetta a 16 bit, i segmenti sono spostati tra memoria e disco fisso solo all’occorrenza. Quando un segmento viene caricato in memoria dal disco, è molto probabile che venga memorizzato in un’area diversa rispetto quella in cui era caricato prima di essere trasferito sul disco. Tutto ciò è fatto in maniera trasparente dal sistema operativo. Il programma non deve essere scritto diversamente per girare in modalità protetta. Un grande svantaggio della modalità protetta a 16 bit è che gli offset sono ancora a 16 bit. Di conseguenza, la dimensione dei segmenti è ancora limitata a 64K. Ciò rende problematico l’uso di array di grandi dimensioni. L’80386 introduce la modalità protetta a 32 bit. Ci sono due principali novità tra la modalità protetta a 32 bit del 386 rispetto a quella a 16 bit del 286:
|
|||||||||
PC Assembly Language | Disclaimer: questo è un link a contenuti ospitati su server esterni. |