Torna indietro   Hardware Upgrade Forum > Software > Programmazione > Corsi, Tutorial e FAQ

NVIDIA Blackwell B200: due chip in uno per rivoluzionare l'intelligenza artificiale
NVIDIA Blackwell B200: due chip in uno per rivoluzionare l'intelligenza artificiale
Due GPU (die) su un unico package per un totale di 208 miliardi di transistor: la nuova GPU Blackwell di NVIDIA nasce per accelerare l'innovazione nel campo dell'intelligenza artificiale come mai prima d'ora. La nuova proposta è accompagnata da 192 GB di memoria HBM3E per una bandwidth di 8 TB/s. A comporre la nuova offerta di NVIDIA troviamo tre soluzioni: B100, B200 e GB200.
HP Envy Move, un PC All-In-One con la batteria che si può spostare facilmente
HP Envy Move, un PC All-In-One con la batteria che si può spostare facilmente
HP Envy Move non è un PC all-in-one come tutti gli altri: si può spostare facilmente e usare lontano dalla presa di corrente. Lo schermo touch consente di usarlo anche come un grande tablet e può diventare un display aggiuntivo. Il tutto condito da un'attenzione all'ambiente grazie all'uso di materiali riciclati.
MSI MPG 321URX QD-OLED: un monitor completo per i giocatori
MSI MPG 321URX QD-OLED: un monitor completo per i giocatori
MSI MPG 321URX QD-OLED è un monitor completo, con diagonale da 32 pollici, risoluzione UHD, porte HDMI 2.1, frequenza di aggiornamento di 240 Hz e con un pannello OLED che offre diverse caratteristiche interessanti per il pubblico dei giocatori
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 25-06-2010, 14:48   #1
Teo@Unix
Senior Member
 
L'Avatar di Teo@Unix
 
Iscritto dal: Mar 2009
Messaggi: 753
[Guida] Formato ELF

Data la mancanza di documentazione in italiano su questo argomento, (invece tanta ne ho trovata del formato PE) ho pensato di pubblicare questa raccolta di appunti sul formato file "ELF", nella speranza sia utile a qualcuno.

Buona lettura.

*******************************************************************************


..:: The Exutable and Linkable Format ::..

## Low level programming - Linux internals ##


... Uno degli aspetti più belli e più importanti delle cose è proprio il loro funzionamento interno ...

~ Index ~

[0x01] Che cos'è un file elf? - Macro analisi
[0x02] ELF Header
[0x03] Sezioni
[0x04] Tabella delle stringhe
[0x05] Tabella dei simboli
[0x06] Rilocazione
[0x07] Program header
[0x08] Collegamento dinamico
[0x09] Tabella hash
[0x0a] Funzioni di iniziazione e di terminazione
[0x0b] Riferimenti


0x01) Si tratta di un formato di file adottato dai sistemi Unix-like per eseguibili, librerie e file oggetto.
Un elf è composto nella maggior parte dei casi da sezioni e segmenti. I segmenti contengono le informazioni necessarie per l'esecuzione del file, le sezioni invece contengono dati importanti per il linking e la rilocazione.
Un file rilocabile mantiene codice e dati disponibili per il linking con altri file oggetto per creare file eseguibili o file oggetto condivisi.
Un file eseguibile rappresenta un'applicazione. Questo viene utilizzato come argomento della funzione execve() per creare una nuova immagine di processo.
Mentre un file oggetto condiviso può avere due scopi; può essere linkato con altri file oggetto o file oggetto condivisi al fine di creare altri file oggetto. Oppure viene utilizzato dal dynamic linker per creare assieme all'eseguibile l'immagine di processo.

Altri oggetti come gli script non rientrano affatto tra gli elementi che adottano questo formato.
Il formato elf è creato esclusivamente da un assemblatore a fronte di una compilazione dei sorgenti.

Linux ci mette a disposizione gli strumenti necessari per poter visualizzare il contenuto sia dell'header che delle sezioni del file elf.
Prima di usare questi strumenti dedicati, analizziamo cosa è contenuto nel file elf nei primi byte, utilizziamo il comando seguente:
(most è un programma per la visualizzazione di lunghi testi nella shell, a.out è un qualsiasi eseguibile elf)

Codice:
root@saturn:~# cat a.out | most
0x00000000: 7F454C46 01010100 00000000 00000000     .ELF............
0x00000010: 02000300 01000000 40830408 34000000     ........@...4...
0x00000020: 54190000 00000000 34002000 08002800     T.......4. ...(.
0x00000030: 26002300 06000000 34000000 34800408     &.#.....4...4...
0x00000040: 34800408 00010000 00010000 05000000     4...............
	....
Sulla parte sinistra sono riportati i riferimenti offset del file. Parte restante riguarda il contenuto del file codificato in esadecimale e, ancora più a destra in ASCII. In quest'ultima codifica è possibile riconoscere varie stringhe, ad esempio quelle dichiarate nel sorgente.
Quello che balza all'occhio sono i primissimi byte, "ELF". Il "magic number".

Vediamo il formato di un file elf a grandi linee, questo è interpretato in modi differenti a seconda della situazione. Difatti questo può essere utilizzato durante la fase di linking o durante la fase di esecuzione effettiva di un programma.

Codice HTML:
    /--------------------\              /--------------------\
    |   ELF Header       |              |   ELF Header       |
     --------------------                --------------------
    |   Program header   |              |   Program header   |
    |   table (Optional) |              |   table(Required)  |
     --------------------                --------------------
    |     Section 1      |              |     Segment 1      |
     --------------------                --------------------
    |       ...          |              |     Segment 2      |
     --------------------                --------------------
    |     Section n      |              |     Segment 3      |
     --------------------                --------------------
    |       ...          |              |       ...          |
     --------------------                --------------------
    |   Section header   |              |   Section header   |
    |   table(Required)  |              |   table (Optional) |
    \--------------------/              \--------------------/
         Linking View                       Execution View

I due schemi descrivono i due punti di vista, ovvero quello del linking e quello a livello di esecuzione rispettivamente.
Cominciando dal ELF Header, questo contiene informazioni riguardo all struttura interna del file. Ad esempio contiene gli indirizzi delle altre sezioni.
Il Program header table descrive i vari segmenti del file elf, è opzionale in fase di link. E' invece essenziale per l'esecuzione, perchè contiene le informazioni necessarie ad istruire altri programmi incaricati di creare l'immagine di processo e caricare l'elf nel modo corretto.
La section header table contiene informazioni che descrivono le sezioni del file.
Le sezioni mantengono la maggior parte delle informazioni necessarie per la fase di link, istruzioni, dati, tabella dei simboli, informazioni di rilocazione ed altro.
Ogni sezione possiede una entry nella tabella. Questa contiene informazioni sulla sezione quali nome, dimensione ed altro.
I file utilizzati durante la fase di link, devono necessariamente avere questa sezione, non è necessaria invece per gli altri file oggetto.

Il punto fondamentale dopo questo primo discorso è che il formato elf è univoco sia per librerie sia per eseguibili. Generalmente tutti i file elf contengono un elf header, un section header più varie sezioni, un program header e vari segmenti.
Attraverso l'utilità "readelf" analizziamo l'ELF Header e visualizziamo informazioni importanti sulle parti del file che abbiamo appena citato.
Prendo un eseguibile qualsiasi a.out:

Codice:
root@saturn:~# readelf -h a.out
ELF Header:
Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class:                             ELF32
Data:                              2's complement, little endian
Version:                           1 (current)
OS/ABI:                            UNIX - System V
ABI Version:                       0
Type:                              EXEC (Executable file)
Machine:                           Intel 80386
Version:                           0x1
Entry point address:               0x8048340
Start of program headers:          52 (bytes into file)
Start of section headers:          6484 (bytes into file)
Flags:                             0x0
Size of this header:               52 (bytes)
Size of program headers:           32 (bytes)
Number of program headers:         8
Size of section headers:           40 (bytes)
Number of section headers:         38
Section header string table index: 35
Le informazioni sulle dimensioni delle varie parti del file sono piuttosto importanti perchè ci rendono in grado di raggiungere ogni sua parte partendo dall'inizio del file o da altri indirizzi già conosciuti.

Per poter rappresentare correttamente tutte le informazioni e tutti i dati contenuti vengono utlizzati dei tipi di dati personalizzati "elf-specific" per le piattaforme 32Bit o 64Bit, noi per semplicità ci limitiamo a parlare a 32 Bit.

Codice HTML:
    NAME            SIZE    ALIGNMENT   PURPOSE
    Elf32_Addr      4       4           Indirizzo senza segno
    Elf32_Off       4       4           File offset senza segno
    Elf32_Half      2       2           Intero medio senza segno
    Elf32_Word      4       4           Intero senza segno
    Elf32_SWord     4       4           Intero con segno
    Unsigned char   1       1           Piccolo intero senza segno
Quello che differisce nei sistemi a 64 bit è che ci sono anche tipi fino a 8 bit di dimensione, di conseguenza, anche di allineamento.

0x02) Come abbiamo detto l'ELF header si trova sempre all'inizio e comincia con il "magic number". Questo è idealmente una campo di una struttura C. Il C è il linguaggio più adatto per descrivere la struttura interna degli elf.
Il C è anche il linguaggio utilizzato per scrivere il kernel. Esso è (a mio parere) una potente interfaccia di programmazione per lavorare a basso livello. Ovvero proprio quello di cui noi abbiamo bisogno.
La nostra enciclopedia da tenere sottobraccio è il file header "elf.h" dove sono definite tutte le strutture che ci interessano durante questa guida. Io mi riferirò al kernel versione 2.6.30. Il file elf.h è da considerare come un approfondimento tecnico di quello che stiamo argomentando qui.

In primo piano troviamo proprio l'ELF Header:

Codice:
/* The ELF file header.  This appears at the start of every ELF file.  */

#define EI_NIDENT (16)

typedef struct
{
	unsigned char	e_ident[EI_NIDENT];	/* Magic number and other info */
	Elf32_Half	e_type;			/* Object file type */
	Elf32_Half	e_machine;		/* Architecture */
	Elf32_Word	e_version;		/* Object file version */
	Elf32_Addr	e_entry;		/* Entry point virtual address */
	Elf32_Off	e_phoff;		/* Program header table file offset */
	Elf32_Off	e_shoff;		/* Section header table file offset */
	Elf32_Word	e_flags;		/* Processor-specific flags */
	Elf32_Half	e_ehsize;		/* ELF header size in bytes */
	Elf32_Half	e_phentsize;	/* Program header table entry size */
	Elf32_Half	e_phnum;		/* Program header table entry count */
	Elf32_Half	e_shentsize;	/* Section header table entry size */
	Elf32_Half	e_shnum;		/* Section header table entry count */
	Elf32_Half	e_shstrndx;		/* Section header string table index */
} Elf32_Ehdr;
Già ben commentato nel sorgente direi.
e_ident oltre ad identificare il file come elf, fornisce una dato "machine-indipendent" su come interpretare il contenuto del file.
In una delle videate precedenti abbiamo visto l'intero valore di questo campo, la cui lunghezza è variabile e contiene tutta una serie di informazioni. Come vedete è un'array. I primi 4 bytes contengono il magic number. Il byte successivo è definito con EI_CLASS e identifica la classe del file, la classe determina i tipi base utilizzati nelle strutture dati per lo stesso file oggetto.
Nel nostro caso avrà valenza ciò che è definito alla riga 127 del file elf.h che definisce una classe 32 bit come segue:

Codice:
#define ELFCLASS32	1		/* 32-bit objects */
Il byte successivo chiamato EI_DATA specifica la codifica sia della struttura dati usata dal file oggetto contenitore che quella
contenuta nelle sezioni.
EI_VERSION è il byte successivo e specifica la versione dell'elf header.
Il byte seguente è EI_OSABI e identifica il sistema operativo e l'ABI per i quali il file è progettato. Questo perchè molti flag
contenuti nel file elf sono specifici dell'architettura e vengono interpretati propio a seconda di cosa è contenuto in questo byte.
EI_ABIVERSION si commenta da solo, contiene la versione dell'ABI.
EI_PAD Questo byte è posto come primo dei byte non usati dell'array e_ident.
Questi byte sono settati a zero e sono riservati per usi futuri.

Il prossimo campo e_type è di 2 byte senza segno. Identifica il tipo di file oggetto, i seguenti sono i possibili valori:

Codice:
#define ET_NONE		0			/* No file type */
#define ET_REL		1			/* Relocatable file */
#define ET_EXEC		2			/* Executable file */
#define ET_DYN		3			/* Shared object file */
#define ET_CORE		4			/* Core file */
#define	ET_NUM		5			/* Number of defined types */
#define ET_LOOS		0xfe00		/* OS-specific range start */
#define ET_HIOS		0xfeff		/* OS-specific range end */
#define ET_LOPROC	0xff00		/* Processor-specific range start */
#define ET_HIPROC	0xffff		/* Processor-specific range end */
e_machine specifica l'architettura richiesta per il file. Non stò a riportare per intero i possibili valori, sono consultabili in elf.h
e rappresentano tutte le possibili architetture.

e_version è di 4 byte con segno e specifica la versione del file oggetto. Può assumere solo tre valori:

Codice:
#define EV_NONE	0	/* Invalid ELF version */
#define EV_CURRENT	1		/* Current version */
#define EV_NUM		2
e_entry è l'indirizzo dell'entry point. E' un dato piuttosto importante perchè specifica il punto al quale il sistema deve cedere il controllo, da ora non starò sempre a ripetere i tipi dei campi, guardate la tabella proposta in precedenza come promemoria.

e_phoff Offset in byte della program header table. Se tale struttura è assente, questo campo è uguale a zero.

e_shoff Mantiene l'offset in byte della section header table, anche in questo caso se non c'è il campo è zero. E' l'offset in byte che separano l'inizio del file al section header table. Valore necessario per poter accedere alle sezioni.

e_flags Definisce un flag specifico per il processore.

e_ehsize La dimensione dell'elf header in bytes.

e_phentsize La dimensione in byte relativa alla entry nella program header table . Tutte le entry sono di ugual dimensione.

e_phnum Il numero di entry nella program header table. Questo moltiplicato a e_phentsize restituisce la dimensione complessiva della tabella in bytes.

e_shentsize Questo specifica la dimensione in bytes della section header. Questa è una entry nella section header table.
Tutte le entry sono uguali.

e_shnum Il numero di entry nella section table. Anche in questo caso il prodotti di questo con il precedente campo restituisce la dimensione della tabella complessiva in byte.

e_shstrndx Questo membro contiene l'indice della entry, associata con il nome della sezione, nella tabella delle stringhe. (un'altra sezione)

Prima di affrontare la struttura program header procederei a descrivere le varie sezioni anche se si trovano fisicamente dopo il program header.

