successivo
precedente
inizio
fine
indice generale
aiuto
indice analitico
volume
parte
TXT
HTML
PDF
pdf
gdoc
P4
Directory di lavoro
bochs
u192
compile
u0.1
linker.ld
u0.2
makeit
u0.1
mount
u192
umount
u192
Prima di iniziare gli esperimenti, si predispone una directory di lavoro, da utilizzare in qualità di utente comune. Nella directory si copia il file floppy.img
e si mettono alcuni script molto semplici:
Listato u192.1. ./mount
#!/bin/sh
chmod a+rw floppy.img
su root -c "mount -o loop,uid=1001 -t vfat floppy.img /mnt/fd0"
|
|
Listato u192.2. ./umount
#!/bin/sh
su root -c "umount /mnt/fd0"
|
|
Listato u192.3. ./bochs
#!/bin/sh
bochs -q 'boot:a' 'floppya: 1_44=floppy.img, status=inserted' 'megs:32'
|
|
Il senso di questi script è evidente e il loro scopo è solo quello di ridurre al minimo l'impegno di digitazione. In questa directory viene poi predisposto anche lo script compile, ma viene descritto nella sezione successiva.
Directory «05/»
A partire dalla directory di lavoro si crea la sottodirectory 05/
, nella quale viene poi messo il codice del sistema che si va a creare. Ma per evitare di fare confusione con i file-make, si predispone uno script per la compilazione che li crea al volo, in base ai contenuti effettivi delle sottodirectory.
Listato u192.4. ./05/makeit
#!/bin/sh
#
# makeit...
#
OPTION="$1"
#
edition () {
local EDITION="include/kernel/build.h"
echo -n > $EDITION
echo -n "#define BUILD_DATE \"" >> $EDITION
echo -n `date "+%Y%m%d%H%M%S"` >> $EDITION
echo "\"" >> $EDITION
}
#
#
#
makefile () {
#
local MAKEFILE="Makefile"
local TAB=" "
#
local SOURCE_C=""
local C=""
local SOURCE_S=""
local S=""
#
local c
local s
#
# Trova i file in C.
#
for c in *.c
do
if [ -f $c ]
then
C=`basename $c .c`
SOURCE_C="$SOURCE_C $C"
fi
done
#
# Trova i file in ASM.
#
for s in *.s
do
if [ -f $s ]
then
S=`basename $s .s`
SOURCE_S="$SOURCE_S $S"
fi
done
#
# Prepara il file make.
#
echo -n > $MAKEFILE
echo "# Questo file è stato prodotto automaticamente" >> $MAKEFILE
echo "# dallo script \"makeit\", sulla base dei" >> $MAKEFILE
echo "# contenuti della directory." >> $MAKEFILE
echo "#" >> $MAKEFILE
echo "c = $SOURCE_C" >> $MAKEFILE
echo "#" >> $MAKEFILE
echo "s = $SOURCE_S" >> $MAKEFILE
echo "#" >> $MAKEFILE
echo "all: \$(s) \$(c)" >> $MAKEFILE
echo "#" >> $MAKEFILE
echo "clean:" >> $MAKEFILE
echo "${TAB}@rm *.o 2> /dev/null ; pwd" >> $MAKEFILE
echo "#" >> $MAKEFILE
echo "\$(s):" >> $MAKEFILE
echo "${TAB}@echo \$@.s" >> $MAKEFILE
echo "${TAB}@as -o \$@.o \$@.s" >> $MAKEFILE
echo "#" >> $MAKEFILE
echo "\$(c):" >> $MAKEFILE
echo "${TAB}@echo \$@.c" >> $MAKEFILE
echo "${TAB}@gcc -Wall -Werror -o \$@.o -c \$@.c" \
"-nostdinc -nostdlib -nostartfiles -nodefaultlibs" \
"-I../include -I../../include -I../../../include" >> $MAKEFILE
#
}
#
#
#
main () {
#
local CURDIR=`pwd`
local OBJECTS
local d
local c
local s
local o
#
edition
#
for d in `find .`
do
if [ -d "$d" ]
then
#
# Ci sono sorgenti in C o in ASM?
#
c=`echo $d/*.c | sed "s/ .*//"`
s=`echo $d/*.s | sed "s/ .*//"`
#
if [ -f "$c" ] || [ -f "$s" ]
then
CURDIR=`pwd`
cd $d
makefile
#
if [ "$OPTION" = "clean" ]
then
make clean
else
if ! make
then
cd "$CURDIR"
exit
fi
fi
cd "$CURDIR"
fi
fi
done
#
cd "$CURDIR"
#
#
#
if [ "$OPTION" = "clean" ]
then
true
else
OBJECTS=""
#
for o in `find . -name \*.o -print`
do
if [ "$o" = "./kernel/kernel_boot.o" ] \
|| [ "$o" = "./kernel/kernel_main.o" ] \
|| [ ! -e "$o" ]
then
true
else
OBJECTS="$OBJECTS $o"
fi
done
#
echo "Link"
#
ld --script=linker.ld -o kernel_image \
kernel/kernel_boot.o \
$OBJECTS \
kernel/kernel_main.o
#
cp -f kernel_image /mnt/fd0/kernel
sync
fi
}
#
# Start.
#
if [ -d include ] && [ -d kernel ] && [ -d lib ]
then
main
else
echo "Mi trovo in una posizione sbagliata e non posso svolgere" \
"il mio compito"
fi
|
|
Va osservato che la variabile TAB deve contenere esattamente una tabulazione orizzontale (di norma il codice 0916. Pertanto, se si riproduce il file o se lo si scarica, occorre verificare che il contenuto sia effettivamente una tabulazione, altrimenti va corretto. Se la variabile TAB contiene solo spazi, i file-make che si ottengono non sono validi.
local TAB=" "
|
In pratica, attraverso questo script, i file-make che si generano hanno un aspetto simile a quello del listato seguente:
c = elenco_file_c_senza_estensione
#
s = elenco_file_asm_senza_estensione
#
all: $(s) $(c)
#
clean:
@rm *.o 2> /dev/null ; pwd
#
$(s):
@echo $@.s
@as -o $@.o $@.s
#
$(c):
@echo $@.c
@gcc -Wall -Werror -o $@.o -c $@.c \ \ -nostdinc -nostdlib -nostartfiles \ \ -nodefaultlibs -I../include \ \ -I../../include -I../../../include
|
|
Il «collegamento» (link) dei file avviene attraverso un comando contenuto nello script makeit, dove si fa in modo di mettere all'inizio il file-oggetto che è responsabile dell'avvio, dal momento che contiene l'impronta di riconoscimento per il sistema di avvio aderente alle specifiche multiboot.
Nella directory di lavoro descritta nella sezione precedente, conviene mettere uno script che richiami a sua volta makeit e che provveda a copiare il file del kernel nel file-immagine del dischetto:
Listato u192.6. ./compile
#!/bin/sh
cd 05
./makeit clean
./makeit
cd ..
|
|
Script di collegamento
Sempre all'interno della directory 05/
va predisposto lo script usato da GNU LD per eseguire correttamente il collegamento dei file oggetto in un file eseguibile unico. Dal momento che nel progetto che si intraprende si intende usare la memoria linearmente, si intende che il blocco minimo sia della dimensione di un registro, ovvero pari a 4 byte:
Listato u192.7. ./05/linker.ld
/***********************************************************************
* La memoria viene usata in modo lineare, senza controlli dei
* privilegi, così non si usano nemmeno gli allineamenti tradizionali
* di 4096 byte, ma solo di 4 byte, ovvero di un registro.
***********************************************************************/
ENTRY (kernel_boot)
SECTIONS {
. = 0x00100000;
k_mem_total_s = .;
.text : {
k_mem_text_s = .;
*(.text)
. = ALIGN (0x4);
k_mem_text_e = .;
}
.rodata : {
k_mem_rodata_s = .;
*(.rodata)
. = ALIGN (0x4);
k_mem_rodata_e = .;
}
.data : {
k_mem_data_s = .;
*(.data)
. = ALIGN (0x4);
k_mem_data_e = .;
}
.bss : {
k_mem_bss_s = .;
*(.bss)
*(COMMON)
. = ALIGN (0x4);
k_mem_bss_e = .;
}
k_mem_total_e = .;
}
|
|
Il codice contenuto nel file del kernel che si va a produrre, deve iniziare a partire da 0010000016, ovvero da 1 Mibyte, come prescrive il sistema di avvio multiboot, il quale va a collocarlo in memoria, a partire da quella posizione. Inoltre, per consentire di individuare i blocchi di memoria utilizzati, vengono inseriti dei simboli; per esempio, k_mem_total_s individua l'inizio del kernel, mentre k_mem_total_e ne individua la fine.
Si dà per scontato che GNU AS predisponga un file eseguibile in formato ELF.
Altre directory
All'interno di 05/
si creano ancora: lib/
, per la libreria standard e altre librerie specifiche del sistema; include/
, per i file di intestazione della libreria; kernel/
con i file iniziali usati dal kernel; app/
per le applicazioni (ovvero le funzioni avviate dal kernel quando tutto è pronto).
«a2» 2013.11.11 --- Copyright © Daniele Giacomini -- appunti2@gmail.com http://informaticalibera.net