Registradores
| 64-bit (Qword) | 32-bit (Dword) | 16-bit (Word) | 8 high bits of lower 16 bits | 8 low bits (Byte) |
|---|---|---|---|---|
| RAX | EAX | AX | AH | AL |
| RBX | EBX | BX | BH | BL |
| RCX | ECX | CX | CH | CL |
| RDX | EDX | DX | DH | DL |
| RSI | ESI | SI | N/A | SIL |
| RDI | EDI | DI | N/A | DIL |
| RBP | EBP | BP | N/A | BPL |
| RSP | ESP | SP | N/A | SPL |
| R8 - R15 | R8D - R15D | R8W - R15W | N/A | R8B - R15B |

Control Flow
A lógica condicional é mecânica e dividida em duas etapas independentes e sequenciais:
- Avaliação: Uma instrução matemática ou lógica é executada e o processador atualiza o registrador de status com base nela.
- Ação: Uma instrução condicional lê o estado desse registrador para decidir se altera o fluxo do programa ou se move um dado.
O Registrador de Status (rFLAGS)
É um registrador de 64 bits onde bits específicos atuam como flags, descrevendo o resultado da última operação de avaliação. As quatro flags principais são:
- ZF (Zero Flag):
1se o resultado da operação foi exatamente zero (ou se dois operandos comparados eram iguais). - SF (Sign Flag):
1se o resultado foi negativo. - CF (Carry Flag):
1se o bit65era um. - OF (Overflow Flag):
1em caso de overflow (inverteu o sinal incorretamente) em operações com sinal.
Instruções de Avaliação
cmp(Compare): Realiza umsub(Destino - Origem).- Exemplo:
cmp rax, rbx. - Se forem iguais, a subtração dá zero e a
ZFvira1. Seraxfor menor, a subtração gera um valor negativo, setandoSFouCF.
- Exemplo:
test(Logical Compare): Realiza um and (Destino & Origem).- Exemplo:
test rax, rax. - É a maneira mais rápida e comum de verificar se um registrador contém o valor
0(0 & 0)
- Exemplo:
Instruções como add e sub também alteram as flags.
Conditional Jumps
Após setar as flags, o programa usa um salto condicional para decidir se deve ou não executar esse jump.
| Instrução | Significado | Categoria | Condição nas Flags |
|---|---|---|---|
| je / jz | Salta se Igual / Zero ( == ) | Igualdade | ZF=1 |
| jne / jnz | Salta se Não Igual / Não Zero ( != ) | Igualdade | ZF=0 |
| jg / jnle | Salta se Maior ( > ) | Signed | ZF=0 e SF=OF |
| jl / jnge | Salta se Menor ( < ) | Signed | SF!=OF |
| jge / jnl | Salta se Maior ou Igual ( >= ) | Signed | SF=OF |
| jle / jng | Salta se Menor ou Igual ( <= ) | Signed | ZF=1 ou SF!=OF |
| ja / jnbe | Salta se Acima ( > ) | Unsigned | CF=0 e ZF=0 |
| jb / jnae | Salta se Abaixo ( < ) | Unsigned | CF=1 |
| jae / jnb | Salta se Acima ou Igual ( >= ) | Unsigned | CF=0 |
| jbe / jna | Salta se Abaixo ou Igual ( <= ) | Unsigned | CF=1 ou ZF=1 |
(Instruções na mesma linha são sinônimos e tem exatamente o mesmo opcode.)
Alternativas Branchless
Essas instruções movem dados condicionalmente sem saltos (não influenciam Branch Prediction):
cmovcc(Conditional Move): Move os dados da origem para o destino apenas se a condição for verdadeira.- Exemplo:
cmove rax, rbx(Move o valor derbxpararaxse a flag Zero estiver ativa).
- Exemplo:
setcc(Set Byte on Condition): Escreve o resultado de uma comparação em um valor booleano (1ou0) no registrador de destino (altera todo o byte inferior). Usados para avaliar expressões lógicas diretas (ex:x = a == b). (ccno nome é uma das condições)- Exemplo:
sete al(Grava1emalse a flag Zero indicar igualdade, ou0caso contrário).
- Exemplo:
Funções
Caller & Callee
A gestão do estado do processador, stack, passagem de argumentos, etc, é regida por uma calling convention que divide a responsabilidade de preservação dos registradores, alinhamento do stack e outras coisas.
- Caller (Chamador): A função atual que executa o
call. - Callee (Chamada): A função que recebe o controle.
Registradores Preservados (Callee-Saved / Não-Voláteis): São registradores cujo valor original deve permanecer inalterado da perspectiva do Caller. Se o Callee precisar usar esses registradores durante sua execução, ele é responsável por salvar o valor original no stack (no prólogo) e restaurá-lo (no epílogo) antes do ret .
Registradores Voláteis (Caller-Saved): Podem ser sobrescritos pelo Callee. Se o Caller precisar manter essa informação, ele mesmo deve salvá-la no stack antes do call .
Linux (System V AMD64 ABI)
Ordem de passagem dos argumentos: Os primeiros seis argumentos inteiros ou ponteiros1 são passados obrigatoriamente na seguinte ordem (argumentos extras ou pertencentes a classe de memória2 são empilhados no stack):
rdirsirdxrcxr8r9
Stack Frame e Red Zone
O stack cresce para baixo ( [rsp - 8] ) e deve estar sempre alinhado para otimizar o barramento de dados da CPU e permitir o uso de instruções vetoriais (SSE/AVX).
- Antes do
call(No Caller): Imediatamente antes de chamar uma função, o registradorrspdeve obrigatoriamente apontar para um endereço que seja múltiplo de 16 (32 ou 64). - A Execução do
call: Ocallaltera a pilha, subtraindo 8 dorspe empilhando o endereço de retorno de 64 bits (rip). - Na Entrada (No Callee): Agora com o Callee no controle é preciso restaurar o alinhamento, assim começa o prólogo da função e a preparação de um stack frame pra ela.
Para que seja possivel usar o stack com segurança ou chamar outras funções o alinhamento de 16 bytes deve ser restaurado. Isso pode ser feito empilhando o Base Pointer, o que subtrai mais 8 bytes do rsp (8 + 8 = 16). Ou alocando espaço de forma explícita (ex: sub rsp, N ).

