[successivo] [precedente] [inizio] [fine] [indice generale] [indice ridotto] [indice analitico] [home] [volume] [parte]


Capitolo 567.   Dal sorgente all'immagine in memoria

Ciò che succede a partire da un file sorgente fino al programma in esecuzione in memoria è definito da un procedimento molto complesso, anche se il compilatore e il sistema operativo consentono di ignorarlo quasi completamente. In questo capitolo si mostra un esempio banale, con tutti i passaggi fino ad arrivare all'immagine in memoria, senza però entrare nella questione dell'uso di librerie dinamiche.

La dimostrazione che appare nel capitolo si basa implicitamente sul formato ELF, sia per i file oggetto rilocabili, sia per i file eseguibili, ma senza entrare nel dettaglio del formato stesso.

567.1   File oggetto

Di norma, la compilazione di un sorgente produce un file oggetto rilocabile, ma non eseguibile. Questo file oggetto contiene il codice ottenuto dall'interpretazione del sorgente, diviso in sezioni (come descritto nel sorgente stesso) che possono essere ricomposte, successivamente, con una cerca libertà.

Figura 567.1. Dalle sezioni del file sorgente a quelle del file oggetto rilocabile.

file oggetto rilocabile

A titolo di esempio si può prendere il file seguente (che riproduce quanto si vede nella figura), compilandolo nel modo consueto (qui si mostra solo l'uso di GNU AS, per semplicità). Si suppone che il file sorgente si chiami prg.s:

.section .data
aaa:   .int 77
.section .bss
.lcomm bbb, 4
.section .text
.globl _start
_start:
    mov   $1, %eax
    mov   $0, %ebx
    int   $0x80

as -o prg.o prg.s[Invio]

Con Objdump si può analizzare il contenuto del file oggetto generato:

objdump -x prg.o[Invio]

prg.o:     file format elf32-i386
prg.o
architecture: i386, flags 0x00000010:
HAS_SYMS
start address 0x00000000

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         0000000c  00000000  00000000  00000034  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000004  00000000  00000000  00000040  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000004  00000000  00000000  00000044  2**2
                  ALLOC
SYMBOL TABLE:
00000000 l    d  .text  00000000 .text
00000000 l    d  .data  00000000 .data
00000000 l    d  .bss   00000000 .bss
00000000 l       .data  00000000 aaa
00000000 l     O .bss   00000004 bbb
00000000 g       .text  00000000 _start

Anche solo intuitivamente, si comprende che il file oggetto riproduce le tre sezioni del sorgente, assegnando loro degli attributi. Per esempio, la sezione .text deve essere caricata in memoria, usata in sola lettura e può essere eseguita; in modo analogo, la sezione .data deve essere caricata in memoria in lettura-scrittura (l'informazione è implicita, in quanto non appare l'attributo READONLY), ma non può essere eseguita; la sezione .bss viene allocata soltanto e non prevede limitazioni particolari, a parte il fatto di non poter essere eseguibile.

Per il momento, l'indirizzo iniziale di riferimento è 0000000016.

Un file oggetto di questo tipo non può essere eseguito perché non contiene le informazioni necessarie al caricamento in memoria.

567.2   File eseguibile

Per ottenere un file eseguibile, i file oggetto che servono vengono raccolti da un collegatore (link editor) che riordina i vari componenti e produce un file con le informazioni necessarie al caricamento in memoria.

Figura 567.4. Dalle sezioni del file oggetto rilocabile ai segmenti del file oggetto eseguibile.

file oggetto eseguibile

Continuando nell'ipotesi della sezione precedente, si passa a generare un file eseguibile a partire dal file oggetto precedente:

ld -o prg prg.o[Invio]

Con Objdump si può analizzare il contenuto del file eseguibile generato:

objdump -x prg[Invio]

prg:     file format elf32-i386
prg
architecture: i386, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x08048074

Program Header:
    LOAD off    0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12
         filesz 0x00000080 memsz 0x00000080 flags r-x
    LOAD off    0x00000080 vaddr 0x08049080 paddr 0x08049080 align 2**12
         filesz 0x00000004 memsz 0x00000008 flags rw-

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         0000000c  08048074  08048074  00000074  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000004  08049080  08049080  00000080  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000004  08049084  08049084  00000084  2**2
                  ALLOC
SYMBOL TABLE:
08048074 l    d  .text  00000000 .text
08049080 l    d  .data  00000000 .data
08049084 l    d  .bss   00000000 .bss
00000000 l    d  *ABS*  00000000 .shstrtab
00000000 l    d  *ABS*  00000000 .symtab
00000000 l    d  *ABS*  00000000 .strtab
08049080 l       .data  00000000 aaa
08049084 l     O .bss   00000004 bbb
08048074 g       .text  00000000 _start
08049084 g       *ABS*  00000000 __bss_start
08049084 g       *ABS*  00000000 _edata
08049088 g       *ABS*  00000000 _end

Il file eseguibile è organizzato in segmenti che possono riferiti, ognuno, a una o più sezioni; ma il file può contenere anche sezioni che non sono riconducibili a un segmento. Il segmento, a differenza della sezione pura e semplice, deve descrivere in che modo il contenuto deve essere caricato in memoria e quali caratteristiche deve avere durante il funzionamento.

Dal rapporto generato da Objdump, precisamente nel riepilogo intitolato Program Header, si può vedere cosa deve essere caricato in memoria e in quale posizione (gli indirizzi si riferiscono alla memoria virtuale). Si notano solo due segmenti, riferiti rispettivamente alla sezione .text, contenente il codice da eseguire, e alla sezione .data.

Il segmento che riguarda la sezione .text deve essere caricato in memoria a partire dall'indirizzo 0804800016, con permessi di lettura ed esecuzione; il segmento che si riferisce alla sezione .data deve essere caricato in memoria a partire dall'indirizzo 0804908016, con permessi di lettura e scrittura. Non esiste un segmento per la sezione .bss in quanto non contiene dati e si sa comunque che deve essere allocata a partire dall'indirizzo 0804908416 (i permessi di lettura e scrittura sono impliciti in questo caso).

Quello che appare indicato come indirizzo iniziale è la posizione in cui si trova la prima istruzione da eseguire, pertanto è la posizione a cui deve passare il controllo il sistema di caricamento, dopo che è stata prodotta l'immagine del processo elaborativo in memoria. Questo indirizzo è interno al primo segmento, il quale è lungo 12810byte (8016byte), pertanto, tra l'indirizzo iniziale e quello ci devono essere delle informazioni amministrative, mentre nello spazio rimanente (esattamente 12 byte) ci sono le istruzioni vere e proprie.

I 116 byte iniziali del primo segmento, di questo esempio, contengono precisamente l'intestazione ELF e la descrizione dei due segmenti del programma.

567.3   Immagine del processo nella memoria virtuale

Il sistema operativo legge il file eseguibile ed estrapola i segmenti, collocandoli in memoria, allocando anche lo spazio non inizializzato (privo pertanto di un segmento nel file eseguibile). Oltre a questo impila sul fondo le variabili di ambiente, gli argomenti della chiamata, il nome del file avviato effettivamente,... Per ultimo, su questa pila, mette la quantità di argomenti ricevuti nella riga di comando e lì posiziona il registro ESP; successivamente, l'incremento di questo registro implica la crescita della pila dei dati.

In un sistema GNU/Linux i processi elaborativi utilizzano un'area della memoria virtuale che va da 0804800016 a BFFFFFFF16, come se ognuno di questi disponesse della stessa dotazione di memoria e fosse sempre tutta propria. È il sistema operativo che crea questa astrazione e alloca o libera la memoria quando serve. Si osservi che lo spazio non allocato non può essere utilizzato e se il programma vi volesse fare riferimento (senza seguire la procedura prevista per l'allocazione) si otterrebbe un errore di segmentazione (segmentation fault).

