Gostaria de fazer algumas perguntas sobre a linguagem Assembly. Meu entendimento é que é muito próximo da linguagem de máquina, tornando-a mais rápida e eficiente.
Como temos arquiteturas de computador diferentes, isso significa que tenho que escrever um código diferente no Assembly para arquiteturas diferentes? Em caso afirmativo, por que o Assembly não é, escreva uma vez - execute todo tipo de idioma? Não seria mais fácil simplesmente torná-lo universal, para que você o escreva apenas uma vez e possa executá-lo em praticamente qualquer máquina com configurações diferentes? (Acho que seria impossível, mas gostaria de ter respostas concretas e aprofundadas)
Algumas pessoas podem dizer que C é o idioma que estou procurando. Eu não usei C antes, mas acho que ainda é uma linguagem de alto nível, embora provavelmente seja mais rápida que Java, por exemplo. Eu posso estar errado aqui.
Respostas:
A linguagem Assembly é uma maneira de escrever instruções para o conjunto de instruções do computador , de uma maneira um pouco mais compreensível para os programadores humanos.
Arquiteturas diferentes têm conjuntos de instruções diferentes: o conjunto de instruções permitidas é diferente em cada arquitetura. Portanto, você não pode esperar ter um programa de montagem de gravar uma vez, executar em qualquer lugar. Por exemplo, o conjunto de instruções suportadas pelos processadores x86 parece muito diferente do conjunto de instruções suportadas pelos processadores ARM. Se você escrevesse um programa de montagem para um processador x86, ele teria muitas instruções que não são suportadas no processador ARM e vice-versa.
O principal motivo para usar a linguagem assembly é que ela permite um controle de nível muito baixo sobre o seu programa e tira proveito de todas as instruções do processador: personalizando o programa para tirar proveito dos recursos exclusivos do processador em particular. vai funcionar, às vezes você pode acelerar o programa. A filosofia de escrever uma vez, executar em qualquer lugar está fundamentalmente em desacordo com isso.
fonte
A DEFINIÇÃO de linguagem assembly é que é um idioma que pode ser traduzido diretamente em código de máquina. Cada código de operação na linguagem assembly traduz para exatamente uma operação no computador de destino. (Bem, é um pouco mais complicado que isso: alguns montadores determinam automaticamente um "modo de endereçamento" com base em argumentos para um código operacional. Mas, ainda assim, o princípio é que uma linha de montagem se traduz em uma instrução em linguagem de máquina.)
Você poderia, sem dúvida, inventar uma linguagem que se parecesse com linguagem assembly, mas seria traduzida para diferentes códigos de máquina em computadores diferentes. Mas, por definição, isso não seria linguagem assembly. Seria uma linguagem de nível superior que se assemelha à linguagem assembly.
Sua pergunta é como perguntar: "É possível fazer um barco que não flutue ou que tenha outra maneira de atravessar a água, mas que tenha rodas e motor e possa viajar em terra?" A resposta seria que, por definição, esse veículo não seria um barco. Parece mais um carro.
fonte
Não há razão conceitual (eu diria, ciência da computação ) contra ter uma linguagem assembly para todos os computadores do mundo. De fato, isso tornaria muitas coisas muito mais fáceis. No que diz respeito à teoria, eles são todos iguais, de qualquer forma, até algumas bijuterias descoladas.
Na prática, no entanto, existem chips diferentes para diferentes finalidades, com diferentes operações e princípios de design (por exemplo, RISC vs CISC) que atendem a diferentes objetivos, e os conjuntos de instruções que os operam e com as linguagens de montagem diferem. No final, a resposta é a mesma que quando perguntamos por que existem tantas linguagens de programação diferentes: objetivos diferentes, decisões de design diferentes.
Dito isso, é claro que você pode introduzir níveis de abstração para acessar alguma interface compartilhada. O x86, por exemplo, foi eliminado no nível do chip por algum tempo; há um pequeno pedaço de hardware que traduz instruções x86 para o que o seu processador realmente trabalha. Idiomas como C estariam a um passo do hardware (se bem que minúsculo), até linguagens como Haskell, Java ou Ruby. Sim, o compilador é uma das principais realizações da ciência da computação, porque possibilita separar preocupações dessa maneira.
fonte
Você menciona a frase "escreva uma vez, execute em qualquer lugar" sem parecer notar seu significado. Esse é o slogan de marketing da Sun Microsystems que inventou comercialmente o conceito de "máquina virtual" e "bytecodes" para Java, embora possivelmente a idéia possa ter se originado na academia 1 st. A idéia foi posteriormente copiada pela Microsoft para .Net depois que eles foram processados com sucesso pela Sun por violação de violação do licenciamento de Java. Bytecodes Java são uma implementação da idéia de montagem entre máquinas ou linguagem de máquina. Eles são usados para várias outras linguagens além do Java e teoricamente podem ser usados para compilar qualquer linguagem. Após muitos anos de otimização muito avançada, o Java se aproxima do desempenho das linguagens compiladas, mostrando que o objetivo da tecnologia de máquina virtual independente de plataforma de alto desempenho é alcançável em geral.
Outra nova idéia, em estágios iniciais / em circulação, relacionada às suas necessidades, é chamada de projeto de recomputação e é para pesquisa científica, embora possa ser usada para outros fins. A idéia é tornar os experimentos computacionais replicáveis via tecnologia de máquina virtual. Essa é principalmente a idéia de simular diferentes arquiteturas de máquinas em hardware arbitrário.
fonte
Razões de alto nível
Quando você pensa sobre isso, um microprocessador faz uma coisa incrível: permite pegar uma máquina (como uma máquina de lavar ou um elevador) e substituir um pedaço inteiro de design personalizado mecanismos ou circuitos com uma barata, o silício produzido em massa lasca. Você economiza muito dinheiro em peças e muito tempo em design.
Mas espere, um chip padrão , substituindo inúmeras configurações personalizadas designs ? Não pode haver um único microprocessador perfeito para todas as aplicações. Alguns aplicativos precisam minimizar o uso de energia, mas não precisam ser rápidos; outros precisam ser rápidos, mas não precisam ser fáceis de programar, outros precisam ser de baixo custo etc.
Portanto, temos muitos "sabores" diferentes de microprocessador, cada um com suas próprias forças e fraquezas. É desejável que todos eles usem um conjunto de instruções compatível, pois isso permite a reutilização de código e facilita a localização de pessoas com as habilidades certas. No entanto, o conjunto de instruções não afetar o custo, complexidade, velocidade, facilidade de uso e limitações físicas do processador, e por isso temos um compromisso: há algumas "mainstream" conjuntos de instruções (e muitos outros menores), e dentro de cada conjunto de instruções, existem muitos processadores com características diferentes.
Ah, e à medida que a tecnologia muda, todas essas trocas são alteradas, assim os conjuntos de instruções evoluem, novos surgem e os antigos morrem. Mesmo se houvesse um "melhor" conjunto de instruções de hoje, talvez não seja daqui a 20 anos.
Detalhes de hardware
Provavelmente, a maior decisão de design em um conjunto de instruções é o tamanho da palavra , ou seja, qual o número que o processador pode "naturalmente" manipular. Os processadores de 8 bits lidam com números de 0 a 255, enquanto os de 32 bits lidam com números de 0 a 4.294.967.295. O código projetado para um precisa ser completamente repensado para outro.
Não se trata apenas de traduzir instruções de uma instrução definida para outra. Uma abordagem completamente diferente pode ser preferível em um conjunto de instruções diferente. Por exemplo, em um processador de 8 bits, uma tabela de pesquisa pode ser ideal, enquanto em um processador de 32 bits uma operação aritmética seria melhor para a mesma finalidade.
Existem outras grandes diferenças entre os conjuntos de instruções. A maioria das instruções se enquadra em quatro categorias:
Os processadores diferem em que tipo de computação eles podem executar, bem como em sua abordagem do fluxo de controle, transferência de dados e configuração do processador.
Por exemplo, alguns processadores AVR não podem se multiplicar nem dividir; enquanto todos os processadores x86 podem. Como você pode imaginar, a eliminação do circuito necessário para tarefas como multiplicação e divisão pode tornar um processador mais simples e mais barato; essas operações ainda podem ser executadas usando rotinas de software, se forem necessárias.
O x86 permite instruções aritméticas para carregar seus operandos da memória e / ou salvar seus resultados na memória; O ARM é uma arquitetura de armazenamento de carga e, portanto, possui apenas algumas instruções dedicadas para acessar a memória. Enquanto isso, o x86 tem instruções de ramificação condicional dedicadas, enquanto o ARM permite praticamente todas instruções sejam executadas condicionalmente. Além disso, o ARM permite a troca de bits como parte da maioria das instruções aritméticas. Essas diferenças levam a diferentes características de desempenho, diferenças no design interno e no custo dos chips e diferenças nas técnicas de programação no nível da linguagem assembly.
Conclusão
A razão pela qual é impossível ter uma linguagem assembly universal é que, para converter adequadamente o código do assembly de um conjunto de instruções para outro, é necessário projetar o código novamente - algo que os computadores ainda não podem fazer.
fonte
Acrescentando a maravilhosa resposta da DW: se você gostaria de ter um montador, seria necessário manter todas as arquiteturas, um tradutor perfeito entre elas e entender completamente o que você está fazendo.
Alguns códigos altamente otimizados por uma arquitetura precisariam ser otimizados, entendidos em um nível mais abstrato e otimizados por outra.
Mas se isso fosse possível, teríamos um compilador C perfeito, e escrever em montagem pura não seria benéfico.
O ponto principal do uso do assembler é o desempenho, que não pode ser extraído dos compiladores recentes.
Escrever esse programa seria ainda mais difícil do que os compiladores existentes, e manter todas as novas arquiteturas que estão sendo criadas tornaria ainda mais difícil.
E para um programa "apenas um", isso também significaria total compatibilidade com versões anteriores.
fonte
A Microsoft inventou o MSIL para ser uma linguagem assembly intermediária. Os programas seriam compilados de C # ou VB.Net para MSIL. No tempo de execução, o MSIL foi compilado no código da máquina que a executava usando um compilador JIT . O arquivo que contém o MSIL era um arquivo .exe com algumas instruções no início do X86 para iniciar o programa. Em um processador ARM, você digitaria a palavra mono na frente do nome do programa para executá-lo.
fonte
Como observado, o LLVM é a coisa mais próxima disso até agora. Uma grande barreira para uma linguagem realmente universal será as diferenças fundamentais relacionadas às trocas implícitas: simultaneidade, uso de memória, taxa de transferência, latência e consumo de energia. Se você escrever em um estilo explicitamente SIMD, poderá estar usando muita memória. Se você escrever em um estilo SISD explicitamente, obterá uma paralelização abaixo do ideal. Se você otimizar a taxa de transferência, prejudicará a latência. Se você maximizar a taxa de transferência de thread único (ou seja: velocidade do relógio), você prejudicará a vida da bateria.
No mínimo, o código precisaria ser anotado com as compensações. O que pode ser mais importante é que o idioma tenha boas propriedades algébricas / de tipo que dão ao compilador muito espaço de manobra para otimizar e detectar inconsistência lógica.
Depois, há a questão do comportamento indefinido. Grande parte da velocidade das linguagens C e assembly vem de um comportamento indefinido. Se você admitir um comportamento indefinido que realmente acontece, acabará tratando-o como casos especiais (ou seja: arquitetura e hackers específicos ao contexto).
fonte
Talvez o que você está procurando seja uma notação da Universal Turning Machine, onde todos concordam com os símbolos dos comandos. ( https://en.wikipedia.org/wiki/Universal_Turing_machine )
Um 'assembler' que traduz um idioma Turning Acceptable para o código de máquina específico do fornecedor subjacente e é compilado para qualquer uma dessas coisas que chamamos de computadores.
Em A arte da programação de computadores, há um exemplo de como isso pode ser.
Mas considere a pergunta "por que não é uma linguagem universal disponível comercialmente que possa ser usada com todos os computadores"? Sugiro que as influências mais dominantes sejam: (1) conveniência, nem todas as linguagens assembly são as mais convenientes de usar; (2) economia, fornecendo incompatibilidade entre máquinas de diferentes marcas e fornecedores, é uma estratégia comercial, bem como o resultado de recursos limitados (tempo / dinheiro) para projetar máquinas.
fonte
suposição: compilar e otimizar uma linguagem de alto nível L1 para uma linguagem de nível inferior L0 é mais fácil do que compilar e otimizar uma linguagem de alto nível L2 (maior que L1) para L0; mais fácil no sentido em que você supostamente pode gerar um código mais otimizado ao compilar L1 a L0 do que L2 a L0.
Eu acho que a suposição provavelmente está correta, é por isso que provavelmente a maioria dos compiladores usa uma linguagem intermediária de baixo nível (IR / LLVM).
se isso for verdade, use qualquer idioma de baixo nível L0 e escreva compiladores para traduzir L0 para outros idiomas de baixo nível. Por exemplo, use o conjunto de instruções MIPS e compile-o para x86, arm, power, ...
-Taoufik
fonte