Por que os compiladores produzem código de montagem?


19

A linguagem assembly é convertida em linguagem de máquina pelo assembler. Por que um compilador converteria linguagem de alto nível em assembly? Não é possível converter diretamente do idioma de alto nível para o código da máquina?

Respostas:


22

Outro motivo para os compiladores produzirem a montagem em vez do código de máquina adequado são:

  • Os endereços simbólicos usados ​​pelos montadores em vez dos endereços de máquinas codificantes facilitam a realocação de códigos .
  • Linking código de pode envolver verificações de segurança, como verificação de tipo, e isso é mais fácil com nomes simbólicos.
  • Pequenas alterações no código da máquina são mais fáceis de serem alteradas alterando o montador em vez do gerador de código.

por que a linguagem assembly é tão eficiente, embora também seja escrita em inglês e como o processador a entende?
CODERSAM 04/10

3
O Assembly @CODERSAM é uma linguagem formal, não uma linguagem natural. É muito próximo à linguagem de máquina. Portanto, a inflação não introduz ineficiências.
Martin Berger

quando você diz "muito próximo da linguagem de máquina", o que isso significa? Estou realmente confuso com isso!
CODERSAM #

2
@CODERSAM O significado exato é complicado, mas algo como homomorfismo na álgebra. Ao traduzir, diga "add eax, # 2", que é o assembly x86, você pode convertê-lo para d7f5 (ou qualquer outra coisa que possa ser o código operacional), imediatamente, sem olhar para o contexto, sem adicionar mais nada. Assembly não tem abstração.
Martin Berger

1
"Assembly não tem abstração" - eu diria que os nomes dos rótulos já são uma abstração (dos deslocamentos). Além disso, o contexto desempenha um papel: por exemplo, add eax,2pode ser traduzido para 83 c0 02ou para 66 83 c0 02, dependendo da última diretiva ocorrida como use16.
Ruslan

15

Um compilador geralmente converte código de alto nível diretamente em linguagem de máquina, mas pode ser construído de forma modular para que um back-end emita código de máquina e outro código de montagem (como o GCC). A fase de geração de código produz "código", que é uma representação interna do código da máquina, que deve ser convertida em um formato utilizável, como linguagem de máquina ou código de montagem.


Além disso, se a fonte puder incluir algum código de montagem, um mecanismo deverá estar disponível para converter essa montagem embutida de qualquer maneira.
Paul A. Clayton

por que a linguagem assembly é tão eficiente, embora também seja escrita em inglês e como o processador a entende?
CODERSAM

1
A linguagem assembly é uma descrição "inglesa" do código da máquina.
Yuval Filmus

11

Historicamente, vários compiladores notáveis ​​produziram código de máquina diretamente. Existem algumas dificuldades em fazê-lo, no entanto. Geralmente, alguém que está tentando confirmar que um compilador está funcionando corretamente achará mais fácil examinar a saída do código de montagem do que o código de máquina. Além disso, é possível (e historicamente comum) usar um compilador C ou Pascal de uma passagem para produzir um arquivo em linguagem assembly que pode ser processado usando um montador de duas passagens. A geração direta de código exigiria o uso de um compilador C ou Pascal de duas passagens ou o uso de um compilador de passagem única seguido por alguns meios de correção de endereços de salto para frente [se um ambiente de tempo de execução disponibilizar o tamanho de um programa iniciado em um ponto fixo, um compilador pode escrever uma lista de patches no final do código e fazer com que o código de inicialização aplique esses patches no tempo de execução; essa abordagem aumentaria o tamanho do executável em cerca de quatro bytes por ponto de correção, mas melhoraria a velocidade de geração do programa].

Se o objetivo é ter um compilador que seja executado rapidamente, a geração direta de código pode funcionar bem. Para a maioria dos projetos, no entanto, o custo de gerar o código da linguagem assembly e montá-lo realmente não é um grande problema atualmente. Ter compiladores produzindo código de uma forma que possa interagir bem com o código produzido por outros compiladores geralmente é um benefício grande o suficiente para justificar o aumento nos tempos de compilação.