0x03) Tutte le entry delle sezioni somo descritte come un array di strutture Elf32_Shdr o Elf64_Shdr a seconda del numero dei bit della piattaforma.
Il section header table index è iscritto in questo array. Possiamo accedere a questo array utilizzando i campi di cui abbiamo discusso prima.
Infatti abbiamo tutti gli elementi necessari, il numero delle sezioni e la loro dimensione, nonchè l'offset da dove cominciare la lettura.

Il seguente esempio mostra la facilità con la quale possiamo arrivare alla posizione delle sezioni nel file:

--- CODE example_1.c---

Codice:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <elf.h>
#include <sys/types.h>

#define LEN_NAME 128

/* Example of elf reading */

int main(int argc, char**argv)
{
        if(argc != 2 ) { fprintf(stderr,"Argument?\n"); return(-1); }

        char szFileName[LEN_NAME];
        FILE*fd;
        size_t nmemb;
        Elf32_Ehdr *elf_header;

        strncpy(szFileName,argv[1],LEN_NAME-1);
        szFileName[LEN_NAME] = '\0';

        if(!(fd = fopen(szFileName,"r"))) {
                fprintf(stderr,"fopen() fail!\n");
                return(-1);
        }

        elf_header = malloc(sizeof(Elf32_Ehdr));

        nmemb = sizeof(Elf32_Ehdr);
        fread((void*)elf_header,1,nmemb,fd);

        printf("\nELF header of %s:\n\n", szFileName);
        // Print object type
        printf("Object file type: %s\n",elf_header->e_ident);

        // Go to the section header
        printf("Section header offset: 0x%08X (%d bytes ) into file\n",(Elf32_Off)elf_header->e_shoff,(Elf32_Off)elf_header->e_shoff);

        free(elf_header);
}
--- CODE END ---

Ottenendo l'header delle sezioni attraverso il valore file offset appena stampato possiamo arrivare molto facilmente ad ogni sezione.
Come abbiamo già detto il section header è un array di elementi di tipo Elf32_Shdr. Ogni entry contiene tipo, nome, dimensione, offset e altre informazioni per ogni sezione.

Molti di questi indici sono riservati. Alcuni file oggetto possono anche non avere sezioni per questi indici speciali. Come ricavare il nome della sezione verrà spiegato al momento di affrontare la string table.

Codice:
/* Special section indices.  */

#define SHN_UNDEF		0		/* Undefined section */
#define SHN_LORESERVE	0xff00		/* Start of reserved indices */
#define SHN_LOPROC		0xff00		/* Start of processor-specific */
#define SHN_BEFORE		0xff00		/* Order section before all others (Solaris).  */
#define SHN_AFTER		0xff01		/* Order section after all others (Solaris).  */
#define SHN_HIPROC		0xff1f		/* End of processor-specific */
#define SHN_LOOS		0xff20		/* Start of OS-specific */
#define SHN_HIOS		0xff3f		/* End of OS-specific */
#define SHN_ABS			0xfff1		/* Associated symbol is absolute */
#define SHN_COMMON		0xfff2		/* Associated symbol is common */
#define SHN_XINDEX		0xffff		/* Index is in extra table.  */
#define SHN_HIRESERVE	0xffff		/* End of reserved indices */
Ogni entry ha la struttura seguente:

Codice:
typedef struct
{
	Elf32_Word	sh_name;		/* Section name (string tbl index) */
	Elf32_Word	sh_type;		/* Section type */
	Elf32_Word	sh_flags;		/* Section flags */
	Elf32_Addr	sh_addr;		/* Section virtual addr at execution */
	Elf32_Off	sh_offset;		/* Section file offset */
	Elf32_Word	sh_size;		/* Section size in bytes */
	Elf32_Word	sh_link;		/* Link to another section */
	Elf32_Word	sh_info;		/* Additional section information */
	Elf32_Word	sh_addralign;	/* Section alignment */
	Elf32_Word	sh_entsize;		/* Entry size if section holds table */
} Elf32_Shdr;
Anche qui i commenti presenti in elf.h ci aiutano.

sh_name specifica il nome della sezione. Questo valore è l'indice (un offset) nella sezione "string table" (che vedremo successivamente).
Fornisce la locazione di una stringa terminata dal carattere nullo.

sh_type indica il tipo di sezione e la sua semantica. I seguenti sono i tipi definiti:

Codice:
/* Legal values for sh_type (section type).  */

#define SHT_NULL	  		0		/* Section header table entry unused */
Marca l'intestazione di sezione come non attiva. Solitamente perchè la entry non ha una sezione associata.

Codice:
#define SHT_PROGBITS	  	1		/* Program data */
Indica che la sezione mantiene informazioni definite dal programma, membri e significato sono determinati dal programma.

Codice:
#define SHT_SYMTAB	  		2		/* Symbol table */
Questo valore indica un tipo di sezione molto importante, la tabella dei simboli. Solitamente fornisce i simboli del file per le operazioni di linking.

Codice:
#define SHT_STRTAB	  		3		/* String table */
Indica la sezione che contiene la tabela dele stringhe.

Codice:
#define SHT_RELA	  		4		/* Relocation entries with addends */
Questa sezione mantiene le entry di rilocazione aggiunte in modo esplicito. Queste entry sono del tipo Elf32_Rela per i 32 bit.
Un file può anche contenere più di una sezione di questo tipo.

Codice:
#define SHT_HASH	  		5		/* Symbol hash table */
La tabella degli hash di simboli. Se ne parlerà più avanti.

Codice:
#define SHT_DYNAMIC	  		6		/* Dynamic linking information */
Informazioni riguardo il linking dinamico.

Codice:
#define SHT_NOTE	  		7		/* Notes */
Mantiene informazioni varie sul file oggetto.

Codice:
#define SHT_NOBITS	  		8		/* Program space with no data (bss) */
Questa sezione solitamente non occupa spazio nel file, altrimenti è molto simile al tipo SHT_PROGBITS.

Codice:
#define SHT_REL		  		9		/* Relocation entries, no addends */
La sezione contiene entry senza aggiunte esplicite, le entry sono sempre del tipo Elf32_Rel.

Codice:
#define SHT_SHLIB	  		10		/* Reserved */
Codice:
#define SHT_DYNSYM	  		11		/* Dynamic linker symbol table */
Un file oggetto può contenere anche un set minimo di simboli per il linking dinamico, questo consente di risparmiare un pò di spazio.

Codice:
#define SHT_INIT_ARRAY	  	14		/* Array of constructors */
#define SHT_FINI_ARRAY	  	15		/* Array of destructors */
#define SHT_PREINIT_ARRAY 	16		/* Array of pre-constructors */
#define SHT_GROUP	  	17		/* Section group */
#define SHT_SYMTAB_SHNDX  	18		/* Extended section indeces */
#define	SHT_NUM		  	19		/* Number of defined types.  */
#define SHT_LOOS	  	0x60000000	/* Start OS-specific.  */
#define SHT_GNU_ATTRIBUTES 	0x6ffffff5	/* Object attributes.  */
#define SHT_GNU_HASH	  	0x6ffffff6	/* GNU-style hash table.  */
#define SHT_GNU_LIBLIST	  0x6ffffff7	/* Prelink library list */
#define SHT_CHECKSUM	  	0x6ffffff8	/* Checksum for DSO content.  */
#define SHT_LOSUNW	  	0x6ffffffa	/* Sun-specific low bound.  */
#define SHT_SUNW_move	  0x6ffffffa
#define SHT_SUNW_COMDAT   	0x6ffffffb
#define SHT_SUNW_syminfo  	0x6ffffffc
#define SHT_GNU_verdef	  	0x6ffffffd	/* Version definition section.  */
#define SHT_GNU_verneed	  0x6ffffffe	/* Version needs section.  */
#define SHT_GNU_versym	  0x6fffffff	/* Version symbol table.  */
#define SHT_HISUNW	  	0x6fffffff	/* Sun-specific high bound.  */
#define SHT_HIOS	  	0x6fffffff	/* End OS-specific type */
#define SHT_LOPROC	  	0x70000000	/* Start of processor-specific */
#define SHT_HIPROC	  	0x7fffffff	/* End of processor-specific */
#define SHT_LOUSER	  	0x80000000	/* Start of application-specific */
#define SHT_HIUSER	  	0x8fffffff	/* End of application-specific */
Questo valore specifica il limite superiore della gamma di indici riservato per i programmi applicativi

sh_flags definisce vari tipi di attributi. Possono essere i seguenti:

Codice:
/* Legal values for sh_flags (section flags).  */

#define SHF_WRITE	     	(1 << 0)	/* Writable */
#define SHF_ALLOC	     	(1 << 1)	/* Occupies memory during execution */
#define SHF_EXECINSTR	    (1 << 2)	/* Executable */
#define SHF_MERGE	     	(1 << 4)	/* Might be merged */
#define SHF_STRINGS	     	(1 << 5)	/* Contains nul-terminated strings */
#define SHF_INFO_LINK	    (1 << 6)	/* `sh_info' contains SHT index */
#define SHF_LINK_ORDER	    (1 << 7)	/* Preserve order after combining */
#define SHF_OS_NONCONFORMING(1 << 8)	/* Non-standard OS specific handling required */
#define SHF_GROUP	     	(1 << 9)	/* Section is member of a group.  */
#define SHF_TLS		     	(1 << 10)	/* Section hold thread-local data.  */
#define SHF_MASKOS	     	0x0ff00000	/* OS-specific.  */
#define SHF_MASKPROC	    0xf0000000	/* Processor-specific */
#define SHF_ORDERED	     	(1 << 30)	/* Special ordering requirement (Solaris).  */
#define SHF_EXCLUDE	     	(1 << 31)	/* Section is excluded unless referenced or allocated (Solaris).*/
Molto semplicemente definiscono gli attributi che le sezioni avranno. Ad esempio SHF_WRITE indicherà una sezione che sarà scrivibile.

sh_addr se la sezione sarà presente nell'immagine di processo, allora questo valore specifica l'indirizzo del primo byte della sezione in memoria. Altrimenti questo valore sarà uguale a 0.

sh_offset specifica l'offset in byte che va dall'inizio del file all'inizio del primo byte della sezione. La sezione SHT_NOBITS descritta prima, non occupa spazio nel file, quindi il membro sh_offset localizza una posizione solo concettuale nel file.

sh_size specifica la dimensione della sezione in bytes.

sh_link contiene un collegamento con la tabella "header table index". L'interpretazione dipende dal tipo di sezione.
Sono gli stessi possibili valori per sh_type.

sh_info Contiene informazioni extra che dipendono dal tipo di sezione.

sh_addralign alcune sezioni hanno un allineamento imposto. Per esempio se una sezione contiene dei valore DWORD, il sistema deve assicurare un allineamento DWORD per l'intera sezione. Questo valore specifica il tipo di allineamento.

sh_entsize alcune sezioni mantengono una tabella di entry di dimensione fissa come la tabella dei simboli. Per queste, questo membro fornisce la dimensione in byte di ogni entry. Contiene 0 se la sezione non contiene una tabella di entry di dimensioni fisse.

Ci sono alcune sezioni dette "speciali", queste sono quelle utilizzate dal sistema.

Codice HTML:
    NOME            TIPO            ATTRIBUTI
    .bss            SHT_NOBITS      SHF_ALLOC + SHF_WRITE
    .comment        SHT_PROGBITS    none
    .data           SHT_PROGBITS    SHF_ALLOC + SHF_WRITE
    .datal          SHT_PROGBITS    SHF_ALLOC + SHF_WRITE
    .debug          SHT_PROGBITS    none
    .dynamic        SHT_DYNAMIC     see below
    .dynstr         SHT_STRTAB      SHF_ALLOC
    .dynsym         SHT_DYNSYM      SHF_ALLOC
    .fini           SHT_PROGBITS    SHF_ALLOC + SHF_EXECINSTR
    .got            SHT_PROGBITS    see below
    .hash           SHT_HASH        SHF_ALLOC
    .init           SHT_PROGBITS    SHF_ALLOC + SHF_EXECINSTR
    .interp         SHT_PROGBITS    see below
    .line           SHT_PROGBITS    none
    .note           SHT_NOTE        none
    .plt            SHT_PROGBITS    see below
    .relname        SHT_REL         see below
    .relaname       SHT_RELA        see below
    .rodata         SHT_PROGBITS    SHF_ALLOC
    .rodata1        SHT_PROGBITS    SHF_ALLOC
    .shstrtab       SHR_STRTAB      none
    .strtab         SHR_STRTAB      see below
    .symtab         SHR_STRTAB      see below
    .text           SHR_STRTAB      SHF_ALLOC + SHF_EXEINSTR
Alcune di queste sono sempre presenti nell'immagine di processo, altre no.

.bss
La sezione bss contiene i dati non inizializzati, fa parte dell'immagine di processo. Per definizione, il sistema inizializza sempre i dati con valori uguali a zero quando il processo è avviato.
La sezione non occupa spazio su disco.

.comment
Contiene informazioni per il controllo della versione.

.data e .datal
Contengono i dati già inizializzati nell'immagine di processo.

.debug
Questa sezione contiene informazioni sui simboli di debug.

.dynamic
Contiene informazioni sul linking dinamico. Questa sezione ha degli attributi dipendenti dal processore.

.dynstr
Contiene le stringhe utilizzate dal dynamic linker, solitamente le stringhe rappresentano i nomi associati alla tabella dei simboli.

.dynsym
Questa sezione contiene la tabella dei simboli per il dynamic linker. Tutto ciò che riguarda il dynamic linker (che sono molte cose) le affronteremo in un capitolo successivo.

.fini
Contiene istruzioni eseguibili che contribuiscono al codice utilizzato dal programma per terminare. Questo quando un programma esce normalmente.

.got
Questa sezione contiene il global offset table, che affronteremo più avanti.

.hash
Contiene gli hash della tabella simboli.

.init
Contiene codice eseguibile che contribuisce al processo di avvio. Quando il programma si avvia, il sistema gestisce l'esecuzione del codice in quesa sezione prima di chiamare main().

.interp
Mantiene il percorso dell'interprete da utilizzare. Se il file ha segmenti rilocabili, gli attributi della sezione conterranno allora anche il flag SHF_ALLOC.

.line
Numeri di linea per i simboli di debugging che descrive la corrispondenza tra il codice sorgnente e quello eseguibile, per esempio durante una sessione di gdb.

.note
Contiene informazioni varie.

.plt
Stà per "procedure linkage table". Contiene la procedura per il linking, vedremo anche questo più avanti, assieme alla sezione .got

.relname e .relaname
Queste due sezioni contengono informazioni per la rilocazione. Se il file ha segmenti rilocabili, gli attributi della sezione comprenderanno anche il flag AHF_ALLOC. Convenzionalmente, "name" è fornito dalla sezione da rilocare. Solitamente si vedranno sezioni chiamate .rel.text oppure .rela.text.

.rodata e .rodatal
Sono sola lettura. Solitamente contribuiscono a formare il segmento non scrivibile nell'immagine di processo.

.shstrtab
Contiene i nomi delle sezioni.

.strtab
Contiene le stringhe associate alle entry dei simboli. Se il file ha segmenti caricabili che includono tabelle di simboli string, la sezione ha il flag SHF_ALLOC settato negli attributi.

