Bootloader.blog

1. Conhecendo o Parede de Carne

Familiarize-se com o Parede de Carne escrevendo e linkando seu primeiro código Assembly!
6 de mar. de 2026|
AssemblyGNUBootloaderHardware

O botão de ligar

Você aperta o botão de ligar do computador e em poucos segundos está olhando pra uma tela de login. Parece simples. Tão simples que a gente nunca para pra pensar no que acontece entre o apertar do botão e o "bem-vindo" do sistema operacional. Mas tem muita coisa acontecendo nesse meio tempo, e é exatamente esse vão que a gente vai explorar juntos neste livro.

Antes do Linux, antes do Windows, antes de qualquer coisa que você já programou, existe um programa minúsculo, quase invisível, que acorda antes de todo mundo. Ele é o bootloader. Se o sistema operacional é o capitão da nave, o bootloader é o sujeito que liga os motores e esquenta os painéis antes do capitão chegar na ponte de comando. Sem ele, nada acontece.

E é esse programa que você vai construir com as suas próprias mãos.

O que você vai encontrar aqui

Este projeto nasceu de uma conversa com meu orientador, o professor Fernando. Eu disse que queria construir meu próprio sistema do zero. Ele me contou que na faculdade dele, os alunos tiveram dois semestres inteiros (um ano!) para construir seus próprios kernels. Com base nisso, resolvi criar o meu bootloader e um kernel mínimo. Nada grandioso, nada que vá competir com o GRUB. Algo para aprender, se divertir e, eventualmente, ensinar outras pessoas. E cá estou, escrevendo essa página numa sexta-feira qualquer, carregado de café, por puro amor ao assunto.

O que você pode esperar:

Ao longo dos capítulos, você vai trabalhar com Assembly x86 e, mais pra frente, com C. Assembly para falar direto com o hardware, C para construir um kernel mínimo que o bootloader vai carregar. Pense assim: o que seria do Spock sem uma tripulação para comandar? Um bootloader sem kernel é a mesma coisa.

A escrita aqui é descontraída, mas o conteúdo é rigoroso. Cada conceito vai ser discutido nos mínimos detalhes. Ao final de cada capítulo tem exercícios para testar o que você aprendeu, divididos em três níveis: o básico (pra aquecer), o intermediário (pra praticar de verdade) e o desafio (pra quem quer ir além). Você pode criar seu próprio programa, rodar aqui mesmo no site, responder os quizzes, ou se preferir, rodar na sua própria máquina. Mas o setup local é por sua conta. A máquina que disponibilizo aqui é mais que suficiente.

1.1 Bem-vindo ao Parede de Carne

O que é o Parede de Carne?

"The master and core of the world."

Tomei a liberdade ambiciosa de emular uma máquina virtual direto no navegador. Uma distro Alpine Linux, a mais leve que consegui montar sem abdicar de confortos essenciais: um editor de texto decente, o assembler do GNU (as), o linker (ld), e nos capítulos mais avançados, o ecossistema do QEMU para rodarmos nosso próprio bootloader.

E o nome dela? Parede de Carne. Uma homenagem ao Terraria. No jogo, a Wall of Flesh é o último boss antes do Hardmode. Quando você derrota ela, o mundo inteiro muda de nível. Achei o nome apropriado: esse é o portal entre "eu sei programar em linguagens de alto nível" e "eu sei o que acontece quando o computador liga". Depois que você passar por aqui, sua visão de computação muda.

A Parede de Carne vai estar sempre no final de cada capítulo, esperando por você. É ali que você coloca em prática tudo que aprender. Basta clicar no ícone e começar.

O usuário é root e a senha é só teclar Enter.

Você conhece sistemas Unix?

Antes de seguir, preciso perguntar: você já mexeu com terminal Linux antes?

1.2 Seu primeiro programa Assembly

Chega de teoria. Vamos escrever código.

Abra a Parede de Carne e crie um arquivo chamado ola.s:

micro ola.s

Agora digite o seguinte:

.section .data
    msg: .ascii "Ola, Parede de Carne!\n"
    len = . - msg

.section .text
    .globl _start

_start:
    movl $4, %eax
    movl $1, %ebx
    movl $msg, %ecx
    movl $len, %edx
    int $0x80

    movl $1, %eax
    movl $0, %ebx
    int $0x80

Calma, eu sei. Se você nunca viu Assembly antes, isso parece uma sopa de letrinhas. Vamos destrinchar.

O que acabou de acontecer?

O programa tem duas seções. A .section .data é onde guardamos dados, coisas que o programa vai usar. No nosso caso, guardamos uma string: "Ola, Parede de Carne!\n". Aquele \n no final é o caractere de nova linha, o equivalente a dar um Enter. E a linha len = . - msg é um truque esperto: o ponto (.) significa "endereço atual", então . - msg calcula o tamanho da string automaticamente. Sem precisar contar na mão.

A .section .text é onde fica o código executável, as instruções de verdade. E _start é o ponto de entrada do programa, o equivalente ao main() do C. O .globl _start avisa o linker: "ei, o programa começa aqui". É por aqui que a CPU começa a executar.

