Atualizado: 30/08/2025

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

Primeiro Programa Assembly no Windows com NASM

O NASM, por ser um montador multiplataforma, oferece uma maneira poderosa de escrever código de baixo nível também no Windows. Neste guia, vamos configurar o ambiente de desenvolvimento no Windows, criar um programa simples e aprender o processo para transformá-lo em um executável funcional.

Instalação

O primeiro passo é obter o próprio montador. Para este guia, usaremos a versão 2.16.01 para Windows de 64 bits, que pode ser baixada da página de lançamentos oficial: https://www.nasm.us/pub/nasm/releasebuilds/2.16.01/win64/.

Releasebuilds do NASM para Windows

Na página, você encontrará duas opções: um instalador (.exe) e um arquivo compactado (.zip). Baixar o arquivo .zip nos dá mais controle sobre a instalação.

Após o download, descompacte o arquivo em um local de fácil acesso, como C:\nasm-2.16.01. Dentro desta pasta, os arquivos mais importantes são:

Os arquivos nasm.exe e ndisasm.exe na pasta extraída

  • nasm.exe: O montador, nossa principal ferramenta.
  • ndisasm.exe: Um desmontador, útil para análises mais avançadas.

Configurando o Path do Sistema

Para podermos chamar o nasm de qualquer diretório no terminal, precisamos adicionar sua pasta ao Path do sistema. Isso informa ao Windows onde encontrar o executável.

  1. No menu Iniciar, pesquise por "editar as variáveis de ambiente para a sua conta (Edit the system variables)".

    Buscando variáveis de ambiente no Windows

  2. Na janela que se abre, clique em "Variáveis de Ambiente (Environment Variables)".

    Janela "Variáveis de Ambiente"

  3. Na seção "Variáveis de usuário" (User variables), selecione a variável Path e clique em "Editar".

    Janela "Variáveis de usuário"

  4. Clique em "Novo" e adicione o caminho completo para a pasta onde você descompactou o NASM.

    Janela para adicionar caminho

Para verificar se a configuração funcionou, abra um novo terminal (Prompt de Comando ou PowerShell) e digite nasm -v. O terminal deve exibir a versão do NASM.

C:\Users\seu_nome>nasm -v
NASM version 2.16.01 compiled on Dec 21 2022

C:\Users\seu_nome>

O Primeiro Código com NASM

Vamos criar nosso primeiro programa. Em um diretório de sua escolha, crie um arquivo chamado hello.asm com o seguinte conteúdo:

global main        ; Torna o ponto de entrada visível para o linker

section .text      ; Início da seção de código
main:              ; Ponto de entrada (estilo C)
    mov rax, 22    ; Define o código de retorno do programa
    ret            ; Retorna o controle ao sistema operacional

Este código é a maneira mais simples de criar um programa funcional no Windows. Vamos analisar suas partes:

  • Ponto de Entrada: No Windows, ao contrário do _start do Linux, a convenção para o ponto de entrada de programas que serão ligados com linkers padrão (como os do GCC ou Visual Studio) é usar um rótulo como main ou _main. A diretiva global main torna esse rótulo visível para o linker.
  • Modelo de Função: Pense no seu programa como uma "função" que é chamada pelo sistema operacional. Quando a função termina, ela retorna um valor. No Windows x64, o valor de retorno de uma função é, por convenção, armazenado no registrador rax.
  • mov rax, 22: Esta linha coloca o número 22 no registrador rax. Este será o código de status que nosso programa retornará ao sistema quando for encerrado.
  • ret: A instrução ret finaliza a "função" e devolve o controle ao processo que a chamou (neste caso, o sistema operacional).

Montagem: Do Código-Fonte ao Código Objeto

Com o arquivo hello.asm salvo, o primeiro passo é a montagem. Este processo traduz nosso código Assembly legível em código de máquina, que o processador entende.

Abra o terminal, navegue até a pasta do seu projeto e execute:

nasm -f win64 hello.asm -o hello.o
  • -f win64: Informa ao NASM para gerar a saída no formato para Windows de 64 bits.
  • -o hello.o: Define o nome do arquivo de saída.

