Introdução à Arquitetura Intel x86-64 e ao Assembly NASM
A Arquitetura Intel x86-64
A arquitetura de processadores Intel x86-64 é a base da maioria dos computadores modernos, desde desktops e notebooks até servidores. Ela segue o modelo da arquitetura von Neumann, que se organiza em três componentes principais: a Unidade Central de Processamento (CPU), a memória e os dispositivos de Entrada/Saída (E/S).
A comunicação entre esses componentes acontece através do barramento do sistema (system bus), um conjunto de vias que se divide em três partes: o barramento de endereço, que indica onde na memória ou em qual dispositivo os dados devem ser lidos ou escritos; o barramento de dados, que transporta os dados em si; e o barramento de controle, que envia sinais para coordenar e sincronizar toda a operação. Compreender esses componentes em um nível fundamental é exatamente o que a programação Assembly permite.
A Relevância do Assembly
Em uma era dominada por linguagens de programação de alto nível, pode-se questionar a utilidade de aprender Assembly. No entanto, seu estudo oferece uma compreensão incomparável da arquitetura do computador. Esse conhecimento é extremamente valioso em áreas como engenharia reversa, análise de vírus e malwares, e na busca por vulnerabilidades de segurança. Além disso, dominar Assembly é uma habilidade essencial para a programação de baixo nível, como no desenvolvimento de sistemas operacionais e drivers de dispositivos.
Para compilar (ou mais precisamente, montar) nossos programas, será utilizado o Netwide Assembler (NASM), disponível em https://www.nasm.us/. Ele é um dos montadores mais populares, por ser multiplataforma (compatível com Windows, macOS e Linux) e utilizar a sintaxe da Intel. Essa sintaxe facilita a transição para programadores que já tiveram contato com outros montadores, como MASM ou YASM.
Antes de escrevermos nosso primeiro código, vamos explorar brevemente a evolução que nos levou à arquitetura x86-64.
A Arquitetura x86
O termo x86 designa uma ampla família de arquiteturas de conjunto de instruções, começando com processadores de 16 bits e evoluindo para 32 bits. Sua história começou em 1978 com o processador Intel 8086. As gerações seguintes (80186, 80286, 80386, etc.) deram origem ao termo "x86". Mesmo com nomes comerciais diferentes, como Pentium e Celeron, os processadores da Intel mantiveram a compatibilidade com essa arquitetura, assim como os processadores da AMD, como Athlon e Duron.
Os primeiros processadores, como o 8086, eram de 16 bits, o que significava que seus registradores e operações manipulavam dados nesse tamanho. Eles não possuíam recursos modernos, como memória virtual ou níveis de proteção, e com 20 linhas de endereço, só podiam acessar 1 MB de memória. Para contornar a limitação de um endereço de 20 bits não caber em um registrador de 16 bits, foi criado um sistema complexo de registradores de segmento.
O grande salto veio em 1985 com o Intel 80386, o primeiro processador de 32 bits da família. Seus registradores, endereços e operações eram de 32 bits, e ele introduziu o modo protegido (protected mode). Esse modo trouxe um mecanismo de privilégios com quatro níveis (de 0 a 3), onde o nível 0 (kernel) tem acesso total ao sistema e o nível 3 (aplicações de usuário) tem acesso restrito. Curiosamente, sistemas operacionais como Windows e Linux utilizam até hoje apenas os níveis 0 e 3. O 80386 também passou a suportar 4 GB de memória com endereços de 32 bits, eliminando a complexidade dos segmentos, e introduziu a memória virtual paginada.
Uma característica importante da arquitetura x86 é a sua ordem de bytes, conhecida como little-endian. Isso significa que valores com múltiplos bytes são armazenados na memória com o byte menos significativo no endereço mais baixo. Por exemplo, o número de 32 bits 0x1A2B3C4D seria armazenado na memória na seguinte ordem de bytes: 4D, 3C, 2B, 1A, com o byte 4D ocupando o primeiro endereço.
A Arquitetura x64
A arquitetura x64 (ou x86-64) não foi uma ruptura, mas sim uma extensão de 64 bits da x86. A primeira especificação, chamada AMD64, foi apresentada pela AMD em 2000. A Intel, que inicialmente investia em uma arquitetura de 64 bits incompatível (IA-64, do processador Itanium), acabou adotando uma abordagem semelhante à da AMD, criando a Intel 64. No final, ambas as tecnologias convergiram para o padrão que conhecemos hoje como x86-64.
Processadores com essa arquitetura são amplamente compatíveis entre si no que diz respeito a aplicações de usuário. As pequenas diferenças que existem são geralmente abstraídas por compiladores e sistemas operacionais, sendo uma preocupação maior apenas para desenvolvedores de software de sistema.
Principais Características da Arquitetura x64
A principal mudança da x64 é a expansão da capacidade de processamento, mantendo a retrocompatibilidade. Os oito registradores de uso geral de 32 bits (como EAX) foram estendidos para 64 bits, agora identificados pelo prefixo R (por exemplo, RAX). Além disso, foram adicionados oito novos registradores de 64 bits (R8 a R15), duplicando o número de registradores de uso geral disponíveis. O ponteiro de instrução (RIP) e o registrador de flags (RFLAGS) também foram expandidos para 64 bits. Essa expansão permite o suporte nativo a operações com números inteiros de 64 bits, tornando os cálculos com números grandes muito mais eficientes.
Apesar dessas mudanças, a x64 mantém uma forte compatibilidade com a x86. O conjunto de instruções é praticamente o mesmo, e os processadores podem operar em um modo de compatibilidade que executa sistemas operacionais e aplicações de 32 bits sem modificações.
A mudança mais impactante é no espaço de endereçamento. Teoricamente, um endereço de 64 bits poderia acessar 16 exabytes (2⁶⁴ bytes) de memória. Na prática, os processadores atuais implementam um espaço de endereçamento virtual de 48 bits. Essa limitação reduz a complexidade do hardware, mas ainda permite acessar impressionantes 256 terabytes (TB) de memória virtual.
Resumo
- Arquitetura Dominante: A arquitetura Intel x86-64, baseada no modelo de von Neumann (CPU, memória, E/S), é a mais utilizada em computadores pessoais e servidores.
- Importância do Assembly: Aprender Assembly proporciona uma compreensão profunda do hardware e é crucial para áreas como segurança da informação e desenvolvimento de sistemas de baixo nível.
- Montador NASM: É um montador Assembly popular, multiplataforma e que utiliza a sintaxe padrão da Intel, facilitando seu aprendizado.
- Evolução da x86: A arquitetura evoluiu de processadores de 16 bits (como o 8086) para 32 bits (como o 80386), introduzindo recursos fundamentais como o modo protegido.
- Expansão para x64: A x64 é uma extensão de 64 bits da x86 que oferece mais registradores, um espaço de endereçamento muito maior e mantém total retrocompatibilidade com software de 32 bits.