.symtab
Tabella dei simboli. Stesso discorso per l'attributo ALLOC della sezione precedente.

.text
Contiene il codice eseguibile del programma.

Concludendo, le sezioni speciali hanno un nome preceduto dal punto (.). Il sistema però può utilizzare anche nomi non preceduti dal punto per le sezioni speciali per evitare conflitti tra queste. Invece le sezioni riservate al processore hanno un nome formato dall'abbreviazione del del tipo di architettura. Ad esempio: .foo.psect con foo tipo di architettura.

Utilizzando il programma readelf possiamo verificare quanto detto fino ad ora, la seguente è una analisi di un comune eseguibile.

Codice:
root@saturn:~# readelf -S a.out
There are 38 section headers, starting at offset 0x1954:

Section Headers:
[Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
[ 0]                   NULL            00000000 000000 000000 00      0   0  0
[ 1] .interp           PROGBITS        08048134 000134 000013 00   A  0   0  1
[ 2] .note.ABI-tag     NOTE            08048148 000148 000020 00   A  0   0  4
[ 3] .hash             HASH            08048168 000168 00002c 04   A  5   0  4
[ 4] .gnu.hash         GNU_HASH        08048194 000194 000020 04   A  5   0  4
[ 5] .dynsym           DYNSYM          080481b4 0001b4 000060 10   A  6   1  4
[ 6] .dynstr           STRTAB          08048214 000214 000053 00   A  0   0  1
[ 7] .gnu.version      VERSYM          08048268 000268 00000c 02   A  5   0  2
[ 8] .gnu.version_r    VERNEED         08048274 000274 000020 00   A  6   1  4
[ 9] .rel.dyn          REL             08048294 000294 000008 08   A  5   0  4
[10] .rel.plt          REL             0804829c 00029c 000020 08   A  5  12  4
[11] .init             PROGBITS        080482bc 0002bc 000030 00  AX  0   0  4
[12] .plt              PROGBITS        080482ec 0002ec 000050 04  AX  0   0  4
[13] .text             PROGBITS        08048340 000340 00019c 00  AX  0   0 16
[14] .fini             PROGBITS        080484dc 0004dc 00001c 00  AX  0   0  4
[15] .rodata           PROGBITS        080484f8 0004f8 00001e 00   A  0   0  4
[16] .eh_frame         PROGBITS        08048518 000518 000004 00   A  0   0  4
[17] .ctors            PROGBITS        08049f0c 000f0c 000008 00  WA  0   0  4
[18] .dtors            PROGBITS        08049f14 000f14 000008 00  WA  0   0  4
[19] .jcr              PROGBITS        08049f1c 000f1c 000004 00  WA  0   0  4	
[20] .dynamic          DYNAMIC         08049f20 000f20 0000d0 08  WA  6   0  4
[21] .got              PROGBITS        08049ff0 000ff0 000004 04  WA  0   0  4
[22] .got.plt          PROGBITS        08049ff4 000ff4 00001c 04  WA  0   0  4
[23] .data             PROGBITS        0804a010 001010 000008 00  WA  0   0  4
[24] .bss              NOBITS          0804a018 001018 000008 00  WA  0   0  4
[25] .comment          PROGBITS        00000000 001018 000103 00      0   0  1
[26] .debug_aranges    PROGBITS        00000000 001120 000070 00      0   0  8
[27] .debug_pubnames   PROGBITS        00000000 001190 000040 00      0   0  1
[28] .debug_info       PROGBITS        00000000 0011d0 000254 00      0   0  1
[29] .debug_abbrev     PROGBITS        00000000 001424 0000da 00      0   0  1
[30] .debug_line       PROGBITS        00000000 0014fe 00016c 00      0   0  1
[31] .debug_frame      PROGBITS        00000000 00166c 00003c 00      0   0  4
[32] .debug_str        PROGBITS        00000000 0016a8 0000ce 01  MS  0   0  1
[33] .debug_loc        PROGBITS        00000000 001776 000043 00      0   0  1
[34] .debug_ranges     PROGBITS        00000000 0017c0 000040 00      0   0  8
[35] .shstrtab         STRTAB          00000000 001800 000151 00      0   0  1
[36] .symtab           SYMTAB          00000000 001f44 0004d0 10     37  56  4
[37] .strtab           STRTAB          00000000 002414 000224 00      0   0  1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
a.out è un eseguibile preso a caso. Con il parametro "-S" readelf ci visualizza tutte le sezioni del file.

0x04) La tabella delle stringhe è un'insieme per lo più contiguo, di stringhe che servono al file oggetto per rappresentare simboli e nomi delle sezioni. Ogni riferimento ad una stringa è come un indice in questa tabella. Il primo byte è l'indice 0. L'ultimo byte della tbella è un carattere nullo e identifica la fine della sezione.
Un piccolo esempio di tabella può essere il seguente:

Codice:
Index  	+0	+1	+2	+3	+4	+5	+6	+7	+8	+9
0		\0	n	a	m	e	.	\0	V	a	r
10		i	a	b	l	e	\0	a	b	l	e
20		\0	\0	x	x	\0
Le stringhe sono indicizzate così:
01 name
07 Variable
11 able
16 able
24 "null string"

Con cat e most andiamo a vedere questa sezione e, guardando nella codifica ASCII, vediamo i simboli definiti nel file a.out:

Codice HTML:
                           / --- Il primo byte nullo
    ...                   V
    0x00002410: 12000B00 00696E69 742E6300 696E6974     .....init.c.init
    0x00002420: 66696E69 2E630063 72747374 7566662E     fini.c.crtstuff.
    0x00002430: 63005F5F 43544F52 5F4C4953 545F5F00     c.__CTOR_LIST__.
    0x00002440: 5F5F4454 4F525F4C 4953545F 5F005F5F     __DTOR_LIST__.__
    0x00002450: 4A43525F 4C495354 5F5F005F 5F646F5F     JCR_LIST__.__do_
    0x00002460: 676C6F62 616C5F64 746F7273 5F617578     global_dtors_aux
    0x00002470: 00636F6D 706C6574 65642E36 36323500     .completed.6625.
    0x00002480: 64746F72 5F696478 2E363632 37006672     dtor_idx.6627.fr
    0x00002490: 616D655F 64756D6D 79005F5F 43544F52     ame_dummy.__CTOR
    0x000024A0: 5F454E44 5F5F005F 5F465241 4D455F45     _END__.__FRAME_E
    0x000024B0: 4E445F5F 005F5F4A 43525F45 4E445F5F     ND__.__JCR_END__
    0x000024C0: 005F5F64 6F5F676C 6F62616C 5F63746F     .__do_global_cto
    0x000024D0: 72735F61 75780070 5F63616E 6172792E     rs_aux.p_canary.
    0x000024E0: 63005F47 4C4F4241 4C5F4F46 46534554     c._GLOBAL_OFFSET
    0x000024F0: 5F544142 4C455F00 5F5F696E 69745F61     _TABLE_.__init_a
    0x00002500: 72726179 5F656E64 005F5F69 6E69745F     rray_end.__init_
    0x00002510: 61727261 795F7374 61727400 5F44594E     array_start._DYN
    0x00002520: 414D4943 00646174 615F7374 61727400     AMIC.data_start.
    0x00002530: 5F5F6C69 62635F63 73755F66 696E6900     __libc_csu_fini.
    0x00002540: 5F737461 7274005F 5F676D6F 6E5F7374     _start.__gmon_st
    0x00002550: 6172745F 5F005F4A 765F5265 67697374     art__._Jv_Regist
    0x00002560: 6572436C 61737365 73005F66 705F6877     erClasses._fp_hw
    0x00002570: 005F6669 6E69006D 656D7365 74404047     ._fini.memset@@G
    0x00002580: 4C494243 5F322E30 005F5F6C 6962635F     LIBC_2.0.__libc_
    0x00002590: 73746172 745F6D61 696E4040 474C4942     start_main@@GLIB
    0x000025A0: 435F322E 30005F49 4F5F7374 64696E5F     C_2.0._IO_stdin_
    0x000025B0: 75736564 005F5F64 6174615F 73746172     used.__data_star
    0x000025C0: 74005F5F 64736F5F 68616E64 6C65005F     t.__dso_handle._
    0x000025D0: 5F44544F 525F454E 445F5F00 5F5F6C69     _DTOR_END__.__li
    0x000025E0: 62635F63 73755F69 6E697400 7072696E     bc_csu_init.prin
    0x000025F0: 74664040 474C4942 435F322E 30005F5F     tf@@GLIBC_2.0.__
    0x00002600: 6273735F 73746172 74005F65 6E64005F     bss_start._end._
    0x00002610: 65646174 61005F5F 69363836 2E676574     edata.__i686.get
    0x00002620: 5F70635F 7468756E 6B2E6278 006D6169     _pc_thunk.bx.mai
    0x00002630: 6E005F69 6E697400                       n._init.
    -- MOST: *stdin*            |                                                                       (560,1) 100%
    Press `Q' to quit, `H' for help, and SPACE to scroll.
                                |
                                \ --- &gt; L'ultimo byte nullo
Nella codifcia ASCII sono visibili tutte le stringhe utilizzate dal file oggetto.
Le stringhe sono quindi referenziate attravero gli indici con qualsiasi byte della sezione.

0x05) La tabella dei simboli del file oggetto contiene le informazioni richieste per localizzare definizioni simboliche e riferimenti del programma. L'indice 0 di st_name identifica la prima entry dell'array, questa è nulla, definita come:

STN_UNDEF 0

La seguente invece è la struttura che definisce le entry sempre per quanto riguarda l'architettura a 32 bit.

Codice:
/* Symbol table entry.  */

typedef struct
{
	Elf32_Word	st_name;	/* Symbol name (string tbl index) */
	Elf32_Addr	st_value;	/* Symbol value */
	Elf32_Word	st_size;	/* Symbol size */
	unsigned char	st_info;	/* Symbol type and binding */
	unsigned char	st_other;	/* Symbol visibility */
	Elf32_Section	st_shndx;	/* Section index */
} Elf32_Sym;
st_name contiene l'indice della tabella. Se questo valore è zero, la entry non ha un nome.

st_value contiene il valore del simbolo. Dipendentemente dal contesto, questo può essere assoluto, un indirizzo o altro.

st_size Molti simboli hanno associata una dimensione. Per esempio il simbolo "data" sono il numero dei bytes contenuti nel file oggetto.
Se è zero non ha una dimensione oppure è sconosciuta.

st_info specifica il tipo gli attributi del simbolo. La sequente è una lista dei possibili attributi di un simbolo, questi illustrano come manipolare i valori,

Codice:
/* How to extract and insert information held in the st_info field.  */

#define ELF32_ST_BIND(val)		(((unsigned char) (val)) >> 4)
#define ELF32_ST_TYPE(val)		((val) & 0xf)
#define ELF32_ST_INFO(bind, type)	(((bind) << 4) + ((type) & 0xf))
st_other non ha un significato è settato a zero.

st_shndx tutte le entry della tabella dei simboli sono definite in relazione alla sezione. Questo elemento contiene l'indice della sezione della tabella. Alcuni di questi hanno un significato speciale.

/* Legal values for ST_BIND subfield of st_info (symbol binding). */

#define STB_LOCAL 0 /* Local symbol */
I simboli locali non sono visibili all'esterno del file oggetto contenente questa definizione. Quindi nomi locali possono essere uguali in più sezioni.

#define STB_GLOBAL 1 /* Global symbol */
I simboli di tipo globale sono visibili anche dagli altri processi e file oggetto.

#define STB_WEAK 2 /* Weak symbol */
Sono dei simboli globali ma con precedenza minore.
Insieme al tipo precedente serve ad evitare che durante la fase di link possano nascere dei conflitti con simboli globali di altri file oggetto.

#define STB_NUM 3 /* Number of defined types. */
#define STB_LOOS 10 /* Start of OS-specific */
#define STB_HIOS 12 /* End of OS-specific */
Questi ultimi due hanno un range riservato per il tipo di processore.

#define STB_LOPROC 13 /* Start of processor-specific */
#define STB_HIPROC 15 /* End of processor-specific */
Sempre relativi al processore, però non sono riservati, il loro significato dipende dall'architettura.

Direi che i commenti presenti in elf.h sono sufficienti per la prossima serie che definisce i valori possibili per st_info

Codice:
/* Legal values for ST_TYPE subfield of st_info (symbol type).  */

#define STT_NOTYPE	0		/* Symbol type is unspecified */
#define STT_OBJECT	1		/* Symbol is a data object */
#define STT_FUNC	2		/* Symbol is a code object */
#define STT_SECTION	3		/* Symbol associated with a section */
#define STT_FILE	4		/* Symbol's name is file name */
#define STT_COMMON	5		/* Symbol is a common data object */
#define STT_TLS		6		/* Symbol is thread-local data object*/
#define	STT_NUM		7		/* Number of defined types.  */
#define STT_LOOS	10		/* Start of OS-specific */
#define STT_HIOS	12		/* End of OS-specific */
#define STT_LOPROC	13		/* Start of processor-specific */
#define STT_HIPROC	15		/* End of processor-specific */
I simboli nei file oggetto condivisi (ad esempio le librerie dinamiche condivise di linux) hanno uno significato speciale.
Quando un'altro file oggetto referenzia una funzione di un oggetto condiviso, il link editor crea in modo automatico una entry nella tabella dei simboli per il simbolo utilizzato.
Se un simbolo ha un valore che riferisce ad una locazione specifica nella sezione, st_shndx, conterrà un indice nella "section header table". Quando una sezione viene mossa durante una rilocazione, il valore di questo simbolo cambierà e continuerà comunque a puntare alla stessa locazione in memoria.

Il comando di readelf per visualizare la tabella dei simboli è il seguente:

Codice:
root@saturn:~# readelf -s a.out

