Formato de arquivo de objeto comum

O formato de arquivo de objeto comum ( COFF ; formato de arquivo de objeto geral alemão  ) é um formato binário para programas e arquivos de objeto. Ele foi introduzido pela AT&T para o sistema operacional Unix System V e agora é usado principalmente no formato PE para Windows baseado nele (consulte Executável portátil ). Para extensões de arquivo "cof", "obj" ou " lib " são freqüentemente usados, se disponíveis e além das extensões usadas para PE .

história

O formato a.out foi originalmente usado para arquivos executáveis ​​no Unix . No entanto, isso não suportava desenvolvimentos modernos, como informações de depuração incorporadas ou bibliotecas dinâmicas . Portanto, a AT&T desenvolveu o Common Object File Format para a versão 3 do Unix System V. Uma vez que o COFF original era limitado em termos de design, diferentes variantes desenvolvidas entre os fabricantes de Unix (por exemplo, XCOFF da IBM para AIX , ECOFF da SGI e outros). Com o Release 4 do System V em 1989, a AT&T substituiu o COFF pelo novo formato ELF (Executable and Linking Format) desenvolvido em conjunto com a Sun Microsystems .

características

Com o COFF, tornou-se possível incorporar informações de depuração diretamente em um arquivo binário. As bibliotecas podem ser vinculadas dinamicamente e tratadas como arquivos separados, portanto, não precisam se tornar uma parte imutável e não intercambiável de um arquivo de programa. Para isso, todos os endereços nas entradas de relocação são carregados na memória virtual do aplicativo em relação ao endereço real da seção. Este endereço precisa da seção apenas para o tempo de compilação já estar definido na programação. Os formatos desenvolvidos de acordo com o COFF também possuem esses recursos.

usar

As versões modernas do Unix e do Linux não suportam mais COFF, mas ainda é usado para sistemas embarcados . No Windows NT (e anteriores), a variante COFF Portable Executable (PE, às vezes também PE / COFF) é o formato de arquivo padrão para bibliotecas e executáveis, mas essa variante difere um pouco do COFF original.

estrutura

Um arquivo COFF consiste em várias partes. Ele começa com o cabeçalho do arquivo e um cabeçalho opcional . Isso é seguido por várias seções que consistem em um cabeçalho, uma seção de dados e uma área para entradas de número de linha e uma área para entradas de relocação. Uma tabela de símbolos e uma tabela de sequência de caracteres seguem no final do arquivo .

Cabeçalho do arquivo

O cabeçalho do arquivo está no início de um arquivo. Lá são armazenados dados que descrevem a estrutura de todo o arquivo. Isso inclui o número mágico , que é diferente para as diferentes variantes ( PE , XCOFF, etc.), um carimbo de data / hora Unix com a hora em que o arquivo foi criado e a posição e o tamanho de outras seções. Além de usar Sinalizar várias propriedades do arquivo a ser definido (por exemplo, como se ele é executável).

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 */
};

Cabeçalho opcional

O cabeçalho opcional contém dados diferentes dependendo da variante COFF. É frequentemente usado para outras informações necessárias para a execução (por exemplo, o endereço de entrada). Como pode ter comprimentos diferentes, seu tamanho é armazenado no "Cabeçalho do Arquivo".

Cabeçalho da seção

O cabeçalho da seção contém dados sobre uma seção, em particular seu tamanho e onde deve ser carregada na memória virtual . Para arquivos executáveis, geralmente o início da memória, ou seja, H. a primeira seção é carregada no endereço 0; isso pode ser diferente para dados vinculados. Eles também contêm um ponteiro e o tamanho das entradas do número da linha e das entradas de relocação.

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 */
};

Seção de dados

A seção de dados pode ter comprimentos diferentes. Ele contém os dados reais no arquivo. Geralmente são instruções em código de máquina , espaço para variáveis ​​e dados que são necessários para a execução - em resumo, o programa real.

Entrada de realocação

Uma entrada de relocação define onde os símbolos podem ser encontrados na seção de dados. Isso é definido individualmente para cada símbolo.

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*/
};

Entrada de número de linha

Uma entrada de número de linha define qual linha no código-fonte corresponde a qual instrução no código de máquina. Isso é especialmente importante para depurar aplicativos. Cada seção tem sua própria tabela de números de linha. As linhas são contadas individualmente para cada função na seção.

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 */
};

Os números de linha são contados a partir do início de cada função a partir de 0. Para uma linha na qual uma função começa, uma entrada com l_lnno = 0e o símbolo da função conforme é l_symndxcriada. Para cada linha adicional na função, uma entrada é criada com o número de linhas desde o início da função como l_lnnoe o endereço da primeira instrução dessa linha como l_paddr.

Tabela de símbolos

A tabela de símbolos contém informações sobre os símbolos do arquivo. Os símbolos são, por exemplo B. Funções ou variáveis ​​que podem ser usadas por outros programas. O tamanho e a posição da tabela de símbolos são especificados no cabeçalho do arquivo . A tabela de símbolos consiste em entradas do formulário

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*/
};

O nome do símbolo é e_namesalvo se tiver oito caracteres ou menos. Caso contrário, é armazenado na tabela de sequência de caracteres e, em seguida, é e_zeros = 0, e e_offsetindica a posição dessa entrada na tabela de sequência de caracteres. O "valor" do símbolo é e_valuesalvo em. Este é geralmente o endereço no qual este símbolo é armazenado, que por sua vez depende do tipo de dados e da classe de e_sclassarmazenamento em que está armazenado. e_typedefine o tipo de dados do símbolo. Pode ser um tipo elementar (int, float etc.) ou um tipo composto (struct, union). Além disso, o símbolo pode definir um valor, um ponteiro, um campo ("array") ou uma função que retorna esse valor. e_classdefine a classe de armazenamento, ou seja, onde e como o símbolo é armazenado (por exemplo, pode ser um símbolo externo, um argumento de função, uma variável global ou estática, etc.). Entradas adicionais podem ocorrer dependendo do tipo de símbolo. O número dessas entradas também é e_numauxindicado.

Mesa de corda

A tabela de strings segue o arquivo no final. Ele começa com um inteiro no qual o comprimento da tabela é armazenado. Então, todas as cordas seguem umas às outras. Para ler uma sequência de caracteres, você precisa saber sua posição e pode começar a ler neste ponto. As strings são terminadas em zero .

Evidência individual

  1. Formato de arquivo de objeto comum Texas Instruments, acessado em 8 de março de 2014
  2. vista geral sobre o SCO System V Release 3 ( Memento do originais de 09 março de 2014 na Internet Archive ) Info: O arquivo de ligação foi inserido automaticamente e ainda não foi marcada. Verifique o link original e o arquivo de acordo com as instruções e remova este aviso. HP, acessado em 8 de março de 2014  @ 1@ 2Modelo: Webachiv / IABot / h10025.www1.hp.com
  3. ^ XCOFF Object File Format IBM, acessado em 8 de março de 2013
  4. Especificação de formato de arquivo de objeto / tabela de símbolos Compaq / HP, acessado em 8 de março de 2014
  5. Tipos de Executable ( Memento do originais de 9 de março de 2014 na Internet Archive ) Info: O arquivo de ligação foi inserido automaticamente e ainda não foi marcada. Verifique o link original e o arquivo de acordo com as instruções e remova este aviso. Linux.org, acessado em 8 de março de 2014 @ 1@ 2Modelo: Webachiv / IABot / www.linux.org
  6. Especificação PE e COFF , Microsoft Developer Network, acessada em 8 de março de 2014

Links da web