Formato file oggetto comune

Il formato file oggetto comune ( COFF ; formato file oggetto generale tedesco  ) è un formato binario per programmi e file oggetto. È stato introdotto da AT&T per il sistema operativo Unix System V ed è ora utilizzato principalmente nel formato PE per Windows basato su di esso (vedere Portable Executable ). Per le estensioni di file vengono spesso utilizzati "cof", "obj" o " lib " , se disponibili e oltre alle estensioni utilizzate per PE .

storia

Il formato a.out è stato originariamente utilizzato per i file eseguibili su Unix . Tuttavia, ciò non supportava gli sviluppi moderni come le informazioni di debug incorporate o le librerie dinamiche . Pertanto AT&T ha sviluppato il Common Object File Format per la Release 3 di Unix System V. Poiché il COFF originale era limitato in termini di design, diverse varianti sviluppate tra i produttori Unix (ad esempio XCOFF di IBM per AIX , ECOFF di SGI e altri). Con la versione 4 di System V nel 1989, AT&T ha sostituito COFF con il nuovo formato ELF (Executable and Linking Format) sviluppato insieme a Sun Microsystems .

caratteristiche

Con COFF è diventato possibile incorporare le informazioni di debug direttamente in un file binario. Le librerie possono essere collegate dinamicamente e gestite come file separati, quindi non è necessario che diventino una parte non modificabile e non intercambiabile di un file di programma. A tale scopo, tutti gli indirizzi nelle voci di riposizionamento vengono caricati nella memoria virtuale dell'applicazione rispetto all'indirizzo effettivo della sezione. Questo indirizzo necessita della sezione solo per il tempo di compilazione da impostare già in fase di programmazione. Anche i formati sviluppati secondo COFF hanno queste capacità.

uso

Le versioni moderne di Unix e Linux non supportano più COFF, ma è ancora utilizzato per i sistemi embedded . In Windows NT (e versioni precedenti) la variante COFF Portable Executable (PE, a volte anche PE / COFF) è il formato di file standard per le librerie e gli eseguibili, ma questa variante differisce leggermente dal COFF originale.

struttura

Un file COFF è composto da più parti. Inizia con l' intestazione del file e un'intestazione opzionale . Segue una serie di sezioni costituite da un'intestazione, una sezione dati e un'area per le voci del numero di riga e un'area per le voci di trasferimento. Alla fine del file seguono una tabella dei simboli e una tabella delle stringhe di caratteri .

Intestazione del file

L' intestazione del file si trova all'inizio di un file. I dati vengono memorizzati lì che descrivono la struttura dell'intero file. Ciò include il numero magico , che è diverso per le diverse varianti ( PE , XCOFF, ecc.), Un timestamp Unix con l'ora in cui è stato creato il file e la posizione e la dimensione delle altre sezioni. Oltre a utilizzare Flag varie proprietà del file da definire (es. Come se sia eseguibile).

struct filehdr {
    unsigned short  f_magic;        /* Magische Zahl */
    unsigned short  f_nscns;        /* Anzahl der Sektionen in der Datei */
    long            f_timdat;       /* Zeitstempel der Erstellung */
    long            f_symptr;       /* Zeiger zur Symboltabelle */
    long            f_nsyms;        /* Größe der Symboltabelle */
    unsigned short  f_opthdr;       /* Größe der "optional header" */
    unsigned short  f_flags;        /* Flags */
};

Intestazione opzionale