Figura 567.6. Dal file oggetto eseguibile all'immagine del processo nella memoria virtuale.

processo nella memoria virtuale

Continuando nell'ipotesi delle sezioni precedenti, si può eseguire il programma sotto il controllo di GDB:

gdb prg[Invio]

Per fissare uno stop occorre indicare un indirizzo che punti almeno all'inizio della seconda istruzione (se si pretende di puntare alla prima istruzione, GDB poi non si ferma). Sapendo che la prima istruzione è all'indirizzo 0804807416 e che occupa cinque byte, si può usare l'indirizzo 0804807916 per indicare l'inizio della seconda:

(gdb) break *0x08048079[Invio]

(gdb) run[Invio]

Si vuole verificare che i dati siano dove previsto:

(gdb) print (int)*0x08049080[Invio]

$1 = 77

(gdb) print (int)*0x08049084[Invio]

$2 = 0

Il secondo indirizzo fa riferimento a una memoria non inizializzata che viene posta inizialmente a zero; pertanto il risultato coincide con le previsioni. Si può verificare la presenza dell'intestazione ELF e della descrizione dei segmenti:

(gdb) print /x (char[116])*0x08048000[Invio]

$3 = {0x7f, 0x45, 0x4c, 0x46, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x2, 0x0, 0x3, 0x0, 0x1, 0x0, 0x0, 0x0, 0x74, 0x80, 0x4, 0x8,
0x34, 0x0, 0x0, 0x0, 0xb0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x34, 0x0,
0x20, 0x0, 0x2, 0x0, 0x28, 0x0, 0x7, 0x0, 0x4, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x80, 0x4, 0x8, 0x0, 0x80, 0x4, 0x8, 0x80, 0x0, 0x0,
0x0, 0x80, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1, 0x0,
0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x80, 0x90, 0x4, 0x8, 0x80, 0x90, 0x4, 0x8,
0x4, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0,
0x0}

