Atualizado: 30/08/2025

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

Primeiro Programa Assembly no Linux com NASM

Programar em Assembly é a forma mais próxima de "conversar" diretamente com o processador do seu computador. É uma habilidade que desmistifica o funcionamento do software em seu nível mais fundamental. Neste guia, vamos usar o montador NASM no ambiente Linux (Ubuntu) para criar, passo a passo, nosso primeiro programa executável.

Instalação

Primeiro, precisamos garantir que as ferramentas necessárias estejam instaladas. Abrimos o terminal e executamos dois comandos. O primeiro sincroniza a lista de pacotes do seu sistema:

sudo apt update

O segundo instala o Netwide Assembler (NASM):

sudo apt -y install nasm

Para confirmar que a instalação foi bem-sucedida, você pode verificar a versão do NASM:

user@programicio:~$ nasm -v
NASM version 2.15.05
user@programicio:~$

A versão do NASM que instalamos com o comando apt é a versão oficial mantida e testada pela equipe do Ubuntu. Ela é garantida para ser estável e compatível com o sistema, sendo perfeita para aprender e para a maioria dos usos.

Contudo, essa versão pode não ser a mais recente lançada pelos desenvolvedores do NASM. Para usuários avançados que precisam das últimas funcionalidades ou otimizações, a versão mais atual está sempre disponível para download no site oficial do NASM. Para tudo o que faremos neste guia, a versão do repositório é mais do que suficiente.

O Primeiro Código com NASM

Vamos começar com um programa que não faz nada além de encerrar sua própria execução de forma limpa. Em um diretório de sua escolha, crie o arquivo hello.asm com o seguinte conteúdo:

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

section .text          ; Início da seção de código executável
_start:                ; Define o ponto de entrada do programa
    mov rax, 60        ; Código da syscall 'exit'
    mov rdi, 22        ; Código de retorno para o sistema
    syscall            ; Pede ao kernel para executar a syscall

Vamos entender a estrutura:

  • Seções: O código é organizado em seções. A seção .text é onde ficam as instruções que a CPU irá executar.
  • Ponto de Entrada: O rótulo _start: marca o início da execução. A diretiva global _start informa ao sistema que este é o "portão de entrada" do nosso programa.

A lógica central é a chamada de sistema (system call ou syscall). Pense nela como preencher um formulário para o kernel do Linux e pedir que ele faça algo em nosso nome.

  1. mov rax, 60: O registrador rax funciona como o campo "Assunto" do nosso formulário. O valor 60 é o código que diz ao kernel: "Eu quero executar a ação de sair (exit)".
  2. mov rdi, 22: O registrador rdi contém o primeiro argumento. Para a chamada exit, este é o código de status que o programa retornará ao sistema. Escolhemos 22 arbitrariamente.
  3. syscall: Esta instrução é o botão "Enviar". Ela pausa nosso programa, entrega o "formulário" (os registradores) ao kernel, que então executa a ação solicitada.

Compilando e Executando

Nosso código-fonte (.asm) precisa passar por um processo de duas etapas para se tornar um programa que o sistema possa rodar.

1. Montagem: Traduzimos nosso código Assembly legível para código de máquina.

nasm -f elf64 hello.asm -o hello.o
  • -f elf64: Especifica que queremos gerar um arquivo no formato ELF64, o padrão para executáveis de 64 bits no Linux.
  • -o hello.o: Define o nome do arquivo de saída. O resultado é um arquivo objeto (.o), que é uma tradução do nosso código, mas ainda não está pronto para ser executado.

2. Ligação (Linking): Pegamos o arquivo objeto e o transformamos em um executável final.

ld -o hello hello.o

O linker ld "encaderna" nosso código objeto, adicionando as informações necessárias para que o sistema operacional saiba como carregá-lo e executá-lo. Agora, temos um arquivo hello executável.

Vamos rodá-lo e verificar o código de saída:

user@programicio:~/asm$ ./hello
user@programicio:~/asm$ echo $?
22
user@programicio:~/asm$

O comando echo $? confirma que nosso programa retornou o código 22, exatamente como programado.

Adicionando Saída ao Console

Agora, vamos fazer nosso programa se comunicar com o mundo. Modifique o hello.asm para exibir uma mensagem:

global _start

section .data          ; Seção para dados inicializados
message: db "Hello Programicio!", 10  ; Nossa string e uma quebra de linha

section .text
_start:
    ; --- Syscall para escrever no console ---
    mov rax, 1         ; Código da syscall 'write'
    mov rdi, 1         ; Argumento 1: Descritor do arquivo (1 = stdout)
    mov rsi, message   ; Argumento 2: Endereço da nossa mensagem
    mov rdx, 19        ; Argumento 3: Tamanho da mensagem em bytes
    syscall

    ; --- Syscall para sair do programa ---
    mov rax, 60        ; Código da syscall 'exit'
    mov rdi, 0         ; Código de retorno 0 (convenção para sucesso)
    syscall

As novidades aqui são:

  • Seção .data: Uma nova seção para armazenar dados que já têm um valor no início do programa. Aqui, criamos message, uma sequência de bytes contendo nossa string. O , 10 no final é o código ASCII para o caractere de quebra de linha (\n).
  • Syscall write: Para escrever no console, preenchemos um novo "formulário":

    • rax = 1: O código da syscall write.
    • rdi = 1: O destino. 1 é o descritor de arquivo para a saída padrão (stdout), ou seja, o terminal.
    • rsi = message: O endereço de memória onde nossa mensagem começa. É crucial entender que passamos a localização, não o texto em si.
    • rdx = 19: O número de bytes a serem lidos a partir desse endereço (18 caracteres da frase + 1 byte da quebra de linha).

Note que agora usamos mov rdi, 0 na chamada exit. Retornar 0 é a convenção universal para indicar que um programa foi executado com sucesso.

Repetimos o processo de montagem e ligação e executamos o resultado:

user@programicio:~/asm$ nasm -f elf64 hello.asm -o hello.o
user@programicio:~/asm$ ld -o hello hello.o
user@programicio:~/asm$ ./hello
Hello Programicio!
user@programicio:~/asm$

Resumo

  • Estrutura em Seções: Programas NASM se organizam em seções como .text (código) e .data (dados).
  • Ponto de Entrada: O rótulo _start, declarado com global, é o início da execução no Linux.
  • Chamadas de Sistema: São a forma de interagir com o kernel do sistema operacional para tarefas como sair (exit, syscall 60) ou escrever na tela (write, syscall 1).
  • Convenção de Registradores: O número da syscall vai em rax, e os argumentos em rdi, rsi, rdx, etc.
  • Compilação em Duas Etapas: O código é primeiro montado (nasm) para um arquivo objeto (.o) e depois ligado (ld) para criar o executável final.
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