Atualizado: 18/10/2025

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

Parâmetros de Funções em Assembly NASM

Parâmetros permitem que uma função receba valores externos para processar. Em Assembly, esses valores geralmente são enviados por registradores, mas também podem ser passados por pilha ou por variáveis globais. É possível combinar esses métodos conforme a necessidade.

Quando o número de parâmetros é pequeno, o modo mais comum é enviá-los por registradores.


Passagem de Parâmetros por Registradores

A seguir, um exemplo simples em Linux:

global _start

section .text
_start:
    mov rcx, 3      ; primeiro parâmetro para a função sum
    mov rdx, 4      ; segundo parâmetro para a função sum
    call sum

    mov rax, 60
    syscall

; definição da função sum
sum:
    mov rdi, rcx    ; copia o valor de RCX para RDI
    add rdi, rdx    ; soma com o valor de RDX
    ret

Os valores 3 e 4 são enviados para a função sum pelos registradores rcx e rdx. Dentro da função, rdi recebe o valor de rcx e o soma com rdx. Ao final, rdi conterá o resultado 7.

Exemplo equivalente em Windows:

global _start

section .text
_start:
    mov rcx, 3      ; primeiro parâmetro para a função sum
    mov rdx, 4      ; segundo parâmetro para a função sum
    call sum
    ret

; definição da função sum
sum:
    mov rax, rcx    ; copia o valor de RCX para RAX
    add rax, rdx    ; soma com o valor de RDX
    ret

Quando todas as funções do programa são escritas em Assembly, é possível definir livremente quais registradores serão usados para enviar parâmetros. Entretanto, ao interagir com funções externas, como as de bibliotecas C/C++ ou APIs do sistema operacional, é necessário seguir as convenções de chamada de cada plataforma.

  • Linux (System V AMD64): os seis primeiros parâmetros são enviados nos registradores rdi, rsi, rdx, rcx, r8 e r9.
  • Windows (Win64): os quatro primeiros parâmetros são enviados nos registradores rcx, rdx, r8 e r9.
  • Parâmetros adicionais são enviados pela pilha.

Essas convenções também se aplicam ao Assembly quando há integração com outras linguagens.

Passagem de Parâmetros pela Pilha

Outra forma de enviar parâmetros é por meio da pilha (stack).

Exemplo em Linux:

global _start

section .text
_start:
    push 1  ; [rsp + 24] = 1
    push 2  ; [rsp + 16] = 2
    push 3  ; [rsp + 8]  = 3

    call sum          ; [rsp] contém o endereço de retorno
    add rsp, 24       ; restaura o ponteiro da pilha

    mov rax, 60
    syscall

; definição da função sum
sum:
    mov rdi, [rsp + 24]   ; RDI = 1
    add rdi, [rsp + 16]   ; RDI = 3
    add rdi, [rsp + 8]    ; RDI = 6
    ret

Cada instrução push insere um valor de 8 bytes na pilha. No exemplo, três valores são empilhados (24 bytes no total). Após a chamada, add rsp, 24 limpa esse espaço.

Durante a execução da função sum, a pilha estará organizada da seguinte forma:

RSP → endereço de retorno
[RSP + 8]  = 3
[RSP + 16] = 2
[RSP + 24] = 1

Assim, para acessar cada parâmetro, são usados deslocamentos de 8, 16 e 24.

Exemplo equivalente em Windows:

global _start

section .text
_start:
    push 1
    push 2
    push 3

    call sum
    add rsp, 24
    ret

; definição da função sum
sum:
    mov rax, [rsp + 24]
    add rax, [rsp + 16]
    add rax, [rsp + 8]
    ret

Inserindo Parâmetros Manualmente na Pilha

Usar várias instruções push pode não ser a forma mais eficiente, especialmente quando os valores são pequenos. É possível escrever diretamente na pilha, reservando espaço manualmente.

Exemplo em Linux:

global _start

section .text
_start:
    sub rsp, 3                ; reserva 3 bytes para parâmetros
    mov byte [rsp + 2], 3
    mov byte [rsp + 1], 4
    mov byte [rsp], 5

    call sum
    add rsp, 3                ; restaura a pilha
    mov rdi, rax              ; copia o resultado para RDI
    mov rax, 60
    syscall

; definição da função sum
sum:
    xor rax, rax
    mov al, [rsp + 10]
    add al, [rsp + 9]
    add al, [rsp + 8]
    ret

Nesse caso, apenas 3 bytes são reservados, pois os parâmetros são de 1 byte cada. O endereço de retorno ainda ocupa 8 bytes, portanto o primeiro parâmetro fica em [rsp + 8].

Exemplo em Windows:

global _start

section .text
_start:
    sub rsp, 3
    mov byte [rsp + 2], 3
    mov byte [rsp + 1], 4
    mov byte [rsp], 5

    call sum
    add rsp, 3
    ret

; definição da função sum
sum:
    xor rax, rax
    mov al, [rsp + 10]
    add al, [rsp + 9]
    add al, [rsp + 8]
    ret

Considerações sobre Alinhamento da Pilha

Em alguns contextos — especialmente ao interagir com APIs externas ou funções C/C++ — há restrições quanto ao alinhamento da pilha. Certas instruções exigem que os dados estejam alinhados em endereços pares ou múltiplos de 16 bytes.

Isso significa que empilhar valores de 1 byte pode causar desalinhamento e comportamento incorreto. Quando necessário, deve-se ajustar a pilha para garantir o alinhamento adequado, mesmo que isso gere algum espaço não utilizado.


Resumo

  • Parâmetros podem ser enviados por registradores, pilha ou variáveis globais.
  • O método mais simples é o envio por registradores, quando há poucos parâmetros.
  • Em chamadas que seguem convenções de linguagens como C/C++, a ordem e os registradores usados dependem do sistema operacional.
  • O envio por pilha é flexível, mas requer cuidado com o uso de espaço e o alinhamento da memória.
  • É possível escrever diretamente na pilha, sem usar push, para otimizar o uso de memória.
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