1

Mesmo plataformas que usam o mesmo conjunto de instruções podem ter diferentes formatos de arquivo de objeto realocáveis. Posso pensar em "a.out" (UNIX antigo), OMF, MZ (EXE do MS-DOS), NE (Windows de 16 bits), COFF (Sistema UNIX V), Mach-O (OS X e iOS) e ELF (Linux e outros), bem como variantes, como XCOFF (AIX), ECOFF (SGI) e Portable Executable (PE) baseado em COFF no Windows de 32 bits. Um compilador que produz linguagem assembly não precisa conhecer muito sobre os formatos de arquivo do objeto, permitindo que o assembler e o vinculador encapsulem esse conhecimento em um processo separado.

Consulte também Diferença entre OMF e COFF no estouro de pilha.


1

Geralmente, os compiladores trabalham internamente com sequências de instruções. Cada instrução será representada por uma estrutura de dados que representa o nome da operação, operandos e assim por diante. Quando os operandos são endereços, esses endereços geralmente são referências simbólicas, e não valores concretos.

Montador de saída é relativamente simples. É basicamente uma questão de pegar a estrutura de dados interna dos compiladores e despejá-la em um arquivo de texto em um formato específico. A saída do assembler também é relativamente fácil de ler, o que é útil quando você precisa verificar o que o compilador está fazendo.

A saída de arquivos de objetos binários é significativamente mais trabalhosa. O gravador do compilador precisa saber como todas as instruções são codificadas (o que pode estar longe de ser trivial em alguns CPUS), ele precisa converter algumas referências simbólicas em endereços relativos de contadores de programas e outras em alguma forma de metadados no arquivo de objeto binário . Eles precisam escrever tudo em um formato altamente específico do sistema.

Sim, você absolutamente pode criar um compilador que possa gerar objetos binários diretamente, sem escrever o assembler como uma etapa intermediária. A questão, como muitas outras coisas no desenvolvimento de software, é se a redução no tempo de compilação vale o trabalho extra de desenvolvimento e manutenção.

O compilador com o qual estou mais familiarizado (freepascal) pode gerar assembler em todas as plataformas, mas apenas objetos binários de saída diretamente em um subconjunto de plataformas.


1

Um compilador deve ser capaz de produzir uma saída do assembler, além do código realocável normal, para o benefício do programador.

Uma vez eu simplesmente não encontrei o bug em um programa C em execução no Unix System V em uma máquina LSI-11. Nada parecia funcionar. Finalmente, em desespero, o compilador C protable excretou uma versão montadora de sua tradução. Eu finalmente encontrei o bug! O compilador estava alocando mais registros do que existia na máquina! (O compilador alocado registra R0 a R8 em uma máquina com apenas registros R0 a R7.) Consegui solucionar o bug no compilador e meu programa funcionou.

Outro benefício de ter saída do assembler é tentar usar bibliotecas "padrão" que usam protocolos de passagem de parâmetros diferentes. Os compiladores C posteriores permitem definir o protocolo com um parâmetro ("pascal" faria o compilador adicionar os parâmetros na ordem dada em oposição ao padrão C de reverter a ordem).

Outro benefício é permitir que o programador veja o trabalho terrível que seu compilador está fazendo. Uma simples instrução C leva cerca de 44 instruções da máquina. Os valores são carregados da memória e rapidamente descartados. etc, etc, etc ...

Pessoalmente, acredito que ter um compilador em vez de um módulo de objeto realocável é realmente estúpido. Enquanto compila seu programa, o compilador reúne muitas informações sobre o seu programa. Geralmente, armazena todas essas informações em algo chamado Tabela de Símbolos. Após excretar o código do assembler, ele lança toda essa tabela de informações. O assembler examina o código excretado e recolhe algumas das informações que o compilador já possuía. No entanto, o assembler não sabe nada sobre as instruções If das instruções For ou While. Então, toda essa informação está faltando. Em seguida, o assembler produz o módulo de objeto relocável que o compilador não produziu.

Por quê???

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.