Symbol table '.dynsym' contains 6 entries:
Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     2: 00000000     0 FUNC    GLOBAL DEFAULT  UND memset@GLIBC_2.0 (2)
     3: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.0 (2)
     4: 00000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.0 (2)
     5: 080484fc     4 OBJECT  GLOBAL DEFAULT   15 _IO_stdin_used

	Symbol table '.symtab' contains 77 entries:
	Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 08048134     0 SECTION LOCAL  DEFAULT    1
     2: 08048148     0 SECTION LOCAL  DEFAULT    2
     3: 08048168     0 SECTION LOCAL  DEFAULT    3
     4: 08048194     0 SECTION LOCAL  DEFAULT    4
     5: 080481b4     0 SECTION LOCAL  DEFAULT    5
     6: 08048214     0 SECTION LOCAL  DEFAULT    6
     7: 08048268     0 SECTION LOCAL  DEFAULT    7
     8: 08048274     0 SECTION LOCAL  DEFAULT    8
     9: 08048294     0 SECTION LOCAL  DEFAULT    9
    10: 0804829c     0 SECTION LOCAL  DEFAULT   10
    11: 080482bc     0 SECTION LOCAL  DEFAULT   11
    12: 080482ec     0 SECTION LOCAL  DEFAULT   12
    13: 08048340     0 SECTION LOCAL  DEFAULT   13
    14: 080484dc     0 SECTION LOCAL  DEFAULT   14
    15: 080484f8     0 SECTION LOCAL  DEFAULT   15
    16: 08048518     0 SECTION LOCAL  DEFAULT   16
    17: 08049f0c     0 SECTION LOCAL  DEFAULT   17
    18: 08049f14     0 SECTION LOCAL  DEFAULT   18
    19: 08049f1c     0 SECTION LOCAL  DEFAULT   19
    20: 08049f20     0 SECTION LOCAL  DEFAULT   20
    21: 08049ff0     0 SECTION LOCAL  DEFAULT   21
    22: 08049ff4     0 SECTION LOCAL  DEFAULT   22
    23: 0804a010     0 SECTION LOCAL  DEFAULT   23
    24: 0804a018     0 SECTION LOCAL  DEFAULT   24
    25: 00000000     0 SECTION LOCAL  DEFAULT   25
    26: 00000000     0 SECTION LOCAL  DEFAULT   26
    27: 00000000     0 SECTION LOCAL  DEFAULT   27
    28: 00000000     0 SECTION LOCAL  DEFAULT   28
    29: 00000000     0 SECTION LOCAL  DEFAULT   29
    30: 00000000     0 SECTION LOCAL  DEFAULT   30
    31: 00000000     0 SECTION LOCAL  DEFAULT   31
    32: 00000000     0 SECTION LOCAL  DEFAULT   32
    33: 00000000     0 SECTION LOCAL  DEFAULT   33
    34: 00000000     0 SECTION LOCAL  DEFAULT   34
    35: 00000000     0 FILE    LOCAL  DEFAULT  ABS init.c
    36: 00000000     0 FILE    LOCAL  DEFAULT  ABS initfini.c
    37: 00000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    38: 08049f0c     0 OBJECT  LOCAL  DEFAULT   17 __CTOR_LIST__
    39: 08049f14     0 OBJECT  LOCAL  DEFAULT   18 __DTOR_LIST__
    40: 08049f1c     0 OBJECT  LOCAL  DEFAULT   19 __JCR_LIST__
    41: 08048370     0 FUNC    LOCAL  DEFAULT   13 __do_global_dtors_aux
    42: 0804a018     1 OBJECT  LOCAL  DEFAULT   24 completed.6625
    43: 0804a01c     4 OBJECT  LOCAL  DEFAULT   24 dtor_idx.6627
    44: 080483d0     0 FUNC    LOCAL  DEFAULT   13 frame_dummy
    45: 00000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    46: 08049f10     0 OBJECT  LOCAL  DEFAULT   17 __CTOR_END__
    47: 08048518     0 OBJECT  LOCAL  DEFAULT   16 __FRAME_END__
    48: 08049f1c     0 OBJECT  LOCAL  DEFAULT   19 __JCR_END__
    49: 080484b0     0 FUNC    LOCAL  DEFAULT   13 __do_global_ctors_aux
    50: 00000000     0 FILE    LOCAL  DEFAULT  ABS initfini.c
    51: 00000000     0 FILE    LOCAL  DEFAULT  ABS p_canary.c
    52: 08049ff4     0 OBJECT  LOCAL  HIDDEN   22 _GLOBAL_OFFSET_TABLE_
    53: 08049f0c     0 NOTYPE  LOCAL  HIDDEN   17 __init_array_end
    54: 08049f0c     0 NOTYPE  LOCAL  HIDDEN   17 __init_array_start
    55: 08049f20     0 OBJECT  LOCAL  HIDDEN   20 _DYNAMIC
    56: 0804a010     0 NOTYPE  WEAK   DEFAULT   23 data_start
    57: 08048440     5 FUNC    GLOBAL DEFAULT   13 __libc_csu_fini
    58: 08048340     0 FUNC    GLOBAL DEFAULT   13 _start
    59: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
    60: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
    61: 080484f8     4 OBJECT  GLOBAL DEFAULT   15 _fp_hw
    62: 080484dc     0 FUNC    GLOBAL DEFAULT   14 _fini
    63: 00000000     0 FUNC    GLOBAL DEFAULT  UND memset@@GLIBC_2.0
    64: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC_
    65: 080484fc     4 OBJECT  GLOBAL DEFAULT   15 _IO_stdin_used
    66: 0804a010     0 NOTYPE  GLOBAL DEFAULT   23 __data_start
    67: 0804a014     0 OBJECT  GLOBAL HIDDEN   23 __dso_handle
    68: 08049f18     0 OBJECT  GLOBAL HIDDEN   18 __DTOR_END__
    69: 08048450    90 FUNC    GLOBAL DEFAULT   13 __libc_csu_init
    70: 00000000     0 FUNC    GLOBAL DEFAULT  UND printf@@GLIBC_2.0
    71: 0804a018     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
    72: 0804a020     0 NOTYPE  GLOBAL DEFAULT  ABS _end
    73: 0804a018     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
    74: 080484aa     0 FUNC    GLOBAL HIDDEN   13 __i686.get_pc_thunk.bx
    75: 080483f4    72 FUNC    GLOBAL DEFAULT   13 main
    76: 080482bc     0 FUNC    GLOBAL DEFAULT   11 _init
Rimane ancora una cosa per quanto riguarda la tabella dei simboli, anche se stiamo parlando comunque di dettagli, per il sistema operativo
i dettagli non esistono quindi non possiamo tralasciare nessuna caratteristica o comportamento.
Il campo st_value abbiamo detto può rappresentare più cose, contiene un indirizzo virtuale.
Nei file rilocabili contiene i vincoli per l'allineamento in memoria per un simbolo il cui indice di sezione è SHN_COMMON.
Per rendere il dynamic linker più efficente l'offset di sezione lascia il posto a un indirizzo virtuale.

0x06) La rilocazione è il processo che interconnette i simboli con gli indirizzi effettivi delle funzioni. Per esempio, quando un programma
effettua una chiamata a funzione, l'istruzione di chiamata deve trasferire il controllo di esecuzione al rispettivo indirizzo.
Per i file rilocabili sono state pensate delle "entry di rilocazione" (relocation entries).
Queste sono necessarie in quanto esse contengono le informazioni su come modificare il contenuto delle sezioni stesse, per permettere l'esecuzione del processo e per consentire ai file oggetto condivisi di fornire informazioni corrette all'immagine di processo.

Le strutture sono le seguenti:

Codice:
/* Relocation table entry without addend (in section of type SHT_REL).  */

typedef struct
{
	Elf32_Addr	r_offset;		/* Address */
	Elf32_Word	r_info;			/* Relocation type and symbol index */
} Elf32_Rel;

/* Relocation table entry with addend (in section of type SHT_RELA).  */

typedef struct
{
	Elf32_Addr	r_offset;		/* Address */
	Elf32_Word	r_info;			/* Relocation type and symbol index */
	Elf32_Sword	r_addend;		/* Addend */
} Elf32_Rela;
r_offset è un indirizzo. Questo indica la locazione dove applicare la rilocazione. Per un file rilocabile, il valore è un file offset che indica
lo scostamento dall'inizio della sezione all'unità di allocazione, che si trova entro la seconda sezione.
Per un file eseguibile o per un file oggetto condiviso, il valore rappresenta il virtual address dell'unità da rilocare.

r_info fornisce l'indice della tabella dei simboli, tenendo presente il tipo di rilocazione fatta, e il tipo di rilocazione da applicare.
Per fare un esempio, ad una chiamata ad una istruzione di rilocazione, (entry nella sezione di rilocazione) viene utilizzato un indice della tabella dei simboli per la funzione chiamata.
Se l'indice è STN_UNDEF, la rilocazione usa 0 come valore del simbolo (campo st_value). I tipi di rilocazione sono specifici per processore.

Ciò che segue riferisce al tipo di rilocazione nella entry o all'indice della tabella dei simboli.
Le seguenti macro permettono l'estrazione dal campo r_info del simbolo o del tipo,

Codice:
/* How to extract and insert information held in the r_info field.  */

#define ELF32_R_SYM(val)		((val) >> 8)
#define ELF32_R_TYPE(val)		((val) & 0xff)
#define ELF32_R_INFO(sym, type)		(((sym) << 8) + ((type) & 0xff))
r_addend questo membro specifica una costante aggiuntiva utilizzata per calcolare il valore da memorizzare nel campo rilocabile.

Quindi una sezione di rilocazione riferisce a altre due sezioni: una tabella di simboli e la sezione da modificare (la sezione rilocata).
I campi sh_info e sh_link visti prima nella "section header" descrivono in questo caso questa relazione. Entry di rilocazione in file oggetto
differenti hanno interpretazioni leggermente differenti del campo r_offset.

Ulteriori informazioni sul modo con il quale il campo r_offset viene interpretato possono essere reperite nella documentazione del processore.

Prima di continuare con la prossima e più impegnativa parte che descrive le operazioni di caricamento di un elf in memoria per l'esecuzione o il collegamento con altri eseguibili vediamo un pò di codice esemplificativo. Un'ottimo sorgente molto utile da consultare che descrive i metodi di accesso a ogni parte dell'elf è quello del programma readelf già citato in più occasioni.
E' scaricabile assieme al pacchetto "bin-utilis".

Il seguente esempio visualizza in modo completo l'ELF header poi stampa ogni entry di sezione, l'esempio cerca di essere il più semplice possibile per mettere in evidenzia i metodi, comunque semplici, per accedere alle sezioni.
Il sorgente readelf.c di bin-utilis è naturalmente più complesso.

--- CODE elf_ex.h ---

Codice:
#include <elf.h>
	#include <errno.h>
	#include <stdlib.h>
	#include <string.h>
	#include <stdio.h>
	#include <sys/types.h>

	#define PATH_LEN 128
	#define READ_PERM "r"
	#define A_BYTE_SIZE 1
	#define MAX_STRING_LEN 32

	#define CALC_ARRAY_SIZE(a,b) (a*b)

	void*get_data(void*,size_t,FILE*,int,int);
	void error(char*);
	FILE*elfopen(char*);
	char*get_arch_string(Elf32_Half);
	char*get_type_string(Elf32_Word);
	
	--- CODE END ---
	
	Il corpo principale è il seguente:
	
	--- CODE example_2.c ---
	
	#include "elf_ex.h"

	int main(int argc, char**argv)
	{
		int current_offset = 0; // The begin of file
		void*data_ptr;

		Elf32_Ehdr *elf_header;
		Elf32_Shdr *elf_sheader;

		short string_table_index;
		short sec_number;
		int sec_entry_size;
		int k;

		/* the delicate task of taking the user input */
		if(argc != 2) error("Pass a valid path of elf file.\n");
		char*szFileName = malloc(PATH_LEN);
		strncpy(szFileName,argv[1],PATH_LEN-1);
		szFileName[PATH_LEN] = '\0';

		/* get file descriptor */
		FILE*elf_fd = elfopen(szFileName);
		free(szFileName);

		/* reading ELF header, arguments for this function are size of allocated space, size of each element of array,
		file descriptor, size of data to be read and file offset */
		data_ptr = get_data(NULL,A_BYTE_SIZE,elf_fd,sizeof(Elf32_Ehdr),current_offset);
		if(!data_ptr) error("get_data() fail!\n");
		elf_header = (Elf32_Ehdr*)data_ptr;
		printf("\nElf Header file informations:\n");
		printf(
		"member e_ident (Object file type): %s\n"
		"member e_machine (Architecture): %s\n"
		"member e_version (Object file version): %d\n"
		"member e_entry (Entry point virtual address): 0x%08X\n"
		"member e_phoff (Program header table file offset): %d (bytes into file)\n"
		"member e_shoff (Section header table file offset): %d (bytes into file)\n"
		"member e_flags (Processor-specific flags): 0x%08X\n"
		"member e_ehsize (ELF header size in bytes): %d (bytes)\n"
		"member e_phentsize (Program header table entry size): %d (bytes)\n"
		"member e_phnum (Program header table entry count): %d\n"
		"member e_shentsize (Section header table entry size): %d (bytes)\n"
		"member e_shnum (Section header table entry count): %d\n"
		"member e_shstrndx (Section header string table index): %d\n"
		,elf_header->e_ident,get_arch_string(elf_header->e_machine),
		elf_header->e_version,elf_header->e_entry,
		elf_header->e_phoff,elf_header->e_shoff,
		elf_header->e_flags,elf_header->e_ehsize,
		elf_header->e_phentsize,elf_header->e_phnum,
		elf_header->e_shentsize,elf_header->e_shnum,
		elf_header->e_shstrndx);

		/* e_shstrndx locates the string table entry in secion header */
		string_table_index = elf_header->e_shstrndx;

		/* Go to the section header */
		current_offset = elf_header->e_shoff;
		sec_number = elf_header->e_shnum;
		sec_entry_size = sizeof(Elf32_Shdr);

		/* free space is no longer use */
		free(data_ptr);

		/* read data */
		data_ptr = get_data(NULL,sec_entry_size,elf_fd,sec_number,current_offset);
		if(!data_ptr) error("get_data() fail!\n");
		elf_sheader = (Elf32_Shdr*)data_ptr;

		/* go to the sring table */
		Elf32_Shdr *bk = elf_sheader;
		for(k=0;k!=string_table_index;k++) elf_sheader++;
		Elf32_Off string_tbl_offset = elf_sheader->sh_offset;
		elf_sheader = bk;

		/* print sections details */
		char*name = malloc(MAX_STRING_LEN);

		printf("\nElf section list:\n\n");
		printf("[Nr] NAME             TYPE                   VA         OFFSET     SIZE         LINK    INFO ALIG ENTSIZE\n");
		for(k=0;k<sec_number;k++)
		{
			/* passing the string table offset displacement to get_data() */
			strcpy(name,get_data(name,A_BYTE_SIZE,elf_fd,MAX_STRING_LEN,string_tbl_offset+(elf_sheader->sh_name)));
			if(name[0]==0x0) strcpy(name,"No name\0");
			printf("[%2d] %-16s %-22s 0x%08X 0x%08X %d bytes\t%-4d %4d %4d %4d\n",k,
				name,get_type_string(elf_sheader->sh_type),elf_sheader->sh_addr,elf_sheader->sh_offset,elf_sheader->sh_size,
				elf_sheader->sh_link,elf_sheader->sh_info,elf_sheader->sh_addralign,elf_sheader->sh_entsize);
			elf_sheader++;
		}

		fclose(elf_fd);
		free(name);
		free(data_ptr);
		return(0);
	}

	void*
	get_data(void*ptr,size_t elem_size, FILE*fd, int elem_num, int offset)
	{
		void*data;
		if(offset) {
			fseek(fd,offset,SEEK_SET);
		}
		if(!ptr) {
			data = malloc(CALC_ARRAY_SIZE(elem_num,elem_size));
		} else data = ptr;
		if(fread(data,elem_size,elem_num,fd) != elem_num) {
			free(data);
			return(NULL);
		}
		rewind(fd);
		return(data);
	}

	void
	error(char*string)
	{
		perror(string);
		exit(1);
	}

	FILE*elfopen(char*path)
	{
		if(!path) error("null path!\n");
		FILE*fd = fopen(path,(const char *)READ_PERM);
		if(!fd) error("fopen() fail!\n");
		return(fd);
	}

	char*get_arch_string(Elf32_Half machine)
	{
		switch(machine)
		{
			case EM_NONE: return("No machine");
			case EM_M32: return("AT&T WE 32100");
			case EM_SPARC: return("SUN SPARC");
			case EM_386: return("Intel 386");
			/* [...] skip uncommon types */
			case EM_S370: return("IBM system/370");
			/* [...] */
			case EM_PPC: return("PowerPC");
			case EM_PPC64: return("PowerPC 64-bit");
			/* [...] */
			case EM_ARM: return("ARM");
			/* [...] */
			case EM_X86_64: return("AMD x86-64");
			/* [...] */
		}
		return("Not-supported");
	}

	char*get_type_string(Elf32_Word type)
	{
		switch(type)
		{
			case SHT_NULL:      return("Unused");
			case SHT_PROGBITS:  return("Program data");
			case SHT_SYMTAB:    return("Symbol table");
			case SHT_STRTAB:    return("String table");
			case SHT_RELA:      return("Reloc. entries");
			case SHT_HASH:      return("Symbol hash table");
			case SHT_DYNAMIC:   return("Dyn link info");
			case SHT_NOTE:      return("Notes");
			case SHT_NOBITS:    return("No data (bss)");
			case SHT_REL:       return("Reloc. entries");
			case SHT_SHLIB:     return("Reserved");
			case SHT_DYNSYM:        return("Dyn link sym table");
			case SHT_INIT_ARRAY:    return("Arr constructors");
			case SHT_FINI_ARRAY:    return("Arr denstructors");
			case SHT_PREINIT_ARRAY: return("Arr pre-constructors");
			case SHT_GROUP:         return("Sec group");
			case SHT_SYMTAB_SHNDX:  return("Ext section indices");
			case SHT_NUM:           return("Numb defined types");
			case SHT_LOOS:          return("Start OS-specific");
			case SHT_GNU_ATTRIBUTES:    return("Object attr");
			case SHT_GNU_HASH:      return("GNU-style hash table");
			case SHT_GNU_LIBLIST:   return("Prelink library list");
			case SHT_CHECKSUM:      return("Check for DSO cont");
			case SHT_LOSUNW:        return("Sun-specific");
			/* [..] Uncommon types */
			case SHT_GNU_verdef:    return("Version def section");
			case SHT_GNU_verneed:   return("Version sym table");
			/* [...] */
			case SHT_HIOS:      return("End OS-spec type");
			case SHT_LOPROC:    return("Start of proc specific");
			case SHT_HIPROC:    return("End of proc specific");
			case SHT_LOUSER:    return("Start of app specific");
			case SHT_HIUSER:    return("End of app specific");
		}
		return("Not-supported");
	}