O resultado é um arquivo objeto (hello.o). Ele contém o código de máquina, mas ainda não é um programa executável. Falta uma etapa crucial: a ligação.

A Necessidade de um Linker

O NASM faz uma coisa muito bem: montar código Assembly. Ele não inclui um linker (ou ligador), que é a ferramenta responsável por pegar um ou mais arquivos objeto e transformá-los em um arquivo .exe final.

Para isso, precisamos de um linker externo. Vamos explorar duas opções populares e gratuitas: o linker do conjunto de compiladores GCC (que obteremos via MSYS2) e o linker do Visual C++.

Ligação com o GCC (via MSYS2)

O MSYS2 é um ambiente de software que fornece um terminal no estilo Unix e um gerenciador de pacotes para instalar facilmente ferramentas de desenvolvimento como o GCC no Windows.

  1. Baixe e Instale o MSYS2: Acesse o site oficial do MSYS2 e baixe o instalador msys2-x86_64-xxxxxxxx.exe.

    O site oficial do MSYS2 com o link de download destacado

  2. Execute o Instalador: Prossiga com a instalação, mantendo as opções padrão. O diretório de instalação típico é C:\msys64.
  3. Inicie o Terminal MSYS2: Após a instalação, um terminal do MSYS2 deve ser aberto. Se não, você pode iniciá-lo executando o arquivo msys2.exe na pasta de instalação.

    O arquivo msys2.exe dentro da pasta de instalação

Com o terminal MSYS2 aberto, o próximo passo é instalar a "caixa de ferramentas" do GCC, que inclui o compilador, o linker e outros utilitários. Para isso, usamos o gerenciador de pacotes pacman:

pacman -S mingw-w64-ucrt-x86_64-gcc

Este comando baixa e instala a cadeia de ferramentas de compilação C/C++ para Windows de 64 bits.

Terminal MSYS2 mostrando a lista de pacotes a serem instalados para o GCC e solicitando confirmação.

Após a instalação, nosso linker, ld.exe, estará localizado em C:\msys64\ucrt64\bin. O diretório do linker ld.exe no MSYS2

Para facilitar o uso, adicione este diretório às variáveis de ambiente do Windows, assim como fizemos com o NASM. Adicionando o diretório do linker ld.exe às variáveis de ambiente do Windows

Com a configuração concluída, abra um novo terminal do Windows e verifique se o ld está acessível:

C:\asm>ld --version
GNU ld (GNU Binutils) 2.40

Agora, podemos finalizar o processo de criação do nosso executável:

ld hello.o -o hello.exe

Para executar e verificar o código de retorno, usamos a variável de ambiente %ERRORLEVEL% no Windows.

C:\asm>nasm -f win64 hello.asm -o hello.o
C:\asm>ld hello.o -o hello.exe
C:\asm>hello.exe
C:\asm>echo %ERRORLEVEL%
22
C:\asm>

Ligação com o Linker do Visual C++

Uma alternativa ao GCC é usar o link.exe, a ferramenta de ligação nativa da Microsoft que vem com o Visual Studio. Sua principal vantagem é ser a ferramenta oficial para a plataforma Windows.

1. Verificando a Instalação do C++

Para que o link.exe esteja disponível, é necessário ter a carga de trabalho "Desenvolvimento para desktop com C++" instalada no Visual Studio. Você pode verificar ou adicionar esta carga de trabalho através do Visual Studio Installer.

Instalador do Visual Studio destacando a opção "Desenvolvimento para desktop com C++".

2. Usando o Terminal Correto

O comando link.exe deve ser executado em um ambiente de terminal específico, pois ele não é reconhecido em um Prompt de Comando padrão. Para isso, o Visual Studio instala um atalho que prepara o ambiente necessário.

Abra o "x64 Native Tools Command Prompt", que está disponível no Menu Iniciar após a instalação dos componentes de C++.

3. Ligando o Programa

Dentro deste terminal especial, navegue até a pasta do seu projeto. Em seguida, execute o comando de ligação: execute o comando de ligação:

C:\asm>link hello.o /entry:main /subsystem:console /out:hello2.exe
Microsoft (R) Incremental Linker Version 14.37.32824.0
Copyright (C) Microsoft Corporation.  All rights reserved.

