Básico sobre arquitetura de computadores

Featured image

Modelo de computação

O modelo de computação é um conjunto de operações básicas e seus respectivos custos

Arquitetura de von Neumann

As principais características da arquitetura:

A linguagem Assembly para um dado processador é uma linguagem de programação constituída de mnemônicos para cada possível instrução binária codificada (código de máquina). Ela deixa a programação em código de máquina muito mais simples, pois o programador então não precisa memorizar a codificação binária das instruções, apenas seus nomes e parâmetros

Uma arquitetura nem sempre define um conjunto exato de instruções, de modo diferente de um modelo de computação

Arquitetura Intel 64

Cada modelo foi desenvolvido visando preservar a compatibilidade com modelos mais antigos. Os processadores são capazes de operar em uma série de modos: modo real, protegido, virtual etc. Se não for explicitamente especificado, descrevemos o funcionamento da CPU no chamado modo longo (long mode), que é o mais recente

Para consultar o manual oficial da intel: https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html#three-volume

Extenções da arquitetura

Registradores

A troca de dados entre CPU e memória é uma parte crítica dos processamentos em um computador de von Neumann. As instruções precisam ser buscadas na memória, os operandos também e algumas instruções igualmente armazenam os resultados na memória. Isso cria um gargalo e resulta em tempo de CPU desperdiçado quando ele espera os dados de resposta do chip de memória. Para evitar esperas constantes, um processador era equipado com suas próprias células de memória, chamadas de registradores

Registradores de propósito geral

Na maior parte das vezes, um programador trabalhará com registradores de propósito geral. Eles são intercambiáveis e podem ser usados em vários comandos distintos

Nome Alias Descrição
r0 rax Uma espécie de “acumulador”, usado em instruções aritméticas
r3 rbx Registrador base. Era usado para endereçamento da base nos primeiros modelos do processador
r1 rcx Usado para ciclos (por exemplo loops)
r2 rdx Armazena dados durante operações de entrada/saída
r4 rsp Armazena o endereço do elemento do topo da pilha de hardware
r5 rbp Base do stack frame
r6 rsi Índice de origem em comandos de manipulação de strings (como movsd)
r7 rdi Índice de destino em comandos de manipulação de strings (como movsd)
r8 - r15 Não há Surgiram depois. Usados principalmente para armazenar variáveis temporárias

Endereçar parte de um registrados é possível. Para cada registrador, podemos endereçar seus 32 bits menos significativos, os 16 bits menos significativos ou os 8 bits menos significativos

Quando os nomes r0,…,r15 são usados, isso é feito com a adição de um sufixo apropriado ao nome de um registrador:

Por exemplo:

Os nomes alternativos também permitem endereçar as partes menores

A convenção de nomenclatura para acessar partes de rax, rbx, rcx e rdx segue o mesmo padrão. Os outros quatro registradores não permitem acesso aos seus segundos bytes menos significativos. A nomenclatura do byte menos significativo difere um pouco para rsi, rdi, rsp e rbp

Em geral, os programadores se atêm aos nomes alternativos para os oito primeiros registradores de propósito geral (r0-r7). Os outros oito registradores (r8-r15) só podem ser nomeados usando uma convenção com indexação

Inconsistência em escritas Todas as leituras de registradores menores se comportam de forma óbvia. As escritas nas partes de 32 bits, porém, preenchem os 32 bits mais significativos do registrador completo com bits de sinal. Por exemplo, zerar eax zerará todo o rax; aramzenar -1 em eax preencherá os 32 bits mais signifativos com uns. Outras escritas (por exemplo, em partes de 16 bits) se comportam conforme esperado: não afetam nenhum dos demais bits

Outros registradores

Os outros registradores apresentam significados especiais. Alguns registradores têm importância para todo o sistema e, desse modo, não podem ser modificados, execto pelo sistema operacional

Um programador tem acesso ao registrador rip. É um registrador de 64 bits, que sempre armazena um endereço da próxima instrução a ser executada. Assim, sempre que qualquer instrução é executada, rip armazenará o endereço da próxima instrução

Outro registrador acessível se chama rflags. Ele armazena flags, que refletem o estado atual do programa - por exemplo, qual foi o resultado da última instrução aritmética: se foi negativo, se um overflow ocorreu, etc. Suas partes menores são chamadas de eflags (32 bits) e flags (16 bits)

Registradores de sistema

Alguns registradores foram projetados para serem usados pelo sistema operacional. Esses registradores não armazenam valores usados em processamentos. Em vez disso, armazenam informações necessárias às estruturas de dados utilizadas por todo o sistema.

Alguns desses registradores são listados a seguir:

Anéis de proteção

Os anéis de proteção (protection rings) são um dos mecanismos projetados para limitar a capacidade das aplicações por razões de segurança e de robustez. Cada tipo de instrução está ligado a um ou mais níveis de privilégio, e não é executável em outros níveis. O nível atual de privilégio é armazenado de algum modo.

O Intel 64 tem quatro níveis de privilégio, dos quais somente dois são usados na prática: o anel 0 (o mais privilegiado) e o anel 3 (o menos privilegiado)

No modo londo, o número do anel de proteção atual é armazenado nos dois bits menos significativos do registrador cs (e duplicados nos bits de ss)

Pilha de hardware

Se estivermos falando de estruturas de dados em geral, uma pilha é uma estrutura de dados com duas operações: um novo elemento pode ser colocado no topo da pilha (push) e o elemento do topo pode ser retirado da pilha (pop)

As pilhas são implementadas com duas instruções de máquina (push e pop) e um registrador (rsp). O registrador rsp armazena o endereço do elemento que está no topo da pilha

As instruções executam do seguinte modo:

Alguns fatos importantes sobre pilha: