Edit page

Papel de um Compilador

Produzir um Object Module

Tradução e Startup

O compilador traduz o programa para instruções de máquina, dando informação para construir um programa completo através de peças soltas:

  • Header: descreve os componentes de um object module;
  • Text segment: tradução das instruções;
  • Static data segment: dados alocados para dar vida ao programa;
  • Relocation info: para componentes que dependem da localização absoluta do loaded program;
  • Symbol table: definições globais e referências externas;
  • Debug info: para associação com o código fonte.

Ligar Object Modules

Ao fazermos linking de object modules produzimos uma imagem executável que converge segmentos, resolve labels, que determinam o seu endereço, e corrigem a localização-dependente e referências externas. Para além disso, não podemos deixar as dependências de localização para corrigirem a mudança de carregador, contudo, com memória vistual, tal não é necessário visto que o programa pode ser carregado para uma localização absoluta no espaço de memória virtual.

Mas como é que carregamos um ficheiro no disco para a memória? Há seis passos diferentes:

  1. Leitura do header para determinar o tamanho dos segmentos;
  2. Criação do espaço de endereçamento virtual;
  3. Cópia do texto e inicialização dos dados para a memória:
    • Ou definição das entradas da tabela de páginas para que possam ser inseridas;
  4. Configuração dos argumentos na pilha;
  5. Inicialização dos registos (incluindo $sp, $fp, $gp);
  6. Salto para o início da rotina:
    • Copia dos argumentos para $a0, ... e chama a função main;
    • Quando a função main retorna, faz um syscall do exit.

Dynamic Linking

À medida que vamos precisando, temos que ir dando link/load da nossa biblioteca. Para este processo é obrigatório que o código seja realocado de modo a evitar que as imagens inchem por causa da ligação estática a todas as bibliotecas referenciadas. Assim, novas versões de bibliotecas são automaticamente apanhadas. Também podemos ter lazy linkage: a ligação feita somente quando uma função é chamada, sabendo que só funções é que de facto podem ser ligadas.

Lazy linkage

Aplicações Java

É importante referir que no Just in time compiler é um tradutor on the fly, ou seja, pega nas instruções Java e recompila em Assembly no momento.

x86 Instruction Encoding

x86 Instruction Encoding

O tamanho das variáveis que devem ser condificadas têm bytes postfix que especificam o modo de endereçamento e operações de bytes de prefixos.

Implementação do IA-32

São conjuntos complexos de instrução que tornam a sua implementação difícil visto que o hardware traduz instruções para micro-operações mais simples, ou seja instruções simples do género 1-1, ou instruções complexas do género 1-muitos; micromotor parecido com RISC; e mercado de partilha que turna isto economicamente viável.

Equívocos Comuns

É fácil cair em conclusões precipitadas relativamente aos compiladores e processadores:

A primeira é que ter instruções mais complexas implica execuções mais rápidas. Isto nem sempre é verdade visto que apesar de serem necessárias menos instruções, estas são mais complexas e difíceis de implementar, o que pode obrigar o processador a correr a uma frequência mais baixa, "atrasando" todas as instruções, incluindo as mais simples. Para além disso, os compiladores são extremamente bons a escrever código eficiente a partir de instruções simples.

A segunda é que devemos escrever trechos de código em Assembly se queremos que sejam mais eficientes. Pelo contrário, os compiladores modernos são bem melhores que qualquer um de nós a escrever Assembly. O tempo desperdiçado a escrever 50 linhas de Assembly para uma função de 10 linhas em C é melhor utilizado a estudar para OC.