Os parâmetros informam ao linker o ponto de entrada (main), o tipo de aplicação (console) e o nome do arquivo de saída. O resultado é um executável que se comporta da mesma forma.

Após a ligação, você pode executar o programa:

C:\asm>hello2.exe

C:\asm>echo %ERRORLEVEL%
22

C:\asm>

Segundo Programa: Escrevendo no Console com a WinAPI

Para realizar tarefas mais complexas (nos próximos temas abordaremos mais sobre isso), como escrever na tela, precisamos interagir com a API do Windows (WinAPI). Vamos modificar nosso hello.asm para chamar funções do sistema:

global main

extern WriteFile
extern GetStdHandle

section .data
message: db "Hello Programicio!", 10  ; Nossa string e uma quebra de linha

section .text
main:
    sub  rsp, 40          ; 1. Prepara a pilha para a chamada de função

    mov  rcx, -11         ; Parâmetro para GetStdHandle: STD_OUTPUT_HANDLE
    call GetStdHandle     ; 2. Obtém o "handle" do console

    mov  rcx, rax         ; Param 1 (WriteFile): o handle do console
    mov  rdx, message     ; Param 2: o endereço da nossa mensagem
    mov  r8d, 19          ; Param 3: o tamanho da mensagem em bytes
    xor  r9, r9           ; Param 4: NULL
    mov  qword [rsp+32], 0  ; Param 5 (na pilha): NULL
    call WriteFile        ; 3. Escreve a mensagem no console

    add  rsp, 40          ; 4. Limpa a pilha
    mov  rax, 0           ; Define o código de retorno como 0 (sucesso)
    ret                   ; Encerra o programa

Analisando o novo fluxo:

  1. Preparando a Pilha (sub rsp, 40): A convenção de chamada de funções no Windows x64 é estrita. Antes de chamar uma função, precisamos "reservar assentos" na pilha. Os primeiros 4 parâmetros de uma função são passados via registradores, mas o sistema exige que um espaço de 32 bytes para eles (chamado de shadow space) seja alocado na pilha de qualquer maneira. Como a função WriteFile tem um 5º parâmetro, precisamos de mais 8 bytes para ele. Total: 32 (shadow space) + 8 (5º parâmetro) = 40 bytes.
  2. Obtendo o "Handle" do Console: Não podemos simplesmente "escrever na tela". Primeiro, pedimos ao Windows um "identificador" (handle) para o dispositivo de saída padrão (o console). Fazemos isso chamando a função GetStdHandle com o código -11 (STD_OUTPUT_HANDLE). A função retorna o handle no registrador rax.
  3. Escrevendo com WriteFile: Com o handle em mãos, podemos chamar WriteFile. Passamos os argumentos nos registradores corretos:

    • rcx: O handle que acabamos de receber.
    • rdx: O endereço de memória da nossa message.
    • r8d: O tamanho da mensagem (19 bytes).
    • r9 e o 5º parâmetro na pilha: Nulos, pois não precisamos dos recursos avançados que eles oferecem.
  4. Limpando e Saindo: add rsp, 40 restaura a pilha à sua posição original, e o programa termina de forma limpa, retornando 0 para indicar sucesso.

Compilação e Ligação (com a WinAPI)

Nosso programa agora depende de funções externas (WriteFile, GetStdHandle) que estão localizadas na biblioteca kernel32.lib. Precisamos informar isso ao linker.

Com o Linker GCC (ld): O parâmetro -l seguido do nome da biblioteca (sem a extensão .lib) faz a ligação.

C:\asm>nasm -f win64 hello.asm -o hello.o
C:\asm>ld hello.o -o hello.exe -l kernel32
C:\asm>hello.exe
Hello Programicio!

Com o Linker da Microsoft (link.exe): Simplesmente adicionamos o nome completo da biblioteca à lista de arquivos a serem ligados.

C:\asm>nasm -f win64 hello.asm -o hello.o
C:\asm>link hello.o kernel32.lib /entry:main /subsystem:console /out:hello2.exe
C:\asm>hello2.exe
Hello Programicio!
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