(gdb) print (char[4])*0x08048000[Invio]

$4 = "\177ELF"

Se si tenta di raggiungere un'area di memoria non allocata, si ottiene un'errore:

(gdb) print /x (int)*0x0804A000[Invio]

Cannot access memory at address 0x804a000

Il registro ESP si trova effettivamente in una zona abbastanza profonda della memoria virtuale:

(gdb) info registers[Invio]

...
esp            0xbf87a540       0xbf87a540
...

(gdb) quit[Invio]

567.4   Allineamento dei segmenti in memoria

Riprendendo il rapporto generato da Objdump, va osservato che i segmenti da caricare in memoria sono «allineati»:

Program Header:
    LOAD off    0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12
         filesz 0x00000080 memsz 0x00000080 flags r-x
    LOAD off    0x00000080 vaddr 0x08049080 paddr 0x08049080 align 2**12
         filesz 0x00000004 memsz 0x00000008 flags rw-

È indicato che l'allineamento è da blocchi di 4 096 byte (100016byte) ovvero 212 byte. Ciò comporta un allontanamento significativo del secondo segmento dal primo (da 0804808016 che sarebbe il primo byte libero dopo il primo segmento, si salta a 0804908016). Questo distacco lo produce il collegatore, o link editor (GNU ld), evidentemente per qualche motivo importante: in un sistema GNU/Linux la memoria virtuale è organizzata in pagine da 4 Kibyte (4 096 byte) e non sarebbe possibile distinguere i permessi di accesso se i segmenti occupassero la stessa pagina.

È il caso di osservare che, nell'esempio mostrato, il distacco appare solo negli indirizzi che i segmenti devono prendere in memoria, perché nel file eseguibile, invece, sono collocati uno di seguito all'altro:

Program Header:
    LOAD off    0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12
         filesz 0x00000080 memsz 0x00000080 flags r-x
    LOAD off    0x00000080 vaddr 0x08049080 paddr 0x08049080 align 2**12
         filesz 0x00000004 memsz 0x00000008 flags rw-

567.5   Script per il collegamento

GNU ld,(1) ovvero il programma che si usa per collegare i file oggetto rilocabili, consente di definire la struttura del file eseguibile da generare, con un certo grado di dettaglio, attraverso quello che viene definito uno script (precisamente link script o linker script).

Esiste una configurazione predefinita di come deve essere realizzata la struttura del file eseguibile e la si può consultare con l'opzione --verbose:

ld --verbose[Invio]