--- CODE END ---

0x07) La sezione rilocazione contiene tutte le informazioni necessarie al sistema per eseguire le azioni che creano il processo.
Molte delle informazioni specifiche per il processore risiedono nella sezione opportunamente marcata come DT_RELA.
Il file oggetto o file eseguibile su disco rappresenta il programma in modo statico. Per eseguirlo il sistema utilizza le informazioni mantenute nel file per creare una rappresentazione dinamica del programma.

Inizialmente abbiamo volutamente tralasciato la descrizione di una parte importante del file, il "program header". Questa porzione di file si trova dopo l'ELF header ed è necessaria per l'esecuzione del programma. E' composto da un array di strutture. Ogni struttura di questo array contiene informazioni riguardo un segmento (parte) del file necessaria per preparare il file all'esecuzione.
Il program header è necessario solamente nei file eseguibili e file oggetto condivisi.
Se riprendiamo in mano la struttura dell'ELF header ci ricordiamo di questi due membri:
e_phoff => che indica l'offset in bytes dall'inizio del file verso al program header.
e_phentsize => che indica la dimensione in byte di ogni entry del program header (non la dimensione totale dell'array)
e_phnum => che indica invece il numero di queste entry

La seguente è la struttura di ogni entry del program header:

Codice:
/* Program segment header.  */

typedef struct
{
	Elf32_Word	p_type;			/* Segment type */
	Elf32_Off	p_offset;		/* Segment file offset */
	Elf32_Addr	p_vaddr;		/* Segment virtual address */
	Elf32_Addr	p_paddr;		/* Segment physical address */
	Elf32_Word	p_filesz;		/* Segment size in file */
	Elf32_Word	p_memsz;		/* Segment size in memory */
	Elf32_Word	p_flags;		/* Segment flags */
	Elf32_Word	p_align;		/* Segment alignment */
} Elf32_Phdr;
p_type questo membro indica il tipo di segmento descritto dalla entry, oppure indica come interpretare le informazioni riportate.
I possibili valori sono i seguenti:

Codice:
/* Legal values for p_type (segment type).  */

#define	PT_NULL		0		/* Program header table entry unused */
#define PT_LOAD		1		/* Loadable program segment */
#define PT_DYNAMIC	2		/* Dynamic linking information */
#define PT_INTERP	3		/* Program interpreter */
#define PT_NOTE		4		/* Auxiliary information */
#define PT_SHLIB	5		/* Reserved */
#define PT_PHDR		6		/* Entry for header table itself */
#define PT_TLS		7		/* Thread-local storage segment */
#define	PT_NUM		8		/* Number of defined types */
#define PT_LOOS		0x60000000	/* Start of OS-specific */
#define PT_GNU_EH_FRAME	0x6474e550	/* GCC .eh_frame_hdr segment */
#define PT_GNU_STACK	0x6474e551	/* Indicates stack executability */
#define PT_GNU_RELRO	0x6474e552	/* Read-only after relocation */
#define PT_LOSUNW	0x6ffffffa
#define PT_SUNWBSS	0x6ffffffa	/* Sun Specific segment */
#define PT_SUNWSTACK	0x6ffffffb	/* Stack segment */
#define PT_HISUNW	0x6fffffff
#define PT_HIOS		0x6fffffff	/* End of OS-specific */
#define PT_LOPROC	0x70000000	/* Start of processor-specific */
#define PT_HIPROC	0x7fffffff	/* End of processor-specific */
Tra i valori principali troviamo:

PT_NULL l'elemento dell'array è inutilizzato, gli altri campi nella entry non sono definiti.

PT_LOAD specifica un segmento caricabile, descritto da p_filesz e p_memsz. I bytes del file sono mappati all'inizio del segmento di memoria. Se la dimensione del segmento di memoria è più larga della dimensione del file, i bytes "extra" saranno settati a 0. La dimensione del file non può essere più grande di quella nella memoria. Le entry di segmenti caricabili sono ordinate nell'array per il campo p_vaddr in ordine decrescente.

PT_DYNAMIC l'elemento dell'array specifica informazioni per il collegamento dinamico. Parleremo più avanti della
funzione effettiva di questo tipo di entry.

PT_INTERP specifica una stringa terminata dal carattere nullo di terminazione che identifica il percorso
dell'interprete da invocare. Questo è necessario solamente per i file eseguibili; questo non può essere presente più di una volta. Se è presente, deve precedere qualsiasi entry di segmento caricabile (PT_LOAD).

PT_NOTE specifica la locazione e la dimensione di informazioni ausiliarie.

PT_SHLIB specifica una entry di tipo riservato.

PT_PHDR se presente, specifica la locazione e la dimensione di tutto il program header, sia nel file che nell'immagine di processo del programma. Questo tipo di segmento non può essere riportato più di una volta nel file. Inoltre, questo è presente solo se il program header è presente anche nell'immagine di pocesso. Se questo tipo è presente nell'array precederà ogni segmento di tipo PT_LOAD.

PT_LOOS, PT_HIOS, PT_LOPROC, PT_HIPROC indicano segmenti dedicati alla semantica del processore.

p_offset scostamento in byte dall'inizio del file all'inizio del segmento.

p_vaddr specifica il virtual address al quale il segmento risiederà in memoria.

p_paddr sui sistemi come system V questo campo ha contenuto non specificato dato che tale sistema non supporta l'indirizzamento fisico. Mentre su altri questo contiene l'indirizzo fisico di memoria al quale si trova il segmento.

p_filesz contiene la dimensione in byte del file immagine del segmento, che può essere 0.

p_memsz contiene la dimensione in byte della immagine di memoria del segmento, che può essere 0.

p_flags possono essere inseriti in questo campo i seguenti flag:

Codice:
/* Legal values for p_flags (segment flags).  */

#define PF_X		(1 << 0)	/* Segment is executable */
#define PF_W		(1 << 1)	/* Segment is writable */
#define PF_R		(1 << 2)	/* Segment is readable */
#define PF_MASKOS	0x0ff00000	/* OS-specific */
#define PF_MASKPROC	0xf0000000	/* Processor-specific */
p_align questo campo fornisce il valore al quale i segmenti devono essere allineati in memoria e nel file.
Se assume 0 o 1 significa che l'allineamento non è richiesto. Altrimenti è un numero positivo. Una potenza di 2.

Abbiamo parlato di segmenti e all'inizio avevamo anche rappresentato con uno schema la struttura del file elf.
Cosa sono esattamente?
Un segmento comprende una o più sezioni, questo fatto è assolutamente trasparente al program header.
Diversi dati devono essere presenti nell'immagine di processo per l'esecuzione del programma come collegamento dinamico ecc... Gli schemi riportati di seguito illustrano il contenuto del segmento in termini generali.
L'ordine e la composizione delle sezioni all'interno del segmento può variare, inoltre, le specifiche del processore possono modificare ulteriormente la struttura del segmento.

Codice HTML:
        text segment
            
            /-------------\
            |   .text     |
             -------------
            |   .rodata   |
             -------------
            |   .hash     |
             -------------
            |   .dynsyn   |
             -------------
            |   .dynstr   |
             -------------
            |   .plt      |
             -------------
            |   .rel.got  |
             -------------
             
        data segment
        
            /------------\
            |   .data    |
             ------------
            |   .dynamic |
             ------------
            |   .got     |
             ------------
            |   .bss     |
             ------------
Con readelf possiamo stampare i vari segmenti:

Codice:
root@HackLab:~# readelf --segments a.out

Elf file type is EXEC (Executable file)
Entry point 0x8048490
There are 8 program headers, starting at offset 52

Program Headers:
	Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
	PHDR           0x000034 0x08048034 0x08048034 0x00100 0x00100 R E 0x4
	INTERP         0x000134 0x08048134 0x08048134 0x00013 0x00013 R   0x1
			[Requesting program interpreter: /lib/ld-linux.so.2]
	LOAD           0x000000 0x08048000 0x08048000 0x00740 0x00740 R E 0x1000
	LOAD           0x000f0c 0x08049f0c 0x08049f0c 0x00120 0x0012c RW  0x1000
	DYNAMIC        0x000f20 0x08049f20 0x08049f20 0x000d0 0x000d0 RW  0x4
	NOTE           0x000148 0x08048148 0x08048148 0x00020 0x00020 R   0x4
	GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x4
	GNU_RELRO      0x000f0c 0x08049f0c 0x08049f0c 0x000f4 0x000f4 R   0x1

Section to Segment mapping:
	Segment Sections...
	00
	01     .interp
	02     .interp .note.ABI-tag .hash .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .eh_frame
	03     .ctors .dtors .jcr .dynamic .got .got.plt .data .bss
	04     .dynamic
	05     .note.ABI-tag
	06
	07     .ctors .dtors .jcr .dynamic .got
0x08) Veniamo al "dynamic linking", collegamento dinamico.
Questo è un processo che risolve (traduce) tutti i riferimenti fatti dal programma (nomi di funzioni) sia in fase di iniziazione che in fase di esecuzione. Molti dei meccanismi che lo compongono sono definiti in termini generali da un modello comune (file elf) determinato dal tipo di sistema operativo, altri sono più specifici per il processore.
Due programmi sono necessari per effettuare queste operazioni, il dynamic linker e l'interprete.
L'interprete in questo caso è un programma in grado di preparare l'esecuzione di un file preparando l'immagine di processo nel modo indicato dalle sezioni del file. Come abbiamo detto se nel program header c'è un elemento di tipo PT_INTERP significa che l'eseguibile parteciperà al collegamento dinamico. Allora durante la chiamata ad exec(), il sistema recupera il percorso dell'eseguibile dal segmento PT_INTERP, creerà poi l'immagine di processo iniziale. (syscall mmap() ) Poi sarà responsabilità dell'interprete, a cui il sistema cederà il controllo, fornire un ambiente all'applicazione.
L'interprete può ricevere il controllo in due modi. Può ricevere un file descriptor che punta all'inizio del file. Utilizzerà questo descrittore per leggere e/o mappare i segmenti del file eseguibile nella memoria. Oppure, a seconda del formato del file, il sistema può caricare il file eseguibile nella memoria invece di dare un file descriptor all'interprete.

Quando viene assemblato un file eseguibile che usa il collegamento dinamico, il link editor aggiungerà al program header una entry del tipo PT_INTERP al file. Indicando al sistema di invocare il dynamic linker come interprete, come si vede dal program header che ho mostrato con readelf: "[Requesting program interpreter: /lib/ld-linux.so.2]"

La funzione exec() assieme al dynamic linker coopereranno per creare l'immagine di processo.
Eseguiranno le seguenti azioni:

- Aggiunta all'immagine di processo dei segmenti del file eseguibile.
- Aggiunta dei segmenti dei file oggetto condivisi all'immagine di processo.
- Attuano la rilocazione dei file oggetto e dell'eseguibile.
- Vengono chiusi i file descriptor utilizzati per leggere le informazioni dal file eseguibile e oggetti condivisi.
- Viene trasferito il controllo al programma.

Il link editor costruisce anche diversi dati che assistono il collegamento dinamico per i file oggetto condivisi o gli eseguibili.
Questi dati risiedono nei segmenti caricabili. Parliamo di questi,

La sezione .dynamic (SHT_DYNAMIC) contiene dati per questa operazione.
Le strutture che risiedono all'inizio della sezione contengono indirizzi di altre informazioni per il collegamento dinamico.
La sezione .hash (SHT_HASH) è una tabella di simboli hash.
Le sezioni .got e .plt con SHT_PROGBITS mantengono due tabelle; la "global offset table" detta con termini inglesi, e la tabella per la procedura di collegamento.
Vedremo fra poco come il dynamic linker usa e modifica le tabelle appena citate per creare l'immagine di processo per i files oggetto.

Il dynamic linker, siccome gli indirizzi virtuali occupati dagli oggetti condivisi sono diversi da quelli memorizzati nel program header, ha il copito anche di rilocare l'immagine di processo, aggiornare gli indirizzi prima che l'applicazione prenda il controllo.

