2015-12-07 34 views
6

Ho iniziato il mio viaggio attraverso lo sviluppo del sistema operativo. La gente di solito urla che usare il binario crudo invece di ELF (o altro formato strutturato) è un errore comune per le applicazioni in un sistema operativo personalizzato. Posso secondarlo a causa dei vantaggi aggiuntivi forniti da ELF (luoghi in cui memorizzare metainformazioni come la tabella dei simboli, .debug e .line). Tuttavia, pensiamo al binario del kernel stesso per un minuto. Dovrebbe essere strutturato (come ELF) e se sì, perché? Altrimenti scrivere un caricatore ELF e schiacciarlo immediatamente dopo che lo stage1 loader sembra uno spreco.Devo creare il mio kernel ELF del sistema operativo o binario raw?

Il kernel AFAIK Linux è un file ELF ma non ne conosco il motivo.

+0

Potrebbe essere una buona domanda, ma possibili risposte su di esso sembra essere per lo più a base di parere, che non è adatto per Stack Overflow. Dal mio punto di vista, avere dimensioni minime e tempo di avvio per il kernel è buono, ma scambiare questa funzione al prezzo dei costi di sviluppo, manutenibilità, ecc vale solo quando ** la perfomance è molto molto critica **. Se è il tuo caso, sei libero di utilizzare * qualsiasi * metodo che riduce le dimensioni e il tempo di avvio del tuo kernel. – Tsyvarev

+0

@Tsyvarev, per costi di sviluppo ecc. Intendi la facilità del debugging quando le informazioni sulle righe di codice vengono memorizzate in fase di runtime? –

+1

Non solo le informazioni di debudding possono essere archiviate in ulteriori sezioni ELF. Ad esempio, il kernel di Linux usa sezioni aggiuntive per la lista dei simboli, esportata per i moduli del kernel. Inoltre, il kernel di Linux ha nozioni sulle sezioni di codice/dati '.init', che vengono caricate in memoria, ma che sono cadute dopo che l'inizializzazione è stata completata, riducendo così l'utilizzo della memoria. – Tsyvarev

risposta

10

Ho discusso se dovrei immergermi in una vasta domanda che porta a risposte convinte. Normalmente voterei per chiudere una domanda come questa, ma in questo caso offrirò una risposta che potrebbe essere di beneficio agli altri. Se chiedi Perché? Lo sto facendo per questa domanda - la cronologia ha mostrato su Stackoverflow che questa domanda viene spesso posta indirettamente come parte di una domanda di sviluppo del sistema operativo più specifica.


Alcuni vantaggi di ELF per un kernel?

  • informazioni di debug può essere incorporato nell'oggetto
  • Un ELF caricatore può impostare l'immagine nella memoria, a zero la sezione BSS automaticamente ecc
  • inizializzato a zero o dati globali inizializzati doesn' t occupare spazio all'interno dell'immagine.
  • I bootloader conformi a Multiboot (come GRUB) possono caricare gli eseguibili ELF correttamente progettati
  • Può essere progettato per essere riposizionabile.

Svantaggi?

  • intestazioni ELF vengono collocati all'inizio dell'eseguibile che possono interferire con l'ambiente bersaglio l'eseguibile verrà eseguito in (come bootloaders)
  • Per piccoli programmi le intestazioni ELF possono essere troppo grandi per alcuni utilizzi (bootloaders)
  • Richiede il codice (caricatore ELF minimo) per eseguire il boot di un eseguibile in memoria e avviare l'esecuzione.

Perché non usiamo ELF per un'immagine finale settore di avvio (MBR)?

Il motivo principale è che il formato ELF inserisce le informazioni di intestazione prima del codice. I BIOS legacy (non EFI) non lo capiranno e inizieranno a eseguire le informazioni dell'intestazione come codice.


Potete utilizzare le immagini ELF per il debug a 16 bit bootloader?

Dipende dall'ambiente e dal debugger. Con il comando remoto GDB debug in QEMU questo è molto possibile. È possibile generare un eseguibile modalità reale a 16 bit in un assemblatore come NASM/GAS ecc come un oggetto ELF (con Nano informazioni di debug), collegarlo a un eseguibile ELF finale e quindi utilizzare un programma come objcopy per rimuovere le intestazioni ELF per generare l'ultimo binario piatto.