...
OUTPUT_FORMAT("elf32-i386", "elf32-i386",
              "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
SEARCH_DIR("/usr/i486-linux-gnu/lib32"); SEARCH_DIR("/usr/local/lib32");...
SECTIONS
{
  /* Read-only sections, merged into text segment: */
  PROVIDE (__executable_start = 0x08048000); . = 0x08048000 + SIZEOF_HEADERS;
  .interp         : { *(.interp) }
  .hash           : { *(.hash) }
    ...
    ...
    ...
  .debug_weaknames 0 : { *(.debug_weaknames) }
  .debug_funcnames 0 : { *(.debug_funcnames) }
  .debug_typenames 0 : { *(.debug_typenames) }
  .debug_varnames  0 : { *(.debug_varnames) }
  /DISCARD/ : { *(.note.GNU-stack) }
}

Con l'opzione -T è possibile rimpiazzare completamente la configurazione predefinita, indicando lo script da caricare al suo posto. A titolo di esempio viene mostrato uno script molto semplificato che può essere usato con il programma apparso nelle sezioni precedenti, producendo un risultato simile:

ENTRY (_start)
SECTIONS {
    . = 0x08048000 + SIZEOF_HEADERS;
    .text . : { *(.text) }
    .data ALIGN (0x1000) : { *(.data) }
    .bss . : {
        *(.bss)
        *(COMMON)
    }
}

La direttiva che appare nella prima riga, dichiara il simbolo in corrispondenza del quale associare il punto di inizio; infatti, secondo le convenzioni comuni, l'etichetta _start è quella che in un sorgente in linguaggio assemblatore segnala l'inizio del programma:

ENTRY (_start)

Successivamente appare un blocco, all'interno del quale si dichiara la configurazione delle sezioni del programma. La prima direttiva di questo blocco definisce l'indirizzo iniziale di riferimento, ottenuto sommando a 0804800016 la dimensione dell'intestazione (ovvero l'intestazione ELF vera e propria, assieme alla descrizione dei segmenti):

    . = 0x08048000 + SIZEOF_HEADERS;

Di seguito appare la descrizione delle tre sezioni tipiche: .text, .data e .bss. La prima è la più semplice, in quanto si limita a dichiarare di collocare la sezione .text a partire dalla posizione corrente (quella raggiunta in quel punto), rappresentata da un punto singolo, ., purché ci siano effettivamente sezioni con quel nome da collocare:

    .text . : { *(.text) }

In questo tipo di direttiva, il punto che rappresenta la posizione corrente è facoltativo (nel senso che può essere omesso); ciò che appare tra parentesi graffe è il contenuto che la nuova sezione .text deve avere e in questo caso rappresenta la somma delle sezioni .text dei file oggetto rilocabili. In particolare, l'asterisco iniziale serve a precisare che in mancanza di tali sezioni nei file oggetto rilocabili, non si deve creare la sezione corrispondente nel file eseguibile.

La sezione .data viene dichiarata in modo simile, con la differenza che, al posto del punto, viene indicato di spostare in avanti l'indirizzo in modo che sia un multiplo di 100016, ovvero di 409610. In questo modo si vuole ottenere che la sezione .data sia distanziata nel file eseguibile e che così distante sia anche il segmento caricato in memoria. In pratica, l'espressione ALIGN (0x1000) si traduce nel calcolo di un indirizzo adeguato all'allineamento che si intende ottenere, di 4 096 byte:

    .data ALIGN (0x1000) : { *(.data) }

L'ultima sezione, .bss, è un po' più articolata, in quanto prevede l'inclusione delle sezioni con lo stesso nome provenienti dai file oggetto rilocabili (se ce ne sono), con l'aggiunta di tutto ciò che costituisce dati non inizializzati, rappresentato dall'espressione *(COMMON).

Riprendendo il programma di esempio già visto nelle sezioni precedenti, ammesso che lo script appena descritto sia contenuto nel file config.ld, il file oggetto prg.o potrebbe essere elaborato nel modo seguente:

ld -T config.ld -o prg prg.o[Invio]

Ecco cosa si può vedere con Objdump:

objdump -x prg[Invio]

prg:     file format elf32-i386
prg
architecture: i386, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x08048074

Program Header:
    LOAD off    0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12
         filesz 0x00000080 memsz 0x00000080 flags r-x
    LOAD off    0x00001000 vaddr 0x08049000 paddr 0x08049000 align 2**12
         filesz 0x00000004 memsz 0x00000008 flags rw-

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         0000000c  08048074  08048074  00000074  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000004  08049000  08049000  00001000  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000004  08049004  08049004  00001004  2**2
                  ALLOC
