È il modo preferito.
Controllate la documentazione di GCC e gli esempi dai file .S
del kernel di Linux che passano attraverso gas (non quelli che passano
attraverso as86).
Gli argomenti a 32 bit vengono posti sullo stack (push) in ordine inverso
rispetto alla sintassi (per cui vi si accede prelevandoli
nell'ordine corretto) sopra l'indirizzo di ritorno a 32 bit.
%ebp
, %esi
,
%edi
, %ebx
sono salvati dalla funzione chiamata,
gli altri dalla funzione chiamante;
per contenere il risultato si usa %eax
,
oppure %edx:%eax
per risultati a 64 bit.
Stack FP: non ne sono certo, ma penso che il risultato vada
in st(0)
e che l'intero stack sia salvato dalla funzione chiamante.
Notate che GCC ha delle opzioni per modificare le convenzioni di chiamata
riservando registri, per mettere argomenti nei registri, per non
fare supposizioni sulla presenza dell'FPU, ecc.
Controllate le pagine .info i386 .
Fate attenzione: in questo caso dovete dichiarare l'attributo decl
per una funzione che seguirà le convenzioni di chiamata
standard di GCC (non so cosa faccia con le convenzioni di chiamata modificate).
Leggete le pagine info di GCC nella sezione:
C Extensions::Extended Asm::
Alcuni compilatori C antepongono un underscore prima di ogni simbolo, mentre altri non lo fanno.
In particolare, GCC a.out per Linux effettua questa anteposizione, mentre GCC ELF per Linux no.
Se avete bisogno di gestire insieme entrambi i comportamenti, guardate come fanno i pacchetti esistenti. Ad esempio, procuratevi dei vecchi sorgenti di Linux, Elk, qthreads, o OCAML...
Potete inoltre far ignorare la rinominazione implicita C->
asm
inserendo istruzioni come
void pippo asm("pluto") (void);
Notate che il programma di utilità objcopy
, dal pacchetto
binutils
, dovrebbe permettervi di trasformare i vostri oggetti
a.out in oggetti ELF e forse anche viceversa, in alcuni casi.
Più in generale, effettuerà un gran numero di conversioni
di formato dei file.
Ciò è espressamente NON consigliato,
poiché le convenzioni cambiano di tanto in tanto
o tra varianti del kernel (vedere L4Linux),
inoltre si perde la portabilità, comporta un lavoro
di scrittura massiccio, si ha ridondanza con gli sforzi di libc ED INOLTRE
preclude estensioni e correzioni apportate a libc come, ad esempio,
il pacchetto zlibc
, che provvede ad una trasparente decompressione
«al volo» di file compressi con gzip.
Il metodo convenzionale e consigliato per chiamare i servizi di sistema
di Linux è, e rimarrà, quello di passare attraverso la libc.
Gli oggetti condivisi dovrebbero mantenere la vostra roba entro
dimensioni contenute.
E se proprio volete binari più piccoli, utilizzate #!
e scaricate sull'interprete il fardello che volete togliere dai vostri
binari.
Ora, se per qualche ragione non volete fare un link alla libc, procuratevi la libc stessa e capite come funziona! Dopotutto, aspirate a sostituirla, no?
Potreste inoltre dare un'occhiata a come il mio eforth 1.0c lo fa.
Anche i sorgenti di Linux tornano utili, in particolare l'header file asm/unistd.h, che descrive come effettuare le chiamate di sistema...
Fondamentalmente, generate un int $0x80
,
con il numero associato a __NR_
nomedellasyscall
(da asm/unistd.h
) in %eax
,
ed i parametri (fino a cinque) in
%ebx
, %ecx
, %edx
,
%esi
, %edi
rispettivamente.
Il risultato viene restituito in %eax
,
dove un numero negativo è un errore
il cui opposto è ciò che libc metterebbe in errno.
Lo stack utente non viene toccato,
così non è necessario averne uno valido quando effettuate
una chiamata di sistema.
Se volete effettuare dell'I/O sotto Linux,
o si tratta di qualcosa di molto semplice che non richiede l'arbitraggio
del sistema operativo, e allora dovreste consultare
l'IO-Port-Programming mini-HOWTO
,
oppure ha bisogno di un driver di periferica nel kernel, nel qual
caso dovreste provare ad approfondire le vostre conoscenze sull'hacking
del kernel, sullo sviluppo di driver di periferica, sui moduli del
kernel, ecc., per i quali ci sono altri
eccellenti HOWTO e documenti del LDP.
In particolare, se ciò che vi interessa è la programmazione della grafica, allora partecipate al progetto GGI: http://synergy.caltech.edu/~ggi/ http://sunserver1.rz.uni-duesseldorf.de/~becka/doc/scrdrv.html
Comunque, in tutti questi casi, fareste meglio ad usare l'assembly inline di GCC con le macro da linux/asm/*.h piuttosto che scrivere file sorgenti completamente in assembly.
Ciò è teoricamente possibile (dimostrazione: guardate come DOSEMU riesca a garantire ai programmi un accesso a porte hardware in modo selettivo), ed ho anche sentito voci secondo le quali qualcuno da qualche parte ci sarebbe di fatto riuscito (nel driver PCI? Roba per l'accesso VESA? ISA PnP? Non so). Se avete informazioni più precise a riguardo, siate i benvenuti. Comunque, buoni posti in cui cercare maggiori informazioni sono i sorgenti del kernel di Linux, i sorgenti di DOSEMU (ed altri programmi nel DOSEMU repository), e sorgenti di vari programmi a basso livello sotto Linux... (forse GGI se supporta VESA). Fondamentalmente, dovete usare la modalità protetta a 16 bit o il modo vm86.
Il primo è più semplice da mettere in piedi, ma funziona solamente con codice «educato» (well-behaved) che non utilizza l'aritmetica dei segmenti o indirizzamento assoluto degli stessi (segmento 0 in particolare), a meno che non ci si trovi nel caso in cui tutti i segmenti utilizzati possano essere preparati in anticipo nella LDT.
Il secondo permette più «compatibilità» con i comuni ambienti a 16 bit, ma richiede una gestione più complessa.
In entrambi i casi, prima di poter saltare al codice a 16 bit, dovete
Ancora una volta, leggete con cura i sorgenti dei contributi al DOSEMU repository menzionato sopra, in particolare quei mini-emulatori per far girare ELKS e/o semplici programmi .COM sotto Linux/i386.
La maggior parte dei DOS extender viene fornita con dell'interfacciamento
a servizi DOS.
Leggete la loro documentazione a riguardo, ma spesso si limitano a simulare
int $0x21
e simili, così vi comportate «come se»
foste in modo reale
(dubito che abbiano qualcosa di più di stub
ed estensioni per lavorare con operandi a 32 bit;
molto probabilmente si limiteranno a riportare l'interrupt
nel gestore del modo reale o del vm86).
Documentazione su DPMI e affini (e molto più) può essere trovata in ftp://x2ftp.oulu.fi/pub/msdos/programming/
Anche DJGPP viene fornito con il proprio derivato/sottoinsieme/sostituto di glibc.
È possibile la compilazione incrociata da Linux a DOS, guardate nella directory devel/msdos/ del vostro mirror locale dell'area FTP di sunsite.unc.edu Date anche un'occhiata al DOS extender «MOSS» dal progetto Flux in Utah.
Altri documenti e FAQ sono molto DOS-centrici. Noi non consigliamo di sviluppare per DOS.
Ehi, questo documento riguarda solo il software libero. Telefonatemi quando Winzozz diventa libero, o ci si possono usare strumenti di sviluppo liberi!
Beh, dopotutto ci sono: Cygnus Solutions ha sviluppato la libreria cygwin32.dll per far girare i programmi GNU su piattaforme Micrashoft. Così potete usare GCC, GAS, tutti gli strumenti di GNU e molte altre applicazioni UNIX. Date un'occhiata alla loro homepage. Io (Faré) non intendo dilungarmi sulla programmazione di WinnaNanna ma sono certo che potete trovare un sacco di documentazione a riguardo praticamente ovunque...
Essendo il controllo ciò che attrae molti programmatori all'assembly, il desiderio di sviluppare sistemi operativi è spesso ciò che li porta all'(o deriva dall') hacking in assembly. Va notato che ogni sistema che permette lo sviluppo di se stesso potrebbe essere considerato un «sistema operativo», anche se magari gira «sopra» ad un sistema sottostante che fornisce multitasking o I/O (in modo molto simile a Linux sopra Mach o OpenGenera sopra UNIX), ecc.
Quindi, per rendere più facile il debugging, potreste voler sviluppare il vostro «sistema operativo» prima come processo che gira sopra a Linux (nonostante la lentezza), quindi usare il Flux OS kit (che consente l'utilizzo di driver di Linux e BSD nel vostro OS) per renderlo autonomo. Quando il vostro sistema è stabile, resta ancora del tempo per scrivere dei driver per l'hardware tutti vostri, se la cosa vi fa proprio piacere.
Questo HOWTO non si occuperà di argomenti quali il codice per il boot loader ed entrare nel modo a 32 bit, gestire gli interrupt, i fondamenti degli orrori intel «modo protetto» o «V86/R86», la definizione di un vostro formato per i file oggetto e le convenzioni di chiamata. Il luogo principale in cui trovare informazioni attendibili a riguardo sono i sorgenti di sistemi operativi o bootloader già esistenti. Ci sono un sacco di riferimenti in questa pagina WWW: http://www.eleves.ens.fr:8080/home/rideau/Tunes/Review/OSes.html