Agora as instruções em si. Lembra que eu disse que Assembly é falar direto com o hardware? Pois é. Cada movl é literalmente "coloque este valor neste registrador". Registradores são caixinhas de memória dentro da CPU, rápidas como um raio e pequenas como um apartamento em São Paulo.

Uma coisa que você vai notar: na sintaxe AT&T que usamos aqui, a ordem é origem, destino. O $ marca valores imediatos (constantes) e o % marca registradores. Pode parecer estranho no começo, mas você acostuma rápido.

movl $4, %eax       # Syscall número 4 = write (escrever)
movl $1, %ebx       # File descriptor 1 = stdout (a tela)
movl $msg, %ecx     # Endereço da nossa mensagem
movl $len, %edx     # Tamanho da mensagem em bytes
int $0x80           # "Ei, Linux! Executa isso pra mim."

A instrução int $0x80 é uma interrupção de software. É assim que um programa em Assembly pede algo ao Linux: "ei, sistema operacional, preparei os registradores com tudo que você precisa. Executa essa syscall pra mim." No caso, estamos pedindo a syscall write, que escreve bytes na tela.

As últimas três linhas fazem a mesma coisa, mas pedindo a syscall exit (número 1). Sem isso, o programa terminaria de um jeito feio, tentando executar lixo na memória. É boa educação avisar o sistema operacional que você terminou.

movl $1, %eax       # Syscall número 1 = exit (sair)
movl $0, %ebx       # Código de saída 0 = "deu tudo certo"
int $0x80           # Tchau, Linux!

Montando e linkando

Código Assembly não roda direto. Precisa de dois passos: montar (transformar Assembly em código de máquina) e linkar (juntar tudo em um executável).

Salve o arquivo no micro (Ctrl+S) e saia (Ctrl+Q). Agora no terminal:

as --32 ola.s -o ola.o

O GNU Assembler leu seu código e gerou um arquivo objeto (ola.o). Esse arquivo tem o código de máquina, mas ainda não é um programa completo. Pense nele como as peças de um Lego antes de montar.

Agora o linker entra em cena:

ld -m elf_i386 ola.o -o ola

O ld pegou o arquivo objeto e criou um executável chamado ola. Agora sim temos um programa de verdade.

Execute:

./ola

Se tudo deu certo, você deve ver na tela:

Ola, Parede de Carne!

Parabéns. Você acabou de escrever, montar e rodar seu primeiro programa Assembly. Não é um bootloader ainda, mas é o primeiro passo. Todo prédio começa pelo alicerce.

Por que dois passos?

Você deve estar se perguntando: por que não pular direto do Assembly pro executável? Boa pergunta. A resposta curta é que separar a montagem da linkagem permite que você construa programas com múltiplos arquivos. Imagine que seu bootloader tem 3 arquivos .s diferentes. O as monta cada um separadamente, gerando 3 arquivos .o. Depois o ld junta os três em um único executável, resolvendo referências entre eles (tipo quando um arquivo chama uma função de outro).

No nosso caso simples, com um único arquivo, parece um passo desnecessário. Mas confie no processo: quando chegarmos ao Stage 2 e ao kernel em C, você vai agradecer por ter entendido isso cedo.

1.3 Entendendo o fluxo

Vamos recapitular o que aconteceu:

  1. Você escreveu código Assembly em um arquivo .s
  2. O GNU Assembler (as) transformou isso em código de máquina (.o)
  3. O linker (ld) criou um executável
  4. O Linux executou o programa, que usou uma interrupção para pedir ao SO que imprimisse texto na tela

Esse fluxo (escrever → montar → linkar → executar) vai ser seu dia a dia nos próximos capítulos. A diferença é que, em breve, quem vai executar seu código não vai ser o Linux. Vai ser o hardware direto, sem sistema operacional por baixo. E aí a brincadeira fica interessante de verdade.

No próximo capítulo, vamos entender o que é o Real Mode, por que a Intel inventou essa coisa de segmentação de memória em 1978, e por que a gente ainda lida com essa herança quarenta e tantos anos depois. Também vamos começar a nos despedir do conforto do Linux e encarar o hardware de frente.

Seu bootloader está nascendo. Cuide bem dele.


Exercícios

Nível 1: Aquecimento

Modifique o programa ola.s para imprimir uma mensagem diferente. Pode ser seu nome, uma citação, qualquer coisa. O legal é que o len = . - msg recalcula o tamanho sozinho, então você só precisa trocar o texto da string.

Nível 2: Prática

Escreva um programa que imprima duas linhas de texto. Você vai precisar de duas strings na .section .data (tipo msg e msg2, cada uma com seu len) e duas chamadas de int $0x80 com a syscall write. Dica: faça uma segunda sequência de movl + int $0x80 apontando para a segunda mensagem.

Nível 3: Desafio

Escreva um programa que imprima os números de 1 a 5 na tela, cada um em uma linha separada. Parece simples, mas tem um detalhe: o número 1 não é o mesmo que o caractere '1'. O caractere '1' tem o valor ASCII 49. Você vai precisar pensar em como converter o número para o caractere correspondente antes de imprimir. Se travar, não se sinta mal. Pesquise sobre a tabela ASCII e volte depois.


Agora é com você. Abra a Parede de Carne e divirta-se!