SYMBOL TABLE:
08048074 l    d  .text  00000000 .text
08049000 l    d  .data  00000000 .data
08049004 l    d  .bss   00000000 .bss
00000000 l    d  *ABS*  00000000 .shstrtab
00000000 l    d  *ABS*  00000000 .symtab
00000000 l    d  *ABS*  00000000 .strtab
08049000 l       .data  00000000 aaa
08049004 l     O .bss   00000004 bbb
08048074 g       .text  00000000 _start

Come si vede, questa volta il segmento riferito alla sezione .data parte esattamente da 0804900016, ma così vale anche per la posizione della stessa sezione .data nel file eseguibile. In pratica, ciò comporta che il file eseguibile sia un po' più grande rispetto a prima, mentre l'utilizzo della memoria non cambia in modo sostanziale.

Sempre a titolo di esempio, si può provare a vedere cosa succede se si evita di allineare la sezione .data:

ENTRY (_start)
SECTIONS {
    . = 0x08048000 + SIZEOF_HEADERS;
    .text . : { *(.text) }
    .data . : { *(.data) }
    .bss . : {
        *(.bss)
        *(COMMON)
    }
}

In questo modo, dato che il contenuto della sezione .text è molto breve, succede che il contenuto di tutte le sezioni finisce nello stesso segmento, il quale, di conseguenza, deve avere tutti i permessi necessari:

ld -T config.ld -o prg prg.o[Invio]

objdump -x prg[Invio]

prg:     file format elf32-i386
prg
architecture: i386, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x08048074

Program Header:
    LOAD off    0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12
         filesz 0x00000084 memsz 0x00000088 flags rwx

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         0000000c  08048074  08048074  00000074  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000004  08048080  08048080  00000080  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000004  08048084  08048084  00000084  2**2
                  ALLOC
SYMBOL TABLE:
08048074 l    d  .text  00000000 .text
08048080 l    d  .data  00000000 .data
08048084 l    d  .bss   00000000 .bss
00000000 l    d  *ABS*  00000000 .shstrtab
00000000 l    d  *ABS*  00000000 .symtab
00000000 l    d  *ABS*  00000000 .strtab
08048080 l       .data  00000000 aaa
08048084 l     O .bss   00000004 bbb
08048074 g       .text  00000000 _start

Naturalmente, anche il file eseguibile torna a essere di dimensioni più piccole.

Sia chiaro che gli esempi di script apparsi qui non possono essere validi in generale, ma servono solo per comprendere a grandi linee il meccanismo. Per utilizzare seriamente questo strumento occorre prima uno studio approfondito del manuale di GNU ld.

567.6   Osservazioni sui simboli

I file oggetto, rilocabili o eseguibili, contengono un elenco di simboli, che Objdump raccoglie in una tabella, denominata SYMBOL TABLE. Vale la pena di confrontare tale tabella nelle varie situazioni descritte in questo capitolo, come riepilogato nelle figure successive.

Figura 567.24. La tabella dei simboli nel file oggetto rilocabile prodotto dalla compilazione del file sorgente.

00000000 l    d  .text  00000000 .text
00000000 l    d  .data  00000000 .data
00000000 l    d  .bss   00000000 .bss
00000000 l       .data  00000000 aaa
00000000 l     O .bss   00000004 bbb
00000000 g       .text  00000000 _start

Figura 567.25. La tabella dei simboli nel file oggetto eseguibile prodotto da GNU ld secondo la configurazione predefinita.

08048074 l    d  .text  00000000 .text
08049080 l    d  .data  00000000 .data
08049084 l    d  .bss   00000000 .bss
00000000 l    d  *ABS*  00000000 .shstrtab
00000000 l    d  *ABS*  00000000 .symtab
00000000 l    d  *ABS*  00000000 .strtab
08049080 l       .data  00000000 aaa
08049084 l     O .bss   00000004 bbb
08048074 g       .text  00000000 _start
08049084 g       *ABS*  00000000 __bss_start
08049084 g       *ABS*  00000000 _edata
08049088 g       *ABS*  00000000 _end

