Atualizado: 18/10/2025

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

Salvando Registradores e Variáveis Durante Chamadas de Funções em Assembly NASM

Durante seus cálculos, uma função em Assembly pode mudar o conteúdo de vários registradores. Caso esses valores ainda sejam necessários no código principal, é preciso salvá-los para garantir o resultado correto do programa.

Considere o seguinte exemplo em Linux:

global _start

section .text
_start:
    mov rdi, 125
    mov rax, 15
    call sum
    add rdi, rax      ; RDI = 25
    mov rax, 60
    syscall

; definição da função sum
sum:
    mov rdi, 5
    mov rax, 10
    add rax, rdi
    ret

A função sum redefine os registradores rdi e rax. Após sua execução, o valor original de rdi (125) é perdido, e o resultado final em rdi é 20 em vez de 140.

Embora seja possível escolher outros registradores, funções reais tendem a usar vários deles simultaneamente. Além disso, o programador pode não saber quais registradores o código que faz a chamada da função utiliza.

Por isso, é uma boa prática — e em muitos casos uma necessidade — salvar os registradores usados pela função na pilha antes de modificá-los e restaurá-los antes do retorno.

Salvando e Restaurando Registradores

global _start

section .text
_start:
    mov rdi, 125
    call sum
    add rdi, rax      ; RDI = 140
    mov rax, 60
    syscall

; definição da função sum
sum:
    push rdi           ; salva RDI na pilha
    mov rdi, 5
    mov rax, 10
    add rax, rdi
    pop rdi            ; restaura RDI da pilha
    ret

Aqui, o valor original de rdi é preservado. No início da função sum, ele é salvo na pilha e, no final, restaurado. O registrador rax não é salvo, pois é usado para armazenar o resultado que será retornado ao código principal.

Salvando Registradores no Código que Faz a Chamada

Também é possível realizar a preservação dos registradores no código que faz a chamada, em vez de dentro da função:

global _start

section .text
_start:
    mov rdi, 125
    push rdi           ; salva RDI
    call sum
    pop rdi            ; restaura RDI
    add rdi, rax       ; RDI = 140
    mov rax, 60
    syscall

; definição da função sum
sum:
    mov rdi, 5
    mov rax, 10
    add rax, rdi
    ret

Essa abordagem funciona, mas tende a ser menos eficiente se o programa fizer várias chamadas de função. Nesse caso, salvar e restaurar registradores em cada chamada aumentaria o tamanho e a complexidade do código principal.

Por isso, a prática mais comum é a própria função ser responsável por preservar os registradores que modifica.

Salvando e Restaurando Variáveis

A mesma lógica vale para variáveis globais. Se uma função altera uma variável usada em outro ponto do programa, é recomendável salvar seu valor antes da modificação e restaurá-lo em seguida.

Exemplo em Linux:

global _start

section .data
num dq 45

section .text
_start:
    call sum
    mov rdi, rax        ; RDI = 25
    add rdi, [num]      ; RDI = 25 + 15 = 40
    mov rax, 60
    syscall

; definição da função sum
sum:
    mov qword [num], 15 ; altera num
    mov rax, 10
    add rax, [num]      ; RAX = 10 + 15 = 25
    ret

O valor da variável num muda de 45 para 15 após a execução da função sum, o que pode gerar resultados inesperados.

Para evitar isso, a variável pode ser salva e restaurada usando a pilha:

global _start

section .data
num dq 45

section .text
_start:
    call sum
    mov rdi, rax        ; RDI = 25
    add rdi, [num]      ; RDI = 25 + 45 = 70
    mov rax, 60
    syscall

; definição da função sum
sum:
    push qword [num]        ; salva num
    mov qword [num], 15     ; altera num
    mov rax, 10
    add rax, [num]          ; RAX = 10 + 15 = 25
    pop qword [num]         ; restaura num
    ret

Exemplo em Windows:

global _start

section .data
num dq 45

section .text
_start:
    call sum
    add rax, [rel num]     ; RAX = 25 + 45 = 70
    ret

; definição da função sum
sum:
    push qword [rel num]       ; salva num
    mov qword [rel num], 15    ; altera num
    mov rax, 10
    add rax, [rel num]         ; RAX = 10 + 15 = 25
    pop qword [rel num]        ; restaura num
    ret

Resumo

  • Funções podem modificar registradores e variáveis usados pelo código que faz a chamada.
  • Para evitar erros, registradores e variáveis importantes devem ser salvos antes da modificação e restaurados depois.
  • A prática mais comum é a própria função ser responsável por preservar o que modifica.
  • O registrador rax geralmente não é salvo, pois é usado para retornar o resultado ao código principal.
  • O mesmo princípio se aplica a variáveis globais.
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