Poi se l'ambiene del processo contiene la variabile LD_BIND_NOW con un valore non nullo, il dynamic linker processa tutte le rilocazioni prima di trasferire il controllo al programma. Per esempio, tutte le seguenti variabili d'ambiente possono specificare questo comportamento:

LD_BIND_NOW = 1
LD_BIND_NOW = on
LD_BIND_NOW = off

Altrimenti, LD_BIND_NOW non dovrà essere presente oppure dovrà essere settato a 0.

Parliamo di come è composta la sezione .dynamic. Questa è una sezione di tipo SHT_DYNAMIC, contenuta a sua volta nel segmento di tipo PT_DYNAMIC. Questo è un array di strutture del tipo Elf32_Dyn (sempre parlando 32 bit)

Codice:
/* Dynamic section entry.  */

typedef struct
{
	Elf32_Sword	d_tag;			/* Dynamic entry type */
	union
	{
		Elf32_Word d_val;			/* Integer value */
		Elf32_Addr d_ptr;			/* Address value */
	} d_un;
} Elf32_Dyn;
d_val è un integer di varia interpretazione.

d_ptr questo rappresenta un indirizzo virtuale. Come detto in precedenza, gli indirizzi virtuali di un file possono non corrispondere agli indirizzi di memoria virtuale del processo, anzi quasi mai è così. Il linker dinamico calcola i nuovi VA a runtime (RVA ovvero real virtual address), sulla base di questo valore e l'indirizzo di memoria base.

I seguenti sono i valori legali di d_val:

Codice:
/* Legal values for d_tag (dynamic entry type).  */

#define DT_NULL		0		/* Marks end of dynamic section */
#define DT_NEEDED	1		/* Name of needed library */
#define DT_PLTRELSZ	2		/* Size in bytes of PLT relocs */
#define DT_PLTGOT	3		/* Processor defined value */
#define DT_HASH		4		/* Address of symbol hash table */
#define DT_STRTAB	5		/* Address of string table */
#define DT_SYMTAB	6		/* Address of symbol table */
#define DT_RELA		7		/* Address of Rela relocs */
#define DT_RELASZ	8		/* Total size of Rela relocs */
#define DT_RELAENT	9		/* Size of one Rela reloc */
#define DT_STRSZ	10		/* Size of string table */
#define DT_SYMENT	11		/* Size of one symbol table entry */
#define DT_INIT		12		/* Address of init function */
#define DT_FINI		13		/* Address of termination function */
#define DT_SONAME	14		/* Name of shared object */
#define DT_RPATH	15		/* Library search path (deprecated) */
#define DT_SYMBOLIC	16		/* Start symbol search here */
#define DT_REL		17		/* Address of Rel relocs */
#define DT_RELSZ	18		/* Total size of Rel relocs */
#define DT_RELENT	19		/* Size of one Rel reloc */
#define DT_PLTREL	20		/* Type of reloc in PLT */
#define DT_DEBUG	21		/* For debugging; unspecified */
#define DT_TEXTREL	22		/* Reloc might modify .text */
#define DT_JMPREL	23		/* Address of PLT relocs */
#define	DT_BIND_NOW	24		/* Process relocations of object */
#define	DT_INIT_ARRAY	25	/* Array with addresses of init fct */
#define	DT_FINI_ARRAY	26	/* Array with addresses of fini fct */
#define	DT_INIT_ARRAYSZ	27	/* Size in bytes of DT_INIT_ARRAY */
#define	DT_FINI_ARRAYSZ	28	/* Size in bytes of DT_FINI_ARRAY */
#define DT_RUNPATH	29		/* Library search path */
#define DT_FLAGS	30		/* Flags for the object being loaded */
#define DT_ENCODING	32		/* Start of encoded range */
#define DT_PREINIT_ARRAY 32		/* Array with addresses of preinit fct*/
#define DT_PREINIT_ARRAYSZ 33	/* size in bytes of DT_PREINIT_ARRAY */
#define	DT_NUM		34	/* Number used */
#define DT_LOOS		0x6000000d	/* Start of OS-specific */
#define DT_HIOS		0x6ffff000	/* End of OS-specific */
#define DT_LOPROC	0x70000000	/* Start of processor-specific */
#define DT_HIPROC	0x7fffffff	/* End of processor-specific */
#define	DT_PROCNUM	DT_MIPS_NUM	/* Most used by any processor */
La seguente tabella riassume i tag richiesti per file eseguibili e file oggetto codivisi. Se un tag è marcato "obbligatorio", allora l'array del collegamento dinamico, per un file elf deve avere una entry di questo tipo. Cosi come "optional" definisce che una entry per un tag può trovarsi nel file ma non è obbligatoria.

Codice HTML:
        Name        d_un        Exutable        Shared object
    ----------------------------------------------------------
    DT_NULL         ignored     mandatory       mandatory
    DT_NEEDED       d_val       optional        optional
    DT_PLTRELSZ     d_val       optional        optional
    DT_PLTGOT       d_ptr       optional        optional
    DT_HASH         d_ptr       mandatory       mandatory
    DT_STRTAB       d_ptr       mandatory       mandatory
    DT_SYMTAB       d_ptr       mandatory       optional
    DT_RELA         d_ptr       mandatory       optional
    DT_RELASZ       d_val       mandatory       optional
    DT_RELAENT      d_val       mandatory       optional
    DT_STRSZ        d_val       mandatory       mandatory
    DT_SYMENT       d_val       mandatory       mandatory
    DT_INIT         d_ptr       optional        optional 
    DT_FINI         d_ptr       optional        optional
    DT_SONAME       d_val       ignored         optional
    DT_RPATH        d_val       optional        ignored
    DT_SYMBOLIC     ignored     ignored         optional
    DT_REL          d_ptr       mandatory       optional
    DT_RELSZ        d_val       mandatory       optional
    DT_RELENT       d_val       mandatory       optional
    DT_PLTREL       d_val       optional        optional
    DT_DEBUG        d_ptr       optional        optional
    DT_TEXTREL      ignored     optional        optional
    DT_JMPREL       d_ptr       optional        optional
    DT_BIND_NOW     ignored     optional        optional
    DT_LOPREC       unspecified unspecified     unspecified
    DT_HIPROC       unspecified unspecified     unspecified
vediamo i principali,

DT_NULL segnala che si tratta dell'ultima entry.

DT_NEEDED è un indice utilizzato nella string table che identifica il nome della libreria richiesta.

DT_PLTRELSZ contiene la dimensione totale in byte delle entry di rilocazione associate con la tabella della procedura di collegamento. Se è presente una entry di tipo DT_JMPREL, una DT_PLTRELSZ la accompagna.

DT_PLTGOT contiene un indirizzo associato con la tabella della procedura di collegamento e / o l'offset globale della tabella.

DT_HASH contiene l'indirizzo della tabella hash. La vedremo più avanti.

DT_STRTAB indirizzo della tabella delle stringhe.

DT_SYMTAB Indirizzo della tabella dei simboli che abbiamo già visto.

DT_RELA contiene l'indirizzo della tabella di rilocazione. Quando la tabella viene costruita per un eseguibile o per un file oggetto, il link editor concatena queste sezioni per formare un'unica tabella. Anche se le sezioni rimangono indipendenti l'una dall'altra nel file oggetto, il dynamic linker le vede come una singola tabella.
Quando il dynamic linker crea l'immagine di processo. per un file eseguibile o aggiunge un file oggetto condiviso all'immagine, questo legge la tabella di rilocazione e esegue le azioni associate.
Se l'elemento è presente, la struttura dinamica deve anche avere gli elementi DT_RELASZ e DT_RELAENT.
Quando la rilocazione è obbligatoria per un file, questi due elementi sono consentiti ma non richiesti.

DT_RELASZ questo elemento contiene la dimensione totale in byte della tabella di rilocazione DT_RELA

DT_RELAENT questo elemento contiene la dimensione totale in byte di ogni entry della tabella di rilocazione DT_RELA

DT_STRSZ dimensione in byte della tabella delle stringhe.

DT_SYMENT dimensione totale in byte di ogni entry della tabella dei simboli.

DT_INIT contiene l'indirizzo della funzione di inizializzazione, parleremo più avanti di questa funzione.

DT_FINI contiene l'indirizzo della funzione di terminazione.

DT_SONAME contiene l'indice da utilizzarsi nella entry DT_STRTAB per recuperare la stringa che definisce il nome dell'oggetto condiviso.

DT_RPATH Come il precedente, è un'indice nella medesima tabella, identifica però un percorso di ricerca per le librerie da cui il file dipende.

DT_SYMBOLIC la presenza di una entry di questo tipo altera la procedura di risoluzione dei simboli attuata dal dynamic linker.
Invece di partire a cercare i simboli dal file eseguibile, parte dallo stesso file oggetto condiviso.
Solo se qui non viene trovato la ricerca prosegue nel file.

DT_REL simile a DT_RELA, eccetto che la tabella ha un elemento aggiuntivo.
Se questo è presente, la struttura dinamica deve avere anche elementi DT_RELSZ e DT_RELENT.

DT_RELSZ dimensione in byte del precedente

DT_RELENT dimensione in byte di ogni entry dell'elemento DT_REL

DT_PLTREL specifica il tipo di entry di rilocazione alla quale la tabella della procedura di collegamento riferisce.
Il membro d_val contiene DT_REL o DT_RELA. Tutte le rilocazioni in una procedura di collegamento devono usare la stessa rilocazione.

DT_DEBUG è' presente se il file contiene informazioni per il debug.

DT_TEXTREL l'assenza di questo elemento significa che nessuna entry di rilocazione causa una modifica ad un segmento non scrivibile, come specificato dall'attributo del segmento nel program header. SE l'elemento è presente, una o più rilocazioni richiede la modifica di un segmento non scrivibile.

DT_JMPREL se presente l'elemento della entry d_ptr contiene l'indirizzo della entry di rilocazione associato solamente con la tebella della procedura di collegamento.

DT_BIND_NOW se questa entry è presente, la entry istruisce il dynamic linker a processare tutte le rilocazioni che contengono questo tipo di oggetto, prima di trasferire il controllo al programma.

DT_INIT_ARRAY indirizzo dell'array di puntatori alle funzioni di inizializzazione.

DT_FINI_ARRAY indirizzo dell'array di puntatori alle funzioni di terminazione.

DT_LOOS, DT_HIOS, DT_LOPROC e DT_HIPTROC conengono informazini specifiche per sistema operativo e processore.

Data la possibilità di utilizzare funzioni situate in oggetti condivisi, i file eseguibili elf hanno quasi sempre anche una o più dipendenze verso questi file oggetto. Quando il dynamic linker crea i segmenti di memoria per un file oggetto le dipendenze (entries DT_NEEDED), indicano quali oggetti condivisi sono necessari per l'esecuziuone. Una volta risolti i riferimenti simbolici, il dynamic linker esamina attraverso una ricerca "breadth-first" la tabella dei simboli alla ricerca di questi. Prima quella del file stesso, poi quella degli oggetti condivisi. Anche quando viene fatto riferimento più volte ad un oggetto condiviso nella lista delle dipendenze, il dynamic linker collegherà l'oggetto solo una volta al processo.

I nomi degli oggetti da cui il file dipende vengono copiati. Ad esempio, se il dynamic linker crea un processo da un file usando un oggetto condiviso che contiene una entry DT_SONAME di "libl" e un'altro oggetto condiviso con percorso "/usr/lib/lib2", il file eseguibile conterrà "libl" e "/usr/lib/lib2" nella sua lista di dipendenze.

Per listare le dipendenze di un file elf è possibile utilizzare il programma "ldd". Questo stampa a video la lista dei percorsi assoluti dei file oggetto necessari all'esecuzione del file. Ad esempio con a.out ottengo la lista seguente:

Codice:
root@saturn:~# ldd a.out
		linux-gate.so.1 =>  (0xffffe000)
		libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7f0d000)
		/lib/ld-linux.so.2 (0xb8081000)
"global offset table" e "procedure linkage table". Queste sono "processor-specific". Queste sono sezioni del file elf.
Affrontiamo il caso del processore 386, ovvero il più generico.

A cosa servono?
In linux, un processo può chiamare qualsiasi funzione esterna proveniente ad esempio da librerie, attraverso una tabella, che funge da
"rampa di lancio". Questa tabella contiene una serie di istruzioni di jump verso indirizzi di memoria. Tra queste funzioni è possibile trovare ad esempio, la funzione exit, necessaria per uscire dal programma. Questa tabella è denominata ".plt", ovvero procedure linkage table.
L'abbiamo conosciuta come sezione, ricordate?

Utilizziamo qualsiasi elf cavia ed andiamo a scovare questa tabella:

Codice:
root@HackLab:~# objdump -d -j .plt ./a.out

./a.out:     file format elf32-i386

	
Disassembly of section .plt:

080483f0 <__gmon_start__@plt-0x10>:
	80483f0:       ff 35 f8 9f 04 08       pushl  0x8049ff8
	80483f6:       ff 25 fc 9f 04 08       jmp    *0x8049ffc
	80483fc:       00 00                   add    %al,(%eax)
        ...

08048400 <__gmon_start__@plt>:
	8048400:       ff 25 00 a0 04 08       jmp    *0x804a000
	8048406:       68 00 00 00 00          push   $0x0
	804840b:       e9 e0 ff ff ff          jmp    80483f0 <_init+0x30>

08048410 <strncpy@plt>:
	8048410:       ff 25 04 a0 04 08       jmp    *0x804a004
	8048416:       68 08 00 00 00          push   $0x8
	804841b:       e9 d0 ff ff ff          jmp    80483f0 <_init+0x30>

08048420 <__libc_start_main@plt>:
	8048420:       ff 25 08 a0 04 08       jmp    *0x804a008
	8048426:       68 10 00 00 00          push   $0x10
	804842b:       e9 c0 ff ff ff          jmp    80483f0 <_init+0x30>

08048430 <strcpy@plt>:
	8048430:       ff 25 0c a0 04 08       jmp    *0x804a00c
	8048436:       68 18 00 00 00          push   $0x18
	804843b:       e9 b0 ff ff ff          jmp    80483f0 <_init+0x30>

08048440 <printf@plt>:
	8048440:       ff 25 10 a0 04 08       jmp    *0x804a010
	8048446:       68 20 00 00 00          push   $0x20
	804844b:       e9 a0 ff ff ff          jmp    80483f0 <_init+0x30>

08048450 <atoi@plt>:
	8048450:       ff 25 14 a0 04 08       jmp    *0x804a014
	8048456:       68 28 00 00 00          push   $0x28
	804845b:       e9 90 ff ff ff          jmp    80483f0 <_init+0x30>

08048460 <fwrite@plt>:
	8048460:       ff 25 18 a0 04 08       jmp    *0x804a018
	8048466:       68 30 00 00 00          push   $0x30
	804846b:       e9 80 ff ff ff          jmp    80483f0 <_init+0x30>