Figura 567.26. La tabella dei simboli nel file oggetto eseguibile prodotto da GNU ld secondo la configurazione predisposta nella sezione precedente.

08048074 l    d  .text  00000000 .text
08048080 l    d  .data  00000000 .data
08048084 l    d  .bss   00000000 .bss
00000000 l    d  *ABS*  00000000 .shstrtab
00000000 l    d  *ABS*  00000000 .symtab
00000000 l    d  *ABS*  00000000 .strtab
08048080 l       .data  00000000 aaa
08048084 l     O .bss   00000004 bbb
08048074 g       .text  00000000 _start

Si può osservare che, dopo la compilazione che produce un file oggetto rilocabile, appaiono gli stessi simboli previsti nel sorgente, con l'aggiunta di nomi corrispondenti a quelli delle sezioni. Nella trasformazione standard in file eseguibile, si vede la comparsa di altri simboli, in particolare: .shstrtab, .symtab, .strtab. Questi rappresentano la collocazione nel file di informazioni amministrative, relative al formato ELF. Inoltre, nel caso specifico dell'eseguibile generato secondo la configurazione predefinita di GNU ld, si vede la comparsa di simboli aggiuntivi che evidentemente dipendono dall'organizzazione della configurazione stessa.

Per comprendere come si possano inserire dei simboli addizionali attraverso lo script per GNU ld, si può riprendere l'esempio già visto nella sezione precedente, ritoccando leggermente la definizione della sezione .bss:

ENTRY (_start)
SECTIONS {
    . = 0x08048000 + SIZEOF_HEADERS;
    .text . : { *(.text) }
    .data ALIGN (0x1000) : { *(.data) }
    .bss . : {
        _sbss = .;
        *(.bss)
        *(COMMON)
        _ebss = .;
    }
}

I simboli che si vogliono aggiungere sono _sbss e _ebss, con lo scopo di individuare l'inizio e la fine della nuova sezione .bss.

Figura 567.28. La tabella dei simboli dopo l'introduzione forzata di _sbss e _ebss.

SYMBOL TABLE:
08048074 l    d  .text  00000000 .text
08049000 l    d  .data  00000000 .data
08049004 l    d  .bss   00000000 .bss
00000000 l    d  *ABS*  00000000 .shstrtab
00000000 l    d  *ABS*  00000000 .symtab
00000000 l    d  *ABS*  00000000 .strtab
08049000 l       .data  00000000 aaa
08049004 l     O .bss   00000004 bbb
08049004 g       .bss   00000000 _sbss
08049008 g       .bss   00000000 _ebss
08048074 g       .text  00000000 _start

Eventualmente si può sperimentare cosa cambia nel contenuto dei file oggetto (rilocabili o eseguibili) quando si compila un sorgente con l'opzione --gstabs di GNU AS o con l'opzione -g di NASM.

567.7   Formati dei file oggetto

I file oggetto rilocabili e i file eseguibili possono essere realizzati secondo diversi formati, ma dipende dal sistema operativo qual è la scelta che si deve operare. Negli esempi mostrati, partendo dal presupposto di utilizzare un sistema GNU/Linux, si fa riferimento al formato ELF, in quanto è quello che deve essere usato e gli strumenti comuni sono già configurati per generare file conformi a tale standard.

Il formato del file che si deve produrre condiziona anche i tipi di sezioni che si possono dichiarare nel sorgente in linguaggio assemblatore. Il formato ELF dà molta libertà, comunque prevede una serie numerosa di sezioni con funzioni specifiche, in particolare .rodata che comporta la creazione di un segmento di memoria con dati inizializzati, ma in sola lettura.

567.8   Riferimenti


1) GNU Binutils   GNU GPL


Appunti di informatica libera 2008 --- Copyright © 2000-2008 Daniele Giacomini -- <appunti2 (ad) gmail·com>


Dovrebbe essere possibile fare riferimento a questa pagina anche con il nome dal_sorgente_all_x0027_immagine_in_memoria.htm

[successivo] [precedente] [inizio] [fine] [indice generale] [indice ridotto] [indice analitico] [home]

Valid ISO-HTML!

CSS validator!

Gjlg Metamotore e Web Directory