Perché preoccuparsi di generare oggetti ELF per un bootloader se lo si riduce a un binario piatto comunque?

Anche se un binario ridotta verrà eseguito nell'ambiente di destinazione, un ambiente con funzionalità di debug remoto come QEMU può utilizzare un binario ELF locale per risolvere i nomi di variabili, etichette, costanti, e consentire la fonte originale per essere navigato (non solo assemblaggio grezzo).

È possibile fornire un esempio di questa tecnica per il debug a 16 bit?

Sì, questo tipo di problema è già emerso. Ho fornito risposte che mostrano come eseguire questa operazione con i servizi di debug remoto di GDB e il debugger remoto in QEMU. Uno di questi esempi è disponibile in questo StackOverflow answer. L'esempio è un bootloader di esempio a 16 bit che può essere sottoposto a debug con GDB. Il debugging a 16 bit è problematico con GDB poiché non ha alcuna comprensione del segmento: coppie di offset nel codice a 16 bit. Viene fornito un collegamento a uno script che aiuta in merito, insieme con l'esempio QEMU utilizzo.


C'è un vantaggio per eseguibile ELF quando viene utilizzato con un caricatore ad avvio multiplo?

Sì! Un grande vantaggio per i bootloader conformi a Multiboot come GRUB è che comprende le immagini ELF. Se si sta scrivendo un kernel in modalità protetta e si utilizza un eseguibile compatibile con Multiboot per il proprio kernel, è possibile salvare sul drudgery (su sistemi x86) l'impostazione dell'ambiente protetto, l'abilitazione A20 Gate, ottenere una mappa di memoria e inizializzando la modalità di modalità video di avvio.

QEMU può avviare direttamente un eseguibile del kernel ELF compatibile con Multiboot?

Sì, con la riga di comando corretta utilizzando l'opzione -kernel è possibile. OS Dev Wiki ha un esempio.

È possibile eseguire il debug della modalità protetta a 32 bit utilizzando i binari ELF con informazioni di debug?

Sì, questo è più semplice di farlo per bootloader a 16 bit in esecuzione in modalità reale. Offro un esempio di questa tecnica in questo StackOverflow answer. Sebbene la tecnica sia per QEMU utilizzando un'immagine ISO, è possibile caricare in alternativa QEMU con il proprio kernel multiboot direttamente utilizzando l'opzione -kernel.


Perché fanno le versioni moderne di Linux utilizzano il formato ELF per il kernel?

Nei tempi antichi dello sviluppo Linux, Linux disponeva di un proprio bootloader, impostava la modalità protetta, abilitava la porta A20, ecc. Questo processo è diverso tra le architetture. È arrivato un punto in cui gli sviluppatori del kernel di Linux hanno scelto di lasciare il lavoro su un bootloader di terze parti.

Sui moderni sistemi desktop si trova GRUB utilizzato come caricatore Muliboot; ELILO può essere utilizzato; su alcuni sistemi integrati U-Boot è diventato un bootloader di scelta. Le specifiche Multiboot sono nate dalla necessità di avviare un kernel Linux, ma farlo indipendentemente dal sistema operativo. Molti esempi di kernel di giocattoli su Internet sono codificati per essere usati come eseguibili ELF in modo che possano trarre vantaggio da ciò che i bootloader conformi a Multiboot hanno da offrire.

più sulla specifica Multiboot può essere trovato nel GRUB Documentation

+0

Una spiegazione meravigliosa e completa, grazie, signore! –

1

a.out può essere un compromesso migliore tra raw/flat binary e ELF. In aout è possibile separare il codice dai dati non inizializzati proprio come in ELF e si possono avere rilocazioni (e simboli, se ci si interessa), nessuno dei quali si ottiene in un binario raw/piatto senza reinventarne esplicitamente parte. Tuttavia, a.out è molto più semplice di ELF, quasi semplice come grezzo/piatto. Molto facile da analizzare e caricare (a meno che non lo si stia facendo nel codice assembly a 16 bit come ho fatto nello stub DPMI del mio compilatore :).