08048470 <__stack_chk_fail@plt>:
	8048470:       ff 25 1c a0 04 08       jmp    *0x804a01c
	8048476:       68 38 00 00 00          push   $0x38
	804847b:       e9 70 ff ff ff          jmp    80483f0 <_init+0x30>

08048480 <exit@plt>:
	8048480:       ff 25 20 a0 04 08       jmp    *0x804a020
	8048486:       68 40 00 00 00          push   $0x40
	804848b:       e9 60 ff ff ff          jmp    80483f0 <_init+0x30>
Esaminiamola più nel dettaglio:

Codice:
root@HackLab:~# objdump -h ./a.out | grep -A 1 .plt
9 .rel.plt      00000048  08048378  08048378  00000378  2**2
					CONTENTS, ALLOC, LOAD, READONLY, DATA
	--
11 .plt          000000a0  080483f0  080483f0  000003f0  2**2
					CONTENTS, ALLOC, LOAD, READONLY, CODE
	--
21 .got.plt      00000030  08049ff4  08049ff4  00000ff4  2**2
					CONTENTS, ALLOC, LOAD, DATA
gli attributi della sezione sono sola lettura.
Notiamo però che molte istruzioni jmp usano non indirizzi ma puntatori ad indirizzi. Questi indirizzi sono contenuti nella già citata "global offset table".
Quindi le posizioni effettive di tutte le funzioni si trovano agli indirizzi di memoria 0x804a000,0x804a004,0x804a008,0x804a00c,0x804a010,0x804a014,0x804a018,0x804a01c e 0x804a01c.

Codice:
root@HackLab:~# objdump -h ./a.out | grep -A 1 .got
20 .got          00000004  08049ff0  08049ff0  00000ff0  2**2
					CONTENTS, ALLOC, LOAD, DATA
21 .got.plt      00000030  08049ff4  08049ff4  00000ff4  2**2
					CONTENTS, ALLOC, LOAD, DATA
					
root@HackLab:~# objdump -d -j .got.plt ./a.out

./a.out:     file format elf32-i386


Disassembly of section .got.plt:

08049ff4 <_GLOBAL_OFFSET_TABLE_>:
	8049ff4:       20 9f 04 08 00 00 00 00 00 00 00 00 06 84 04 08      ...............
	804a004:       16 84 04 08 26 84 04 08 36 84 04 08 46 84 04 08     ....&...6...F...
	804a014:       56 84 04 08 66 84 04 08 76 84 04 08 86 84 04 08     V...f...v.......
(la sezione .got.plt è caratteristica delle architetture intel)
Ora guardate queso comando di objdump:

Codice:
root@HackLab:~# objdump -R a.out

a.out:     file format elf32-i386

DYNAMIC RELOCATION RECORDS
OFFSET   TYPE              VALUE
08049ff0 R_386_GLOB_DAT    __gmon_start__
0804a02c R_386_COPY        stderr
0804a000 R_386_JUMP_SLOT   __gmon_start__
0804a004 R_386_JUMP_SLOT   strncpy
0804a008 R_386_JUMP_SLOT   __libc_start_main
0804a00c R_386_JUMP_SLOT   strcpy
0804a010 R_386_JUMP_SLOT   printf
0804a014 R_386_JUMP_SLOT   atoi
0804a018 R_386_JUMP_SLOT   fwrite
0804a01c R_386_JUMP_SLOT   __stack_chk_fail
0804a020 R_386_JUMP_SLOT   exit
Nella tabella GOT si trovano questa serie di indirizzi, ovvero gli indirizzi delle nostre funzioni.

La tabella "Global offset table" contiene quindi indirizzi virtuali assoluti in dati privati, questo comportamento fa in modo che gli indirizzi sono raggiungibili senza compromettere la posizione indipendente e la condivisione della sezione text del programma. Pertanto un programma potrò chiamare una funzione come printf() sempre facendo riferimento a questa tabella.

Dopo che il sistema ha creato i segmenti per il file, il dynamic linker processa le entry di rilocazione, molte delle quali sono del tipo
R_386_GLOB_DAT o R_386_JUMP_SLOT.
Il dynamic linker determina se associare il valore del simbolo, calcolare il loro valore assoluto, e settare l'appropriata entry in memoria al rispettivo valore.
Se un programma richiede un accesso diretto all'indirizzo assoluto del simbolo R_386_GLOB_DAT, questo simbolo avrà una entry del tipo detto prima, ovvero global offset table. Siccome il file eseguibile e i file oggetto condivisi hanno global offset table separati, un indirizzo del simbolo può apparire in diverse tabelle.
Il dynamic linker processa tutte queste rilocazioni prima di dare il controllo a qualsiasi codice in memoria.
Questo permette ad un programma come il dynamic linker di trovare l'indirizzo della sua struttura dinamica senza processare prima le entry di rilocazione.
Questo è particolarmente importante per il dynamic linker, perchè questo deve prima inzializzare se stesso senza demandare ad altri programmi il compito di preparare la sua immagine di processo in memoria.

Così come la tabella global offset table ridirige un dato indirizzo verso una posizione assoluta nella memoria, la procedura di collegamento redirige le chiamate a funzioni in modo indipendente dal tipo di queste verso la posizione assoluta GOT.
Sui sistemi system V, queste procedure risiedono in segmenti .text condivisi, ma si utilizzano gli indirizzi della tabella global offset.
Il dynamic linker determina gli indirizzi assoluti di destinazione e modifica il global offset table di conseguenza.

La tabella della procedura di collegamento permette quindi la risoluzione delle chiamate effettuate da un file oggetto ad un'altro.

Nelle architetture intel, la procedura di collegamento risiede nel segmento .text condiviso, ma vengono usati gli indirizzi nei loro privati global offset table in accordo con l'immagine di memoria del processo. Gli eseguibii e oggetti condivisi hanno tabelle di collegamento separate.

0x09) La tabella hash è identica sia per le architetture 32 che 64 bit. La seguente è la struttura della tabella:

Codice HTML:
        /-------------------\
        |     nbucket       |
         -------------------
        |     nchain        |
         -------------------
        |     bucket[0]     |
        |      ......       |
        | bucket[nbucket-1] |
         -------------------
        |     chain[0]      |
        |      ......       |
        |  chain[nchain-1]  |
        \-------------------/
bucket e chain come avrete capito sono due array. Entrambi contengono indici per la tabella.
Il numero di simboli contenuti è nchain, sia bucket che chain identificano ogni entry della tabella, la funzione
che segue accetta come argomento il nome di un simbolo e ne ritorna il suo valore che viene usato per calcolare l'indice bucket.
Di conseguenza, se la funzione ritorna il valore di x per un nome, bucket[x%nbucket] restituisce un indice, y, per entrambe le tabelle.
Se la entry della tabella non è quella desiderata, chain[y] restituisce il prossimo simbolo della tabella con lo stesso valore hash.
Seguendo il collegamento si ottiene il nome desiderato oppure il valore STN_UNDEF.

Codice:
unsigned long
elf_hash(const unsigned char *name)
{
		unsigned long   h = 0, g;
		while (*name)
		{
				h = (h << 4) + *name++;
				if (g = h & 0xf0000000)
						h ^= g >> 24;
				h &= ~g;
		}
		return h;
}
0x0a) Le funzioni di iniziazione e terminazione abbiamo già detto che sono contenute in un array di puntatori.
Dopo che il dynamic linker ha terminato la costruzione dell'immagine di processo e ha eseguito la rilocazione dove necessario, ogni oggetto condiviso può eseguire le procedure di iniziazione del codice.

Queste sono le primissime istruzioni del nostro programma. Andiamole a vedere, utilizziamo in questo caso gdb,

Codice:
root@saturn:~# gdb a.out
GNU gdb 6.8-debian
...
(gdb) disass _init
Dump of assembler code for function _init:
0x080482bc <_init+0>:   push   %ebp	
0x080482bd <_init+1>:   mov    %esp,%ebp
0x080482bf <_init+3>:   push   %ebx
0x080482c0 <_init+4>:   sub    $0x4,%esp
0x080482c3 <_init+7>:   call   0x80482c8 <_init+12>
0x080482c8 <_init+12>:  pop    %ebx
0x080482c9 <_init+13>:  add    $0x1d2c,%ebx
0x080482cf <_init+19>:  mov    -0x4(%ebx),%edx
0x080482d5 <_init+25>:  test   %edx,%edx
0x080482d7 <_init+27>:  je     0x80482de <_init+34>
0x080482d9 <_init+29>:  call   0x80482fc <__gmon_start__@plt>
0x080482de <_init+34>:  call   0x80483d0 <frame_dummy>
0x080482e3 <_init+39>:  call   0x80484b0 <__do_global_ctors_aux>
0x080482e8 <_init+44>:  pop    %eax
0x080482e9 <_init+45>:  pop    %ebx
0x080482ea <_init+46>:  leave
0x080482eb <_init+47>:  ret
End of assembler dump.
(gdb) disass _fini
Dump of assembler code for function _fini:
0x080484dc <_fini+0>:   push   %ebp
0x080484dd <_fini+1>:   mov    %esp,%ebp
0x080484df <_fini+3>:   push   %ebx
0x080484e0 <_fini+4>:   sub    $0x4,%esp
0x080484e3 <_fini+7>:   call   0x80484e8 <_fini+12>
0x080484e8 <_fini+12>:  pop    %ebx
0x080484e9 <_fini+13>:  add    $0x1b0c,%ebx
0x080484ef <_fini+19>:  call   0x8048370 <__do_global_dtors_aux>
0x080484f4 <_fini+24>:  pop    %ecx
0x080484f5 <_fini+25>:  pop    %ebx
0x080484f6 <_fini+26>:  leave
0x080484f7 <_fini+27>:  ret
End of assembler dump.
(gdb)
I processi di iniziazione non possono avvenire naturalmente nello stesso medesimo istante. L'esecuzione di queste procedure tiene conto delle dipendenze tra file oggetto. Ammettiamo di avere 3 oggetti A,B,C. A dipende da C e C dipende da B, B non ha dipendenze. L'ordine di iniziazione sarà quindi C -> B -> A. A potrebbe essere l'eseguibile ma anche un'altro file oggetto condiviso.

Similmente ciò avviene per le procedure di terminazione, l'ordine di esecuzione di queste sarà esattamente l'inverso dell'ordine di iniziazione.

0x0b) In conclusione di questa trattazione piuttosto teorica del formato elf, vediamo come, con l'aiuto di objdump, possiamo rapidamente disassemblare alcune sezioni di un file.
La consultazione di tale output offre ulteriori spunti molto interessanti in vista di tutto quello di cui abbiamo discusso fino ad ora.