L' intestazione opzionale contiene dati diversi a seconda della variante COFF. Viene spesso utilizzato per altre informazioni necessarie per l'esecuzione (ad esempio l'indirizzo di ingresso). Poiché può essere di diverse lunghezze, la sua dimensione è memorizzata nella "File Header".

Intestazione della sezione

L' intestazione della sezione contiene i dati su una sezione, in particolare quanto è grande e dove deve essere caricata nella memoria virtuale . Per i file eseguibili, solitamente l'inizio della memoria, ad es. H. la prima sezione viene caricata all'indirizzo 0; questo può essere diverso per i dati collegati. Contengono inoltre un puntatore e la dimensione delle voci del numero di riga e delle voci di trasferimento.

struct sectionhdr {
    char           s_name[8];  /* Name der Sektion */
    unsigned long  s_paddr;    /* Speicheradresse, an die diese Sektion geladen werden soll*/
    unsigned long  s_vaddr;    /* virtuelle Adresse, an die diese Sektion geladen werden soll */
    unsigned long  s_size;     /* Größe der Sektion (inklusive Header)*/
    unsigned long  s_scnptr;   /* Zeiger zu den Daten dieser Sektion */
    unsigned long  s_relptr;   /* Zeiger zu den Relokationseinträgen dieser Sektion */
    unsigned long  s_lnnoptr;  /* Zeiger zu dem Zeilennummerneinträgen dieser Sektion */
    unsigned short s_nreloc;   /* Anzahl der Relokationseinträge */
    unsigned short s_nlnno;    /* Anzahl der Zeilennummerneinträge */
    unsigned long  s_flags;    /* Flags */
};

Sezione dati

La sezione dati può essere di diverse lunghezze. Contiene i dati effettivi nel file. Di solito si tratta di istruzioni in codice macchina , spazio per variabili e dati necessari per l'esecuzione - in breve, il programma vero e proprio.

Ingresso del trasferimento

Una voce di riposizionamento definisce dove è possibile trovare i simboli nella sezione dati. Questo è definito individualmente per ogni simbolo.

typedef struct reloc{
    unsigned long  r_vaddr;   /* Adresse für die Relokation */
    unsigned long  r_symndx;  /* Symbol, für das die Relokation gilt */
    unsigned short r_type;    /* Type der Relokation*/
};

Inserimento del numero di riga

Una voce del numero di riga definisce quale riga nel codice sorgente corrisponde a quale istruzione nel codice macchina. Ciò è particolarmente importante per il debug delle applicazioni. Ogni sezione ha la propria tabella di numeri di riga. Le righe vengono conteggiate individualmente per ciascuna funzione nella sezione.

typedef struct lineno{
    union l_addr{
        unsigned long l_symndx;  /* Index des Namens der Funktion */
        unsigned long l_paddr;   /* Adresse der Zeilennummer */
    };
    unsigned short l_lnno;  /* Zeilennummer */
};

I numeri di riga vengono contati dall'inizio di ogni funzione da 0. Per una riga su cui inizia una l_lnno = 0funzione, viene l_symndxcreata una voce con e il simbolo della funzione così com'è . Per ogni riga aggiuntiva nella funzione, viene creata una voce con il numero di righe dall'inizio della funzione as l_lnnoe l'indirizzo della prima istruzione da questa riga as l_paddr.

Tabella dei simboli

La tabella dei simboli contiene informazioni sui simboli nel file. I simboli sono ad es. B. Funzioni o variabili che possono essere utilizzate da altri programmi. La dimensione e la posizione della tabella dei simboli sono specificate nell'intestazione del file . La tabella dei simboli è composta dalle voci del modulo

typedef struct sysent{
  union e {
    char e_name[8];             /* Name des Symbols */
    struct e {
      unsigned long e_zeroes;   /* Falls 0, ist der Name des Symbols in der Zeichenkettentabelle angelegt*/
      unsigned long e_offset;   /* Position des Symbols in der Zeichenkettentabelle */
    };
  };
  unsigned long e_value;        /* Wert (in der Regel Adresse) des Symbols */
  short e_scnum;                /* Sektion */
  unsigned short e_type;        /* Datentyp */
  unsigned char e_sclass;       /* Speicherklasse */
  unsigned char e_numaux;       /* Anzahl zusätzlicher Einträge*/
};

Il nome del simbolo viene e_namesalvato se contiene otto caratteri o meno. Altrimenti viene memorizzato nella tabella delle stringhe di caratteri, quindi è e_zeros = 0e e_offsetindica la posizione di questa voce nella tabella delle stringhe di caratteri. Il "valore" del simbolo viene e_valuesalvato in. Questo è solitamente l'indirizzo in cui è memorizzato questo simbolo, che a sua volta dipende dal tipo di dati e dalla classe di archiviazione in cui è e_sclassarchiviato. e_typedefinisce il tipo di dati del simbolo. Può essere un tipo elementare (int, float ecc.) O un tipo composto (struct, union). Inoltre, il simbolo può definire un valore, un puntatore, un campo ("array") o una funzione che restituisce questo valore. e_classdefinisce la classe di archiviazione, ovvero dove e come viene memorizzato il simbolo (ad esempio può essere un simbolo esterno, un argomento di funzione, una variabile globale o statica, ecc.). Possono seguire voci aggiuntive a seconda del tipo di simbolo. Viene inoltre e_numauxindicato il numero di queste voci .

Tabella delle stringhe

La tabella delle stringhe segue il file alla fine. Inizia con un numero intero in cui è memorizzata la lunghezza della tabella. Quindi tutte le corde si susseguono. Per leggere una stringa di caratteri, devi conoscere la sua posizione e puoi iniziare a leggere a questo punto. Le stringhe hanno terminazione zero .

Prove individuali

  1. Common Object File Format Texas Instruments, accesso 8 marzo 2014
  2. Panoramica su SCO System V Release 3 ( Memento del l' originale dal 9 marzo 2014 in Internet Archive ) Info: Il dell'archivio collegamento è stato inserito automaticamente e non ancora verificata. Si prega di controllare l'originale e il collegamento all'archivio secondo le istruzioni, quindi rimuovere questo avviso. HP, accesso 8 marzo 2014  @ 1@ 2Modello: Webachiv / IABot / h10025.www1.hp.com
  3. ^ XCOFF Object File Format IBM, accesso 8 marzo 2013
  4. Specifica del formato del file oggetto / tabella dei simboli Compaq / HP, accesso 8 marzo 2014
  5. Typer of Executable ( Memento of the original from March 9, 2014 in Internet Archive ) Info: Il link all'archivio è stato inserito automaticamente e non è stato ancora verificato. Si prega di controllare l'originale e il collegamento all'archivio secondo le istruzioni, quindi rimuovere questo avviso. Linux.org, accesso 8 marzo 2014 @ 1@ 2Modello: Webachiv / IABot / www.linux.org
  6. Specifiche PE e COFF , Microsoft Developer Network, accesso 8 marzo 2014

link internet