Dal codice sorgente al codice binario
La programmazione inizia con un'idea intelligente e scrivendo il codice sorgente in un linguaggio di programmazione di tua scelta, ad esempio C e salvare il codice sorgente in un file. Con l'aiuto di un compilatore adeguato, ad esempio GCC, il codice sorgente viene tradotto in codice oggetto, prima. Alla fine, il linker traduce il codice oggetto in un file binario che collega il codice oggetto con le librerie di riferimento. Questo file contiene le singole istruzioni come codice macchina compreso dalla CPU e viene eseguito non appena viene eseguito il programma compilato.
Il file binario sopra menzionato segue una struttura specifica e uno dei più comuni è chiamato elfo che abbrevia il formato eseguibile e collegabile. È ampiamente utilizzato per file eseguibili, file di oggetti trasferibili, librerie condivise e dump core.
Venti anni fa - Nel 1999 - Il progetto 86open ha scelto ELF come formato di file binario standard per sistemi unix e unix su processori X86. Fortunatamente, il formato ELF era stato precedentemente documentato sia nell'interfaccia binaria dell'applicazione di System V, sia nello standard dell'interfaccia dello strumento [4]. Questo fatto ha semplificato enormemente l'accordo sulla standardizzazione tra i diversi fornitori e gli sviluppatori di sistemi operativi basati su Unix.
Il motivo alla base di tale decisione è stato la progettazione di elfo: flessibilità, estensibilità e supporto multipiattaforma per diversi formati endian e dimensioni degli indirizzi. La progettazione di Elf non si limita a un processore specifico, set di istruzioni o architettura hardware. Per un confronto dettagliato dei formati di file eseguibili, dai un'occhiata qui [3].
Da allora, il formato ELF è in uso da diversi sistemi operativi. Tra gli altri, questo include Linux, Solaris/Illumos, Free-, Net- e OpenBSD, QNX, BeoS/Haiku e Fuchsia OS [2]. Inoltre, lo troverai su dispositivi mobili che eseguono Android, Maemo o Meego OS/Sailfish OS, nonché su console di gioco come PlayStation Portable, Dreamcast e Wii.
La specifica non chiarisce l'estensione del nome file per i file ELF. In uso è una varietà di combinazioni di lettere, come .axf, .bidone, .elfo, .o, .PRX, .sbuffo, .ko, .così e .mod o nessuno.
La struttura di un file elfo
Su un terminal Linux, il comando elfo ti dà un utile riassunto sulla struttura di un file ELF:
Elenco 1: la manpazza della struttura degli elfi
$ uomo elfoCome puoi vedere dalla descrizione sopra, un file ELF è costituito da due sezioni: un'intestazione ELF e dati di file. La sezione dei dati dei file può essere costituita da una tabella di intestazione del programma che descrive zero o più segmenti, una tabella di intestazione della sezione che descrive zero o più sezioni, seguite da dati a cui si fa riferimento dalle voci dalla tabella dell'intestazione del programma e dalla tabella dell'intestazione della sezione. Ogni segmento contiene informazioni necessarie per l'esecuzione del tempo del file, mentre le sezioni contengono dati importanti per il collegamento e il trasferimento. La Figura 1 lo illustra schematicamente.
L'intestazione degli elfi
L'intestazione ELF è lunga 32 byte e identifica il formato del file. Si inizia con una sequenza di quattro byte unici che sono 0x7f seguiti da 0x45, 0x4c e 0x46 che si traduce nelle tre lettere E, L e F. Tra gli altri valori, l'intestazione indica anche se si tratta di un file ELF per un formato a 32 o 64 bit, utilizza poca o grande endianness, mostra la versione ELF e per il quale il sistema operativo è stato compilato per interagire con il Set di istruzioni binarie per applicazioni destra (ABI) e CPU.
L'esdump del tocco binario sembra segue:
.Elenco 2: L'hexdump del file binario
$ hd/usr/bin/touch | Testa -5Debian GNU/Linux offre il comando readelf fornito nel pacchetto GNU "Binutils". Accompagnato da Switch -H (versione breve per "-File-Header") Visualizza bene l'intestazione di un file ELF. La lista 3 lo illustra per il comando.
.Elenco 3: visualizzazione dell'intestazione di un file ELF
$ readelf -h/usr/bin/touchL'intestazione del programma
L'intestazione del programma mostra i segmenti utilizzati in fase di esecuzione e indica al sistema come creare un'immagine di processo. L'intestazione dall'elenco 2 mostra che il file elfo è composto da 9 intestazioni del programma che hanno una dimensione di 56 byte ciascuno e la prima intestazione inizia al byte 64.
Ancora una volta, il comando Readelf aiuta a estrarre le informazioni dal file ELF. Lo switch -L (corto per -program -headers o -segments) rivela maggiori dettagli come mostrato nell'elenco 4.
.Elenco 4: visualizzare le informazioni sulle intestazioni del programma
$ readelf -l/usr/bin/touchL'intestazione della sezione
La terza parte della struttura degli elfo è l'intestazione della sezione. Ha lo scopo di elencare le singole sezioni del binario. Lo switch -s (corto per le sezioni di sezione o -sezioni) elenca le diverse intestazioni. Per quanto riguarda il comando touch, ci sono 27 intestazioni di sezione e l'elenco 5 mostra i primi quattro più l'ultimo, solo. Ogni riga copre la dimensione della sezione, il tipo di sezione, nonché il suo indirizzo e offset di memoria.
.Elenco 5: Dettagli della sezione rivelati da Readelf
$ readelf -s/usr/bin/touchStrumenti per analizzare un file elfo
Come avrai notato dagli esempi sopra, GNU/Linux è arricchito con una serie di strumenti utili che ti aiutano ad analizzare un file ELF. Il primo candidato che daremo un'occhiata è l'utilità del file.
Il file visualizza le informazioni di base sui file ELF, inclusa l'architettura impostata per le istruzioni per la quale il codice in un file di oggetti trasferibile, eseguibile o condiviso è previsto. Nell'elenco 6 dice che/bin/touch è un file eseguibile a 64 bit seguendo la base standard Linux (LSB), dinamicamente collegata e costruita per il kernel GNU/Linux versione 2.6.32.
.Elenco 6: Informazioni di base utilizzando il file
$ file /bin /touchIl secondo candidato è letto. Visualizza informazioni dettagliate su un file ELF. L'elenco degli switch è relativamente lungo e copre tutti gli aspetti del formato ELF. Utilizzando lo switch -n (breve per -note) Listato 7 mostra solo le sezioni Note, che esistono nel tocco del file: il tag versione ABI e la stringa di build ID.
.Elenco 7: visualizzare le sezioni selezionate di un file ELF
$ readelf -n/usr/bin/touchSi noti che sotto Solaris e FreeBSD, l'Elfdump dell'utilità [7] corrisponde a Readelf. A partire dal 2019, non c'è stata una nuova versione o aggiornamento dal 2003.
Il numero tre è il pacchetto denominato Elfutils [6] che è puramente disponibile per Linux. Fornisce strumenti alternativi ai binutili GNU e consente anche di convalidare i file ELF. Si noti che tutti i nomi delle utility fornite nel pacchetto iniziano con l'UE per "Elf Utils".
Ultimo ma non meno importante menzionare Objdump. Questo strumento è simile al lettura ma si concentra su file di oggetti. Fornisce una gamma simile di informazioni sui file ELF e su altri formati di oggetti.
.Elenco 8: Informazioni sul file estratte da Objdump
$ objdump -f /bin /touchEsiste anche un pacchetto software chiamato "Elfkickers" [9] che contiene strumenti per leggere il contenuto di un file ELF e manipolarlo. Sfortunatamente, il numero di versioni è piuttosto basso, ed è per questo che lo menzioniamo e non mostriamo ulteriori esempi.
Come sviluppatore potresti dare un'occhiata a "Pax-Utils" [10,11]. Questo set di utility fornisce una serie di strumenti che aiutano a convalidare i file ELF. Ad esempio, Dumpelf analizza il file ELF e restituisce un file di intestazione C contenente i dettagli - vedere la Figura 2.
Grazie a una combinazione di design intelligente e documentazione eccellente il formato Elfo funziona molto bene ed è ancora in uso dopo 20 anni. Le utility mostrate sopra consentono una vista di approfondimento in un file elfo e ti consentono di capire cosa sta facendo un programma. Questi sono i primi passi per l'analisi del software - Happy Hacking!
Lo scrittore desidera ringraziare Axel Beckert per il suo sostegno riguardo alla preparazione di questo articolo.