A Red Zone é uma otimização de arquitetura exclusiva da System V ABI, é uma área de 128 bytes localizada em endereços de memória imediatamente inferiores ao ponteiro atual da pilha (de rsp - 1 até rsp - 128 ).
A memória localizada nessa área é reservada para uso por “leaf functions” (funções que não chamam outras funções), como espaço adicional para o frame delas, dessa maneira elas não precisam modificar o Stack Pointer ( rsp ).
Uso dos Registradores de Propósito Geral
| Registrador | Usos Principais | Callee-Saved |
|---|---|---|
| rax | 1º registrador de retorno; contém o número da syscall antes da interrupção. | Não (Volátil) |
| rbx | Uso geral. Atua como armazenamento seguro de longo prazo. | Sim (Não-volátil) |
| rcx | 4º argumento inteiro. É destruído pelo kernel em syscall s (usado para salvar o rip temporariamente). | Não (Volátil) |
| rdx | 3º argumento inteiro; 2º registrador de retorno (para retornos de 128 bits). | Não (Volátil) |
| rdi | 1º argumento inteiro. Em C++ é o registrador que carrega o ponteiro this . | Não (Volátil) |
| rsi | 2º argumento inteiro. | Não (Volátil) |
| rbp | Base Pointer (stack frames). Compiladores omitem o frame pointer e o utilizam como um registrador de uso geral. | Sim (Não-volátil) |
| rsp | Stack Pointer. Aponta para o topo da pilha. | Sim (Não-volátil) |
| r8 | 5º argumento inteiro. | Não (Volátil) |
| r9 | 6º argumento inteiro. | Não (Volátil) |
| r10 | Temporário. O kernel usa para passar o 4º argumento. | Não (Volátil) |
| r11 | Temporário. É destruído pelo kernel em syscall s (usado para salvar o rflags ). | Não (Volátil) |
| r12 - r15 | Uso geral para salvar variáveis locais. | Sim (Não-volátil) |
Windows (Microsoft x64 ABI)
A calling convention baseia-se no modelo __fastcall e em um modelo de tratamento de exceções baseado em metadados (unwind data).
Ordem de passagem dos argumentos: Há uma correspondência estrita de um para um entre os argumentos da função e os registradores, um único argumento nunca é dividido em múltiplos registradores. Os quatro primeiros argumentos são passados em registradores, o quinto e os seguintes são empilhados da direita para a esquerda (cima para baixo). Argumentos maiores que 8 bytes ou com tamanhos diferentes de 1, 2, 4 ou 8 bytes são passados por referência.
- Inteiros / Ponteiros:
rcxrdxr8r9
- Ponto Flutuante (XMM):
xmm0xmm1xmm2xmm3
Stack Frame e Shadow Store
O stack exige alinhamento de 16 bytes para o registrador rsp na maior parte do código (exceto em leaf functions ou durante a execução de prólogos/epílogos).
O Caller é responsável por alocar o espaço na base da pilha para os parâmetros do Callee. O Caller deve sempre alocar espaço contíguo suficiente para abrigar os quatro parâmetros do registrador (32 bytes), mesmo que o Callee não receba quatro parâmetros. Esses 4 slots pertencem ao Callee, que pode utilizá-los para salvar os argumentos passados via registrador na memória, caso precise do endereço deles ou para depuração.
Ao contrário do linux, toda memória além do endereço atual do rsp (abaixo do topo da pilha) é considerada volátil. O sistema operacional, depuradores ou tratadores de interrupção podem sobrescrever essa área a qualquer momento. Portanto, o rsp deve ser obrigatoriamente subtraído para alocar espaço físico antes de qualquer tentativa de leitura ou escrita de variáveis locais.
Tipos de Funções e Unwindability
- Frame Functions: Funções que alocam espaço na pilha, chamam outras funções ou salvam registradores não-voláteis. Requerem um prólogo e epílogo com estruturas e instruções altamente restritas. Isso é obrigatório para que os dados de exceção (
pdataexdata) consigam realizar o “unwind” (desenrolamento) da pilha em caso de erro, restaurando o contexto do chamador. - Leaf Functions (Funções Folha): Funções que não alteram registradores não-voláteis (incluindo o
rsp). Não podem chamar funções nem alocar espaço na pilha. Não exigem prólogo, epílogo ou metadados de exceção, e têm a permissão de deixar a pilha desalinhada durante a sua execução.
Retorno de Valores
- Valores escalares e tipos definidos pelo usuário que caibam em 64 bits (1, 2, 4, 8, 16, 32 ou 64 bits), incluindo structs são retornados em
rax. - Tipos não-escalares (floats, doubles e vetores como
__m128) são retornados emxmm0. - Para tipos definidos pelo usuário que excedem 64 bits ou não cumprem os requisitos de retorno por valor, o Caller deve alocar a memória e passar um ponteiro oculto para ela como o primeiro argumento (em
rcx). Os argumentos reais são deslocados uma posição para a direita. O Callee retorna esse mesmo ponteiro emrax.
Uso dos Registradores de Propósito Geral
| Registrador | Usos Principais | Callee-Saved |
|---|---|---|
| rax | Valor de retorno. | Não (Volátil) |
| rbx | Uso geral. | Sim (Não-volátil) |
| rcx | 1º argumento inteiro. Em __thiscall (métodos não estáticos C++) é o registrador usado para passar o ponteiro this . | Não (Volátil) |
| rdx | 2º argumento inteiro. | Não (Volátil) |
| rdi | Uso geral. Diferente do Linux deve ser preservado. O Callee deve salvá-lo se for utilizá-lo para instruções de string ( rep stosq , etc). | Sim (Não-volátil) |
| rsi | Uso geral. Mesma regra do rdi | Sim (Não-volátil) |
| rbp | Frame pointer. Também de uso geral em funções normais, mas é obrigatoriamente forçado a atuar como Base Pointer se a função utilizar alloca() . | Sim (Não-volátil) |
| rsp | Stack Pointer. | Sim (Não-volátil) |
| r8 | 3º argumento inteiro. | Não (Volátil) |
| r9 | 4º argumento inteiro. | Não (Volátil) |
| r10 - r11 | Usados pela ntdll.dll nos stubs de syscall / sysret . O compilador utiliza como descartáveis. | Não (Volátil) |
| r12 - r15 | Uso geral. | Sim (Não-volátil) |
| xmm0 - xmm3 | Primeiros 4 argumentos de floating point/vector. xmm0 é o valor de retorno de float/double. | Não (Volátil) |
| xmm4 - xmm5 | Usados como 5º e 6º argumentos se a função usar __vectorcall . | Não (Volátil) |
| xmm6 - xmm15 | Operações floating point. Diferente do Linux devem ser preservados. | Sim (Não-volátil) |