Codice:
root@saturn:~# objdump -d a.out

	a.out:     file format elf32-i386


   Disassembly of section .init:

   080482bc <_init>:
	80482bc:       55                      push   %ebp
	80482bd:       89 e5                   mov    %esp,%ebp
	80482bf:       53                      push   %ebx
	80482c0:       83 ec 04                sub    $0x4,%esp
	80482c3:       e8 00 00 00 00          call   80482c8 <_init+0xc>
	80482c8:       5b                      pop    %ebx
	80482c9:       81 c3 2c 1d 00 00       add    $0x1d2c,%ebx
	80482cf:       8b 93 fc ff ff ff       mov    -0x4(%ebx),%edx
	80482d5:       85 d2                   test   %edx,%edx
	80482d7:       74 05                   je     80482de <_init+0x22>
	80482d9:       e8 1e 00 00 00          call   80482fc <__gmon_start__@plt>
	80482de:       e8 ed 00 00 00          call   80483d0 <frame_dummy>
	80482e3:       e8 c8 01 00 00          call   80484b0 <__do_global_ctors_aux>
	80482e8:       58                      pop    %eax
	80482e9:       5b                      pop    %ebx
	80482ea:       c9                      leave
	80482eb:       c3                      ret
	
   Disassembly of section .plt:

   080482ec <__gmon_start__@plt-0x10>:
	80482ec:       ff 35 f8 9f 04 08       pushl  0x8049ff8
	80482f2:       ff 25 fc 9f 04 08       jmp    *0x8049ffc
	80482f8:       00 00                   add    %al,(%eax)
        ...

   080482fc <__gmon_start__@plt>:
	80482fc:       ff 25 00 a0 04 08       jmp    *0x804a000
	8048302:       68 00 00 00 00          push   $0x0
	8048307:       e9 e0 ff ff ff          jmp    80482ec <_init+0x30>

   0804830c <memset@plt>:
	804830c:       ff 25 04 a0 04 08       jmp    *0x804a004
	8048312:       68 08 00 00 00          push   $0x8
	8048317:       e9 d0 ff ff ff          jmp    80482ec <_init+0x30>

   0804831c <__libc_start_main@plt>:
	804831c:       ff 25 08 a0 04 08       jmp    *0x804a008
	8048322:       68 10 00 00 00          push   $0x10
	8048327:       e9 c0 ff ff ff          jmp    80482ec <_init+0x30>

   0804832c <printf@plt>:
	804832c:       ff 25 0c a0 04 08       jmp    *0x804a00c
	8048332:       68 18 00 00 00          push   $0x18
	8048337:       e9 b0 ff ff ff          jmp    80482ec <_init+0x30>

   Disassembly of section .text:

   08048340 <_start>:
	8048340:       31 ed                   xor    %ebp,%ebp
	8048342:       5e                      pop    %esi
	8048343:       89 e1                   mov    %esp,%ecx
	8048345:       83 e4 f0                and    $0xfffffff0,%esp
	8048348:       50                      push   %eax
	8048349:       54                      push   %esp
	804834a:       52                      push   %edx
	804834b:       68 40 84 04 08          push   $0x8048440
	8048350:       68 50 84 04 08          push   $0x8048450
	8048355:       51                      push   %ecx
	8048356:       56                      push   %esi
	8048357:       68 f4 83 04 08          push   $0x80483f4
	804835c:       e8 bb ff ff ff          call   804831c <__libc_start_main@plt>
	8048361:       f4                      hlt
	8048362:       90                      nop
	8048363:       90                      nop
	8048364:       90                      nop
	8048365:       90                      nop
	8048366:       90                      nop
	8048367:       90                      nop
	8048368:       90                      nop
	8048369:       90                      nop
	804836a:       90                      nop
	804836b:       90                      nop
	804836c:       90                      nop
	804836d:       90                      nop
	804836e:       90                      nop
	804836f:       90                      nop

   08048370 <__do_global_dtors_aux>:
	8048370:       55                      push   %ebp
	8048371:       89 e5                   mov    %esp,%ebp
	8048373:       53                      push   %ebx
	8048374:       83 ec 04                sub    $0x4,%esp
	8048377:       80 3d 18 a0 04 08 00    cmpb   $0x0,0x804a018
	804837e:       75 40                   jne    80483c0 <__do_global_dtors_aux+0x50>
	8048380:       8b 15 1c a0 04 08       mov    0x804a01c,%edx
	8048386:       b8 18 9f 04 08          mov    $0x8049f18,%eax
	804838b:       2d 14 9f 04 08          sub    $0x8049f14,%eax
	8048390:       c1 f8 02                sar    $0x2,%eax
	8048393:       8d 58 ff                lea    -0x1(%eax),%ebx
	8048396:       39 da                   cmp    %ebx,%edx
	8048398:       73 1f                   jae    80483b9 <__do_global_dtors_aux+0x49>
	804839a:       8d b6 00 00 00 00       lea    0x0(%esi),%esi
	80483a0:       8d 42 01                lea    0x1(%edx),%eax
	80483a3:       a3 1c a0 04 08          mov    %eax,0x804a01c
	80483a8:       ff 14 85 14 9f 04 08    call   *0x8049f14(,%eax,4)
	80483af:       8b 15 1c a0 04 08       mov    0x804a01c,%edx
	80483b5:       39 da                   cmp    %ebx,%edx
	80483b7:       72 e7                   jb     80483a0 <__do_global_dtors_aux+0x30>
	80483b9:       c6 05 18 a0 04 08 01    movb   $0x1,0x804a018
	80483c0:       83 c4 04                add    $0x4,%esp
	80483c3:       5b                      pop    %ebx
	80483c4:       5d                      pop    %ebp
	80483c5:       c3                      ret
	80483c6:       8d 76 00                lea    0x0(%esi),%esi
	80483c9:       8d bc 27 00 00 00 00    lea    0x0(%edi,%eiz,1),%edi

   080483d0 <frame_dummy>:
	80483d0:       55                      push   %ebp
	80483d1:       89 e5                   mov    %esp,%ebp
	80483d3:       83 ec 08                sub    $0x8,%esp
	80483d6:       a1 1c 9f 04 08          mov    0x8049f1c,%eax
	80483db:       85 c0                   test   %eax,%eax
	80483dd:       74 12                   je     80483f1 <frame_dummy+0x21>
	80483df:       b8 00 00 00 00          mov    $0x0,%eax
	80483e4:       85 c0                   test   %eax,%eax
	80483e6:       74 09                   je     80483f1 <frame_dummy+0x21>
	80483e8:       c7 04 24 1c 9f 04 08    movl   $0x8049f1c,(%esp)
	80483ef:       ff d0                   call   *%eax
	80483f1:       c9                      leave
	80483f2:       c3                      ret
	80483f3:       90                      nop

   080483f4 <main>:
	80483f4:       8d 4c 24 04             lea    0x4(%esp),%ecx
	80483f8:       83 e4 f0                and    $0xfffffff0,%esp
	80483fb:       ff 71 fc                pushl  -0x4(%ecx)
	80483fe:       55                      push   %ebp
	80483ff:       89 e5                   mov    %esp,%ebp
	8048401:       51                      push   %ecx
	8048402:       83 ec 24                sub    $0x24,%esp
	8048405:       c7 44 24 08 08 00 00    movl   $0x8,0x8(%esp)
	804840c:       00
	804840d:       c7 44 24 04 00 00 00    movl   $0x0,0x4(%esp)
	8048414:       00
	8048415:       8d 45 f4                lea    -0xc(%ebp),%eax
	8048418:       89 04 24                mov    %eax,(%esp)
	804841b:       e8 ec fe ff ff          call   804830c <memset@plt>
	8048420:       8b 45 00                mov    0x0(%ebp),%eax
	8048423:       89 44 24 04             mov    %eax,0x4(%esp)
	8048427:       c7 04 24 00 85 04 08    movl   $0x8048500,(%esp)
	804842e:       e8 f9 fe ff ff          call   804832c <printf@plt>
	8048433:       83 c4 24                add    $0x24,%esp
	8048436:       59                      pop    %ecx
	8048437:       5d                      pop    %ebp
	8048438:       8d 61 fc                lea    -0x4(%ecx),%esp
	804843b:       c3                      ret
	804843c:       90                      nop
	804843d:       90                      nop
	804843e:       90                      nop
	804843f:       90                      nop

   08048440 <__libc_csu_fini>:
	8048440:       55                      push   %ebp
	8048441:       89 e5                   mov    %esp,%ebp
	8048443:       5d                      pop    %ebp
	8048444:       c3                      ret
	8048445:       8d 74 26 00             lea    0x0(%esi,%eiz,1),%esi
	8048449:       8d bc 27 00 00 00 00    lea    0x0(%edi,%eiz,1),%edi

   08048450 <__libc_csu_init>:
	8048450:       55                      push   %ebp
	8048451:       89 e5                   mov    %esp,%ebp
	8048453:       57                      push   %edi
	8048454:       56                      push   %esi
	8048455:       53                      push   %ebx
	8048456:       e8 4f 00 00 00          call   80484aa <__i686.get_pc_thunk.bx>
	804845b:       81 c3 99 1b 00 00       add    $0x1b99,%ebx
	8048461:       83 ec 0c                sub    $0xc,%esp
	8048464:       e8 53 fe ff ff          call   80482bc <_init>
	8048469:       8d bb 18 ff ff ff       lea    -0xe8(%ebx),%edi
	804846f:       8d 83 18 ff ff ff       lea    -0xe8(%ebx),%eax
	8048475:       29 c7                   sub    %eax,%edi
	8048477:       c1 ff 02                sar    $0x2,%edi
	804847a:       85 ff                   test   %edi,%edi
	804847c:       74 24                   je     80484a2 <__libc_csu_init+0x52>
	804847e:       31 f6                   xor    %esi,%esi
	8048480:       8b 45 10                mov    0x10(%ebp),%eax
	8048483:       89 44 24 08             mov    %eax,0x8(%esp)
	8048487:       8b 45 0c                mov    0xc(%ebp),%eax
	804848a:       89 44 24 04             mov    %eax,0x4(%esp)
	804848e:       8b 45 08                mov    0x8(%ebp),%eax
	8048491:       89 04 24                mov    %eax,(%esp)
	8048494:       ff 94 b3 18 ff ff ff    call   *-0xe8(%ebx,%esi,4)
	804849b:       83 c6 01                add    $0x1,%esi
	804849e:       39 fe                   cmp    %edi,%esi
	80484a0:       72 de                   jb     8048480 <__libc_csu_init+0x30>
	80484a2:       83 c4 0c                add    $0xc,%esp
	80484a5:       5b                      pop    %ebx
	80484a6:       5e                      pop    %esi
	80484a7:       5f                      pop    %edi
	80484a8:       5d                      pop    %ebp
	80484a9:       c3                      ret

   080484aa <__i686.get_pc_thunk.bx>:
	80484aa:       8b 1c 24                mov    (%esp),%ebx
	80484ad:       c3                      ret
	80484ae:       90                      nop
	80484af:       90                      nop

   080484b0 <__do_global_ctors_aux>:
	80484b0:       55                      push   %ebp
	80484b1:       89 e5                   mov    %esp,%ebp
	80484b3:       53                      push   %ebx
	80484b4:       83 ec 04                sub    $0x4,%esp
	80484b7:       a1 0c 9f 04 08          mov    0x8049f0c,%eax
	80484bc:       83 f8 ff                cmp    $0xffffffff,%eax
	80484bf:       74 13                   je     80484d4 <__do_global_ctors_aux+0x24>
	80484c1:       bb 0c 9f 04 08          mov    $0x8049f0c,%ebx
	80484c6:       66 90                   xchg   %ax,%ax
	80484c8:       83 eb 04                sub    $0x4,%ebx
	80484cb:       ff d0                   call   *%eax
	80484cd:       8b 03                   mov    (%ebx),%eax
	80484cf:       83 f8 ff                cmp    $0xffffffff,%eax
	80484d2:       75 f4                   jne    80484c8 <__do_global_ctors_aux+0x18>
	80484d4:       83 c4 04                add    $0x4,%esp
	80484d7:       5b                      pop    %ebx
	80484d8:       5d                      pop    %ebp
	80484d9:       c3                      ret
	80484da:       90                      nop
	80484db:       90                      nop

	Disassembly of section .fini:

   080484dc <_fini>:
	80484dc:       55                      push   %ebp
	80484dd:       89 e5                   mov    %esp,%ebp
	80484df:       53                      push   %ebx
	80484e0:       83 ec 04                sub    $0x4,%esp
	80484e3:       e8 00 00 00 00          call   80484e8 <_fini+0xc>
	80484e8:       5b                      pop    %ebx
	80484e9:       81 c3 0c 1b 00 00       add    $0x1b0c,%ebx
	80484ef:       e8 7c fe ff ff          call   8048370 <__do_global_dtors_aux>
	80484f4:       59                      pop    %ecx
	80484f5:       5b                      pop    %ebx
	80484f6:       c9                      leave
	80484f7:       c3                      ret
Riferimenti:

http://www.sco.com/developers/gabi/1.../contents.html

http://en.wikipedia.org/wiki/Executa...inkable_Format

book: "Understanding the linux kernel"

Unix kernel sources

glibc sources

*******************************************************************
Questa guida è sotto licenza Creative Commons Attribution-Noncommercial-Share Alike 2.5.

P.S.
Ho dovuto fare alcune prodezze per inserire la guida come post.
Quindi ho pensato di allegare anche la stessa in formato html (rar dentro zip) che è più leggibile.
Bye.
Allegati
File Type: zip elf.zip (23.4 KB, 22 visite)

Ultima modifica di Teo@Unix : 25-06-2010 alle 17:18.
Teo@Unix è offline   Rispondi citando il messaggio o parte di esso
Old 25-06-2010, 16:15   #2
astorcas
Senior Member
 
L'Avatar di astorcas
 
Iscritto dal: Jan 2005
Città: Siena
Messaggi: 1310
credo di amarti....

è un paio di giorni che cerco una guida così!
astorcas è offline   Rispondi citando il messaggio o parte di esso
Old 25-06-2010, 17:09   #3
banryu79
Senior Member
 
L'Avatar di banryu79
 
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
Mazza che lavoro, complimentissimi e ammirevole spirito di condivisione
__________________

As long as you are basically literate in programming, you should be able to express any logical relationship you understand.
If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it.
(Chris Crawford)
banryu79 è offline   Rispondi citando il messaggio o parte di esso
Old 25-06-2010, 17:22   #4
pabloski
Senior Member
 
Iscritto dal: Jan 2008
Messaggi: 8406
Ottima idea. In italiano non ho mai trovato nulla sul formato elf, per quanto si tratti di un argomento decisamente importante.
pabloski è offline   Rispondi citando il messaggio o parte di esso
Old 25-06-2010, 22:10   #5
Teo@Unix
Senior Member
 
L'Avatar di Teo@Unix
 
Iscritto dal: Mar 2009
Messaggi: 753
Vi ringrazio.
Spero possa risultare utile.
Nel caso andrebbe spostata nella sezione guide.

Ciao.
Teo@Unix è offline   Rispondi citando il messaggio o parte di esso
Old 13-08-2010, 11:46   #6
zappy
Senior Member
 
L'Avatar di zappy
 
Iscritto dal: Oct 2001
Messaggi: 19497
Quote:
Originariamente inviato da Teo@Unix Guarda i messaggi
Vi ringrazio.
Spero possa risultare utile.
Nel caso andrebbe spostata nella sezione guide.

Ciao.
l'argomento non mi interessa e ci sono capitato per caso.
Però mi chiedevo perchè non lo pubblichi su wikipedia: anche perchè la voce http://it.wikipedia.org/wiki/Executa...inkable_format è molto più scarsa della tua guida
__________________
Mai discutere con un idiota. Ti trascina al suo livello e ti batte con l'esperienza (O.W.)
zappy è offline   Rispondi citando il messaggio o parte di esso
Old 14-08-2010, 10:50   #7
Teo@Unix
Senior Member
 
L'Avatar di Teo@Unix
 
Iscritto dal: Mar 2009
Messaggi: 753
è un'idea. thank you.
Teo@Unix è offline   Rispondi citando il messaggio o parte di esso
Old 16-08-2010, 09:32   #8
zappy
Senior Member
 
L'Avatar di zappy
 
Iscritto dal: Oct 2001
Messaggi: 19497
Quote:
Originariamente inviato da Teo@Unix Guarda i messaggi
è un'idea. thank you.
poi se vuoi farne una versione più "seria", ch'è anche nonciclopedia http://nonciclopedia.wikia.com/
__________________
Mai discutere con un idiota. Ti trascina al suo livello e ti batte con l'esperienza (O.W.)
zappy è offline   Rispondi citando il messaggio o parte di esso
Old 19-03-2011, 11:56   #9
Explode18
Bannato
 
Iscritto dal: Mar 2011
Messaggi: 94
Appena ho un po di tempo provo e ti dico =) complimenti
Explode18 è offline   Rispondi citando il messaggio o parte di esso
Old 03-04-2012, 12:39   #10
Blackskull182
Member
 
L'Avatar di Blackskull182
 
Iscritto dal: Mar 2007
Messaggi: 207
Grazie mille
__________________
Tutti gli imbecilli della Borghesia che pronunciano continuamente le parole: immorale, immoralità, moralità nell’arte e altre bestialità mi fanno pensare a Louise Villedieu, puttana da cinque franchi, che accompagnandomi una volta al Louvre, dove non era mai stata, si mise ad arrossire, a coprirsi la faccia, e tirandomi a ogni momento per la manica, mi domandava davanti alle statue e ai quadri immortali come si potesse esporre pubblicamente simili indecenze. (Charles Baudelaire)
Blackskull182 è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


NVIDIA Blackwell B200: due chip in uno per rivoluzionare l'intelligenza artificiale NVIDIA Blackwell B200: due chip in uno per rivol...
HP Envy Move, un PC All-In-One con la batteria che si può spostare facilmente HP Envy Move, un PC All-In-One con la batteria c...
MSI MPG 321URX QD-OLED: un monitor completo per i giocatori MSI MPG 321URX QD-OLED: un monitor completo per ...
realme 12 Pro+ 5G: un potente mid-range con teleobiettivo sotto i 400 euro. La recensione realme 12 Pro+ 5G: un potente mid-range con tele...
Fujifilm Simulazione Pellicola – Guida all'uso Fujifilm Simulazione Pellicola – Guida all'uso
Audi svela Q6 e-tron, salto in avanti to...
Microsoft annuncia: le chiavi RSA 1024-b...
Nothing annuncerà domani, 20 marz...
Galaxy Z Fold6, la versione economica po...
Tesla conferma: in Italia la Model Y RWD...
Sk hynix, tempismo perfetto: è pr...
Microsoft conferma un secondo evento a m...
Xiaomi 14 Ultra è disponibile in ...
Apple al lavoro per evitare commissioni ...
TSMC e Synopsys sono pronte ad accelerar...
Whistleblowing, obbligo e opportunit&agr...
Offerte di Primavera Amazon: da mezzanot...
Nothing Phone (2a) è ora lo smart...
Tutte le offerte Apple da non perdere or...
Tutte le offerte sui televisori Amazon: ...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 12:35.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Served by www2v