Aprendendo Assembly
Doar para o autor
  • Introdução
  • Conteúdo
  • Como usar este livro
  • A base
    • Noção geral da arquitetura
    • Modos de operação
    • Sintaxe
    • Registradores de propósito geral
    • Endereçamento
    • Pilha
    • Saltos
    • Procedimentos
    • Seções e símbolos
    • Instruções assembly x86
    • Instruções do NASM
    • Pré-processador do NASM
    • Syscall no Linux
    • Olá mundo no Linux
    • Revisão
  • Aprofundando em Assembly
    • Registradores de segmento
    • CALL e RET
    • Position-independent executable
    • Atributos
    • Prefixos
    • Flags do processador
    • Instruções condicionais
    • Programando no MS-DOS
    • Interrupções de software e exceções
    • Procedimentos do BIOS
    • Usando instruções da FPU
    • Entendendo SSE
      • Instruções de movimentação de dados
      • Instruções aritméticas
      • Instruções lógicas e de comparação
      • Instruções com inteiros 128-bit
      • Instruções de conversão
  • Programando junto com C
    • Sintaxe do GAS
    • Convenção de chamada da System V ABI
    • Convenções de chamada no Windows
    • Variáveis em C
    • Funções em C
    • Ambiente hosted
    • Ambiente freestanding
    • Inline Assembly no GCC
    • Instruções intrínsecas
  • Depuração de código
    • Entendendo os depuradores
    • Depurando com o GDB
    • Depurando com o Dosbox
  • Apêndices
    • Código de máquina
      • Formato das instruções
      • Atributos e prefixos
      • Immediate
      • Displacement
      • ModR/M e SIB
      • Opcode
      • Prefixo REX
      • Codificação dos registradores
  • Metadados
    • TO DO
    • Referências
Powered by GitBook
On this page
  • Convenção de chamada x64
  • Registradores
  • Passagem de parâmetros
  • Retorno de valores
  • Convenção de chamada cdecl
  • Registradores
  • Passagem de parâmetros
  • Retorno de valores
  • Convenção de chamada stdcall
  • Registradores
  • Passagem de parâmetros
  • Retorno de valores

Was this helpful?

Export as PDF
  1. Programando junto com C

Convenções de chamada no Windows

Aprendendo sobre as convenções de chamada usadas no Windows (x64, cdecl e stdcall).

PreviousConvenção de chamada da System V ABINextVariáveis em C

Last updated 3 years ago

Was this helpful?

O Windows tem suas próprias convenções de chamadas e o objetivo desse tópico é aprender sobre as três principais que dizem respeito à linguagem C.

Convenção de chamada x64

Essa é a convenção de chamada padrão usada em x86-64 e portanto é essencial aprendê-la caso vá programar no Windows diretamente em Assembly.

Registradores

Os registradores RBX, RBP, RDI, RSI, RSP, R12 até R15 e XMM6 até XMM15 devem ser preservados pela função chamada (callee). Caso a função chamada precise alterar o valor de algum desses registradores ela tem a obrigação de preservar o valor anterior e restaurá-lo antes de retornar.

Os demais registradores são considerados voláteis, isto é, podem ter seu valor alterado quando uma chamada de função é efetuada. A função chamada pode modificar o valor dos registradores voláteis livremente.

Passagem de parâmetros

  • Os primeiros quatro argumentos inteiros ou ponteiros são passados nos seguintes registradores e na mesma ordem: RCX, RDX, R8 e R9. Os demais argumentos devem ser empilhados na ordem inversa.

  • Os primeiros quatro argumentos float ou double são passados nos registradores XMM0 até XMM3 como . Os demais também são empilhados na ordem inversa.

  • Structs e unions de 8, 16, 32 ou 64 bits são passados como se fossem inteiros do respectivo tamanho. Se forem de outro tamanho a função chamadora deve então passar um ponteiro para a struct/union que será armazenada em uma memória alocada pela própria função chamadora. Essa memória deve estar em um endereço alinhado por 16 bytes.

A função chamadora (caller) é responsável por alocar um espaço de 32 bytes na pilha chamado de shadow space. Ele é alocado com o intuito de ser usado pela função chamada (callee) para armazenar os parâmetros passados em registradores caso seja necessário, por exemplo caso a função chamada precise usar esses registradores com outro intuito. Esse espaço vem antes mesmo do primeiro parâmetro empilhado.

Exemplo de protótipo de função:

int sum(int a, int b, int c, int d, int e, int f);

Assim que a função fosse chamada ECX, EDX, R8D e R9D armazenariam os parâmetros a, b, c e d respectivamente. O parâmetro f seria empilhado seguido do parâmetro e.

O 0(%rsp) seria o endereço de retorno. O espaço entre 8(%rsp) e 40(%rsp) é o shadow space. 40(%rsp) apontaria para o parâmetro e, enquanto 48(%rsp) apontaria para o parâmetro f. Como na demonstração abaixo:

mov %ecx, 8(%rsp)  # Armazenando o parâmetro A no shadow space
mov %edx, 16(%rsp) # Parâmetro B
mov %r8d, 24(%rsp) # Parâmetro C
mov %r9d, 32(%rsp) # Parâmetro D

# Parâmetro E: 40(%rsp)
# Parâmetro F: 48(%rsp)

Retorno de valores

  • Valores inteiros e ponteiros são retornados em RAX.

  • Valores float ou double são retornados no registrador XMM0.

  • O retorno de structs é feito com a função chamadora alocando o espaço de memória necessário para a struct, ela então passa o ponteiro para esse espaço como primeiro argumento para a função em RCX. A função chamada (callee) deve retornar o mesmo ponteiro em RAX.

Convenção de chamada cdecl

A convenção de chamada __cdecl é a convenção padrão usada em código escrito em C na arquitetura IA-32 (x86).

Registradores

Apenas os registradores EAX, ECX e EDX são considerados voláteis, ou seja, registradores que podem ser modificados livremente pela função chamada. Todos os demais registradores precisam ser preservados e restaurados antes do retorno da função.

Passagem de parâmetros

Todos os parâmetros são passados na pilha e devem ser empilhados na ordem inversa. A função chamadora (caller) é a responsável por remover os argumentos da pilha após a função retornar.

Exemplo:

push $3
push $2
push $1
call my_function
add $12, %esp

# 12 é o tamanho em bytes dos três valores empilhados

Retorno de valores

  • Valores inteiros ou ponteiros são retornados em EAX.

  • Valores float ou double são retornados em ST0.

  • O retorno de structs ocorre da mesma maneira que na convenção de chamada x64. Com a diferença que o primeiro argumento é, obviamente, passado na pilha.

Convenção de chamada stdcall

Registradores

Assim como na __cdecl os registradores EAX, ECX e EDX são voláteis e os demais devem ser preservados pela função chamada.

Passagem de parâmetros

Todos os argumentos são passados na pilha na ordem inversa. A função chamada (callee) é a responsável por remover os argumentos da pilha. Exemplo:

push $3
push $2
push $1
call my_function

Retorno de valores

O retorno de valores funciona da mesma maneira que o retorno de valores da __cdecl.

A convenção de chamada __stdcall é a utilizada para chamar funções da .

WinAPI
valores escalares