Per chi si avvale di un sistema operativo GNU, gli strumenti per sviluppare codice per x86-16 sono costituiti dalla raccolta nota con il nome Dev86, la quale mette assieme il compilatore C Bcc,(1) l'assemblatore As86 e il «collegatore» Ld86, oltre a una libreria C adatta per produrre applicazioni per ELKS (Embeddable Linux kernel subset).
Considerato che strumenti del genere sono utili, presumibilmente, per realizzare un programma autonomo (stand alone) o il kernel di un sistema operativo, un programma di avvio facilita molto il lavoro e consente di concentrare l'attenzione su ciò che si vuole realizzare veramente. Per questo motivo, nel capitolo viene anche preso in considerazione Bootblocks per l'avvio di un sistema operativo da dischetti con file system Minix 1.
In una distribuzione GNU/Linux Debian sono disponibili i pacchetti bcc, bin86 e elks-libc che forniscono il necessario per la compilazione, ma in un altro sistema GNU può essere necessario procurarsi il pacchetto sorgente Dev86, dal quale si ottiene ciò che serve.
Se si è costretti a partire dai sorgenti di Dev86, una volta scaricato il pacchetto, questo può essere espanso in una directory qualunque nell'elaboratore GNU, come mostrato dall'esempio seguente, dove però, successivamente, si possano acquisire i privilegi dell'utente root:
$
tar xzvf Dev86src-0.16.17.tar.gz
[Invio]
Si ottiene la directory dev86-0.16.17/
che si articola ulteriormente. Terminata l'installazione occorre compilare questi sorgenti e installarli. In questo caso si prevede di installare Dev86 a partire da /opt/dev86/
:
$
cd dev86-0.16.17
[Invio]
$
make PREFIX=/opt/dev86/
[Invio]
Viene richiesto di intervenire su alcuni indicatori (flag); in generale dovrebbe andare bene ciò che viene proposto in modo predefinito:
1) (ON) Library of bcc helper functions 2) (ON) Minimal syscalls for BIOS level 3) (ON) Unix error functions 4) (ON) Management for /etc/passwd /etc/group /etc/utmp 5) (OFF) Linux-i386 system call routines GCC 6) (ON) GNU termcap routines 7) (ON) Bcc 386 floating point 8) (ON) Linux-i386 system call routines 9) (ON) Example kernel include files and syscall.dat 10) (ON) Malloc routines 11) (ON) Various unix lib functions 12) (ON) Msdos system calls 13) (ON) Regular expression lib 14) (ON) Stdio package 15) (ON) String and memory manipulation 16) (ON) Linux-8086 system call routines 17) (ON) Termios functions 18) (ON) Unix time manipulation functions. |
Select config option to flip [or quit] >
quit
[Invio]
Al termine della compilazione si passa all'installazione, cominciando dalla creazione della directory /opt/dev86/
. Per fare questo occorrono i privilegi dell'utente root:
$
su
[Invio]
...
#
mkdir -p /opt/dev86
[Invio]
#
make install
[Invio]
Bcc(2) è un compilatore C tradizionale, ovvero fatto per la vecchia sintassi, nota con la sigla K&R. Tuttavia, con l'ausilio di un programma esterno (di norma si tratta di Unproto di Wietse Venema, incluso nella distribuzione Dev86), può compilare sorgenti scritti nella forma di un C standard, pur non potendo disporre di tutte le funzionalità di un compilatore aggiornato.
bcc [opzioni] file_c... |
|
L'esempio seguente mostra la compilazione del file mio.c
, per produrre il file mio.s
, contenente il codice in linguaggio assemblatore. Per la compilazione, i file di intestazione vengono cercati esclusivamente in percorsi stabiliti: ../include
e ../../include
.
$
bcc -ansi -0 -S -o mio.s
\
\ -I -I../include -I../../include mio.c
[Invio]
L'esempio successivo è simile, ma si produce il file oggetto mio.o
:
$
bcc -ansi -0 -c -o mio.s
\
\ -I -I../include -I../../include mio.c
[Invio]
I nomi delle variabili e delle funzioni scritte in linguaggio C, si traducono nel linguaggio assemblatore in nomi preceduti dal trattino basso. Per esempio, la funzione main(), diventa il simbolo _main. Per questa ragione, quando si scrivono porzioni di codice in linguaggio assemblatore da esportare, occorre ricordare di aggiungere un trattino basso all'inizio.
A meno di voler produrre programmi per il sistema operativo ELKS, il compilatore Bcc va utilizzato con l'opzione -c, oppure -S, per poter controllare i passaggi successivi, in particolare la fase di collegamento dei vari componenti. |
As86 è un assemblatore in linguaggio x86, adatto alla compilazione di quanto prodotto da Bcc. La sintassi usata da As86 è fondamentalmente quella Intel.
as86 [opzioni] file_s |
|
L'esempio seguente rappresenta una situazione di utilizzo comune, in cui si produce il file oggetto mio.o
, a partire dal sorgente mio.s
:
$
as86 -u -0 -o mio.o mio.s
[Invio]
Come precisato a proposito di Bcc, se si devono importare dei simboli dal codice C, occorre aggiungere un trattino basso all'inizio dei nomi.
Ld86 è il «collegatore» (linker) associato a As86. La caratteristica di Ld86 è quella di poter produrre un eseguibile «impuro» (come viene definito nella sua pagina di manuale), per il quale il segmento usato dal codice è lo stesso usato per i dati (CS==DS==SS), oppure può tenere separati il codice e i dati in segmenti distinti (ma in tal caso vale ancora l'uguaglianza DS==SS).
Nella pagina di manuale di Ld86 si parla di «I&D», ovvero di istruzioni e dati, che possono essere separati o meno. |
ld86 [opzioni] file_o... |
|
L'esempio seguente mostra la creazione di un programma, privo di intestazione e di simboli, dove tutto viene così definito attraverso il codice in modo esplicito. In particolare, si presume che il file crt0.o
sia realizzato in modo da definire esattamente la forma della prima parte del file eseguibile.
$
ld86 -d -s -o kimage crt0.o body.o main.o
[Invio]
Ld86 definisce implicitamente dei simboli, raggiungibili dal codice che si scrive. Tra questi, sono molto importanti quelli seguenti, con cui è possibile determinare la collocazione in memoria del programma, distinguendo tra codice e dati:
|
In generale, la struttura di un file eseguibile prodotto da Ld86 è composta inizialmente dal codice, quindi continua con i dati inizializzati. Lo spazio dei dati non inizializzati non fa parte del file e deve essere previsto quando si carica il file in memoria, per metterlo in esecuzione; inoltre, lo stesso va fatto per la pila (stack) dei dati, la quale deve collocarsi dopo tale area.
Il pacchetto Bootblocks(3) consente di avviare un sistema per elaboratori x86-16, contenuto in un dischetto o in una partizione del disco fisso, con il kernel inserito nello stesso file system. Il pacchetto viene distribuito assieme agli strumenti di sviluppo Dev86, ma non viene compilato automaticamente assieme a quelli. Si trova precisamente nella sottodirectory bootblocks/
dei sorgenti di Dev86. Si compila in modo molto semplice con il comando make:
#
cd sorgenti_dev86/bootblocks
[Invio]
#
make
[Invio]
Dalla compilazione si ottengono diversi file e sono utili in particolare:
|
Per avviare un programma autonomo o un kernel vero e proprio, in un dischetto con file system Minix 1, è sufficiente copiare tale file in modo che si trovi nella directory principale con il nome boot
, oppure si crea la directory /boot/
e vi si colloca il file con il nome che si preferisce.
Supponendo di utilizzare un sistema GNU/Linux, supponendo di avere preparato il dischetto Minix (con i nomi al massimo di 14 byte) contenente tutto quello che serve, soprattutto con la directory /boot/
o con il file boot
, se questo dischetto risulta inserito nell'unità corrispondente al file di dispositivo /dev/fd0
, senza essere stato innestato, si può eseguire il comando seguente, tenendo conto che il programma makeboot si presume collocato in una directory prevista tra i vari percorsi della variabile di ambiente PATH:
#
makeboot minix /dev/fd0
[Invio]
Wrote sector 0 Wrote sector 1 |
Se il programma si accorge che il settore di avvio del dischetto contiene già qualcosa, si rifiuta di procedere, a meno di usare l'opzione -f:
#
makeboot -f minix /dev/fd0
[Invio]
Boot block isn't empty, zap it first Wrote sector 0 Wrote sector 1 |
È importante sapere che questo programma di avvio colloca in memoria il programma o il kernel da avviare a partire dall'indirizzo efficace 1000016. Pertanto, dopo l'avvio effettivo, rimane inutilizzato lo spazio di memoria da 0050016 0FFFF16.
Andrew S. Tanenbaum, Operating Systems: Design and Implementation, prima edizione, 1987, Prentice-Hall, ISBN 0-13-637406-9
Appendice B: introduction to the IBM PC
MAD, Assembly tutorial
Wikipedia, x86 instruction listings
The x86 Interrupt List, aka "Ralf Brown's Interrupt List", "RBIL"
Computer interrupt
http://www.ece.msstate.edu/~reese/EE3724/lectures/interrupt/interrupt.pdf
BiosCentral, BIOS data area
Robert de Bath, Linux 8086 development environment
1) Bcc, As86, Ld86 GNU GPL
2) Va specificato che si tratta del compilatore Bcc di Bruce Evans, perché con questo nome o con questa sigla si trovano più facilmente riferimenti a compilatori C diversi, per esempio quello di Borland.
3) Bootblocks GNU GPL
«a2» 2013.11.11 --- Copyright © Daniele Giacomini -- appunti2@gmail.com http://informaticalibera.net