Atualizado: 18/10/2025

Este conteúdo é original e não foi gerado por inteligência artificial.

Pilha (Stack) em Assembly NASM

A pilha é uma estrutura de dados dinâmica usada para armazenar informações temporárias do programa — como variáveis locais, endereços de retorno e dados intermediários. O processador x86-64 controla a pilha por meio do registrador RSP (Stack Pointer), que sempre aponta para o topo da pilha.

Quando o programa é iniciado, o sistema operacional inicializa o registrador RSP com o endereço da última célula de memória reservada para o segmento de pilha. No Linux x86-64, por exemplo, o tamanho padrão da pilha é de 2 MB.

A pilha cresce dos endereços mais altos para os mais baixos, ou seja, a cada novo dado adicionado, o valor de RSP é reduzido. Por padrão, o endereço da pilha é alinhado em 16 bytes no início da execução.


Instruções PUSH e POP

A instrução push insere um valor no topo da pilha. Ela pode receber como operando um registrador de 16 ou 64 bits, um endereço de memória, ou uma constante de 16 a 32 bits (neste caso, a constante de 32 bits é expandida para 64 bits).

Ao executar push, o processador subtrai o tamanho do operando do registrador RSP e armazena o valor no novo endereço apontado:

rsp = rsp - tamanho_do_operando
[rsp] = valor

A instrução pop faz o inverso: recupera o valor do topo da pilha e o armazena no operando informado (geralmente um registrador). Em seguida, o valor de RSP é incrementado pelo tamanho do operando:

operando = [rsp]
rsp = rsp + tamanho_do_operando

Exemplo (Linux)

global _start

section .text
_start:
    mov rdx, 15
    push rdx          ; adiciona o valor de RDX à pilha
    pop rdi           ; recupera o valor no topo da pilha para RDI
    mov rax, 60
    syscall

Se o registrador RSP inicialmente contém o endereço 0x00FFFFF0, após o comando push rdx:

  • RSP é decrementado em 8 bytes (0x00FFFFE8);
  • o valor 15 é armazenado no endereço apontado por RSP.

O comando pop rdi então:

  • lê o valor armazenado (15);
  • move-o para RDI;
  • e incrementa novamente RSP para 0x00FFFFF0.

Exemplo (Windows)

global _start

section .text
_start:
    mov rdx, 15
    push rdx
    pop rax
    ret

Princípio LIFO e Preservação de Registradores

A pilha segue o princípio LIFO (Last In, First Out — último a entrar, primeiro a sair). Isso significa que o último valor adicionado será o primeiro a ser removido.

Uma das utilizações mais comuns de push e pop é salvar o conteúdo dos registradores durante cálculos intermediários, permitindo reutilizá-los sem perder valores anteriores.

Exemplo (Linux)

global _start

section .text
_start:
    mov rdi, 11
    mov rdx, 33

    push rdi
    push rdx

    pop rdi     ; rdi = 33
    pop rdx     ; rdx = 11

    mov rax, 60
    syscall

Os valores são recuperados em ordem inversa à que foram empilhados — o último push é o primeiro a ser pop.

Sempre que dados forem adicionados à pilha, deve haver a mesma quantidade de remoções posteriores para manter o equilíbrio do RSP.

Salvando e Restaurando os Flags

As instruções pushfq e popfq servem para armazenar e restaurar o registrador RFLAGS, que contém os flags de estado do processador.

Exemplo (Linux)

global _start

section .text
_start:
    pushfq          ; salva os flags atuais
    mov al, 255
    add al, 2       ; 255 + 2 = 257 → ativa o flag CF (Carry Flag)
    popfq           ; restaura o estado anterior dos flags
    jc set          ; o salto não ocorrerá, pois CF foi restaurado para 0
    mov rdi, 11
    jmp exit
set:
    mov rdi, 22
exit:
    mov rax, 60
    syscall

O uso de pushfq e popfq é essencial quando operações aritméticas alteram os flags e o programa precisa preservá-los para instruções subsequentes.

Restaurando o Ponteiro da Pilha sem POP

Nem sempre é necessário remover explicitamente os dados da pilha. Se for preciso apenas restaurar o valor original de RSP, pode-se somar o tamanho dos dados empilhados diretamente:

global _start

section .text
_start:
    mov rdi, 11
    mov rdx, 33

    push rdi
    push rdx

    add rsp, 16     ; restaura RSP (2 × 8 bytes)
    mov rax, 60
    syscall

Da mesma forma, pode-se reservar espaço na pilha subtraindo um valor de RSP:

global _start

section .text
_start:
    sub rsp, 16     ; reserva 16 bytes
    ; uso temporário da pilha
    add rsp, 16     ; restaura o ponteiro
    mov rax, 60
    syscall

Acesso Direto à Pilha

O registrador RSP também pode ser usado para acessar diretamente os dados na pilha, sem usar push ou pop. Isso é feito por meio de endereçamento indireto:

global _start

section .text
_start:
    sub rsp, 16
    mov rdx, 11
    mov [rsp], rdx      ; escreve 11 no endereço atual da pilha
    mov rdi, [rsp]      ; lê o mesmo valor (11)
    add rsp, 16
    mov rax, 60
    syscall

Esse método é útil quando não se deseja alterar o ponteiro da pilha.

Exemplo com Deslocamento

global _start

section .text
_start:
    push 12
    push 13
    push 14
    push 15

    mov rdi, [rsp+16]   ; acessa o valor 13
    add rsp, 32
    mov rax, 60
    syscall

Como cada push ocupa 8 bytes, rsp+16 aponta para o terceiro valor empilhado.

Exemplo com Soma de Valores (Linux)

global _start

section .text
_start:
    sub rsp, 16

    mov rcx, 12
    mov rdx, 13

    mov [rsp + 8], rcx   ; [rsp+8] = 12
    mov [rsp], rdx       ; [rsp] = 13

    mov rdi, [rsp]
    add rdi, [rsp+8]     ; 13 + 12 = 25

    add rsp, 16
    mov rax, 60
    syscall

Exemplo equivalente (Windows)

global _start

section .text
_start:
    sub rsp, 16

    mov rcx, 12
    mov rdx, 13

    mov [rsp + 8], rcx
    mov [rsp], rdx

    mov rax, [rsp]
    add rax, [rsp+8]

    add rsp, 16
    ret

Resumo

  • A pilha armazena dados temporários e é controlada pelo registrador RSP.
  • A pilha cresce em direção a endereços menores.
  • push insere um valor; pop o remove.
  • O acesso segue o princípio LIFO (Last In, First Out).
  • pushfq e popfq salvam e restauram os flags de estado.
  • É possível ajustar diretamente o ponteiro da pilha com add rsp, N ou sub rsp, N.
  • O endereçamento indireto com [rsp + deslocamento] permite ler ou gravar valores específicos sem alterar RSP.
Política de Privacidade

Copyright © www.programicio.com Todos os direitos reservados

É proibida a reprodução do conteúdo desta página sem autorização prévia do autor.

Contato: programicio@gmail.com