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/.

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:

- 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.
No menu Iniciar, pesquise por "editar as variáveis de ambiente para a sua conta (Edit the system variables)".

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

Na seção "Variáveis de usuário" (User variables), selecione a variável
Pathe clique em "Editar".
Clique em "Novo" e adicione o caminho completo para a pasta onde você descompactou o NASM.

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 operacionalEste 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
_startdo 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 comomainou_main. A diretivaglobal maintorna 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úmero22no registradorrax. Este será o código de status que nosso programa retornará ao sistema quando for encerrado.ret: A instruçãoretfinaliza 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.
Baixe e Instale o MSYS2: Acesse o site oficial do MSYS2 e baixe o instalador msys2-x86_64-xxxxxxxx.exe.

- Execute o Instalador: Prossiga com a instalação, mantendo as opções padrão. O diretório de instalação típico é
C:\msys64. 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.exena 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.

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

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

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.

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 programaAnalisando o novo fluxo:
- 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çãoWriteFiletem um 5º parâmetro, precisamos de mais 8 bytes para ele. Total: 32 (shadow space) + 8 (5º parâmetro) = 40 bytes. - 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
GetStdHandlecom o código-11(STD_OUTPUT_HANDLE). A função retorna o handle no registradorrax. Escrevendo com
WriteFile: Com o handle em mãos, podemos chamarWriteFile. Passamos os argumentos nos registradores corretos:rcx: O handle que acabamos de receber.rdx: O endereço de memória da nossamessage.r8d: O tamanho da mensagem (19 bytes).r9e o 5º parâmetro na pilha: Nulos, pois não precisamos dos recursos avançados que eles oferecem.
- Limpando e Saindo:
add rsp, 40restaura a pilha à sua posição original, e o programa termina de forma limpa, retornando0para 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!