Implementação de uma calculadora gráfica em arquitetura x64 puro Assembly

Resumo
Este trabalho apresenta o desenvolvimento e a implementação de uma calculadora com interface gráfica nativa para sistemas operacionais Windows, desenvolvida inteiramente em linguagem Assembly para arquitetura x86-64. Diferente de abordagens convencionais que utilizam bibliotecas de alto nível e ambientes de tempo de execução (Runtime C/C++), este programa interage diretamente com a interface de programação de aplicativos do Windows (Windows API), demonstrando em detalhe a estrutura de janelas, o fluxo de mensagens, a criação de controles e a manipulação de dados em nível de arquitetura. O resultado é um executável de tamanho reduzido, sem dependências externas e que ilustra os princípios fundamentais de funcionamento de aplicações gráficas na plataforma Windows.
Palavras-chave: Assembly x86-64; Windows API; Interface Gráfica; Processamento de Mensagens; Programação de Baixo Nível.
Introdução
A programação de aplicações gráficas é comumente realizada por meio de linguagens de alto nível e frameworks que abstraem a complexidade do sistema operacional. Embora essa prática seja eficiente para o desenvolvimento de software produtivo, ela oculta os mecanismos fundamentais que regem a criação de janelas, a comunicação com o sistema operacional e a organização da memória e da pilha de execução.
A linguagem Assembly permite ao programador compreender e controlar diretamente os recursos do processador e do sistema operacional. Em especial, a arquitetura x86-64 apresenta um conjunto de registradores e uma convenção de chamada bem definida para a plataforma Windows, que possibilita a construção de aplicações gráficas funcionais por meio de chamadas diretas às funções do sistema.
Este trabalho tem como objetivo apresentar o projeto e a implementação de uma calculadora gráfica desenvolvida puramente em Assembly x64, utilizando exclusivamente funções da Windows API. Discutem-se a estrutura da aplicação, a convenção de chamada utilizada, o tratamento de mensagens e a lógica de funcionamento, bem como as dificuldades encontradas e as soluções adotadas durante o desenvolvimento.
Fundamentos Teóricos
A Plataforma Windows e a Interface Gráfica
As aplicações com interface gráfica no Windows seguem um modelo orientado a eventos. O sistema operacional notifica a aplicação sobre ações do usuário (cliques, digitação, movimentação da janela) por meio de mensagens que são enfileiradas e processadas pela própria aplicação.
Para que uma janela exista, é necessário:
1. Registrar uma classe de janela informando características e procedimento de tratamento de mensagens;
2. Instanciar a janela principal;
3. Executar um laço de leitura e despacho de mensagens.
Convenção de Chamada na Arquitetura x64 Windows
A plataforma Windows para processadores de 64 bits adota uma convenção de chamada padronizada:
- Os quatro primeiros parâmetros são passados pelos registradores: RCX, RDX, R8 e R9;
- Parâmetros subsequentes são enviados por meio da pilha, com deslocamentos consecutivos;
- Antes de cada chamada de função, a pilha deve ser alinhada em endereços múltiplos de 32 bytes;
- A função chamada preserva os registradores RBX, RBP, RSI, RDI, R12–R15, devolvendo-os inalterados ao chamador.
Funções Essenciais da Windows API Utilizadas
Função
Propósito
GetModuleHandleA
Obtém o endereço da instância do programa
RegisterClassExA
Registra as características da classe de janela
CreateWindowExA
Cria a janela principal e controles (botões, campos de texto)
ShowWindow / UpdateWindow
Exibe e redesenha a janela
GetMessageA
Lê mensagens da fila de eventos do sistema
TranslateMessage
Converte mensagens de teclado
DispatchMessageA
Envia mensagens ao procedimento da janela
SetWindowTextA
Atualiza o texto exibido no visor
PostQuitMessage
Encerra o laço de mensagens
DefWindowProcA
Processa mensagens não tratadas pela aplicação
Metodologia e Desenvolvimento
Estrutura Geral do Programa
A aplicação foi organizada em quatro etapas principais:
- Inicialização: obtenção da instância do programa e registro da classe de janela;
- Criação da Janela Principal e Controles: instanciação da janela, do visor e dos botões numéricos e de operação;
- Laço de Mensagens: leitura, tradução e despacho contínuo de eventos do sistema;
- Procedimento de Janela: tratamento de criação, comandos e encerramento.
Tratamento de Mensagens
O procedimento WindowProc é o núcleo lógico da aplicação. Ele recebe mensagens enviadas pelo sistema e responde conforme o tipo:
- WM_CREATE: acionada no momento da criação da janela. Nesta etapa, instancia-se o campo de exibição (visor alinhado à direita, somente leitura) e cada um dos 16 botões organizados em quatro linhas: dígitos de 0 a 9, ponto decimal, operadores (+ − × /), botão de limpeza (C) e botão de igualdade (=). Cada botão é criado por chamada direta à função CreateWindowExA, com posicionamento e dimensões definidos em coordenadas de tela.
- WM_COMMAND: acionada quando o usuário clica em um botão. O identificador do controle é extraído e comparado para executar a ação correspondente:
- Dígitos: concatenam o caractere ao número exibido;
- Ponto decimal: insere separador, evitando repetição;
- Operadores: convertem o valor exibido em inteiro e armazenam o valor e o tipo de operação;
- Botão de igualdade: realiza a operação aritmética, trata divisão por zero e converte o resultado de volta para texto;
- Botão C: reinicia todos os valores e exibe o número zero.
- WM_DESTROY: encerra a aplicação corretamente ao fechar a janela.
Mensagens não tratadas são encaminhadas à função padrão DefWindowProcA.
Conversão de Dados
Como a API do Windows trabalha com texto e os cálculos exigem valores numéricos, foram implementadas duas rotinas auxiliares:
- StringParaInteiro: percorre caractere por caractere, convertendo o texto em valor inteiro com sinal;
- InteiroParaString: converte o resultado numérico de volta para sequência de caracteres, tratando sinal negativo e valor zero.
Compilação e Linkagem
O código foi montado com o NASM no formato binário de 64 bits e posteriormente vinculado ao executável por meio do GCC (MinGW-w64), que realiza a ligação com as bibliotecas do sistema user32.dll (interface gráfica) e kernel32.dll (funções básicas).
bash
nasm -f win64 calc.asm -o calc.o
gcc calc.o -o calc.exe -mwindows -luser32 -lkernel32
Resultados e Discussão
Tamanho e Independência de Runtime
O executável gerado possui aproximadamente 15 KB e não exige bibliotecas adicionais ou ambientes de tempo de execução instalados no sistema. Essa característica contrasta com aplicações compiladas em linguagens de alto nível, que frequentemente dependem de bibliotecas externas e apresentam tamanho significativamente maior.
Desafios e Correções
Durante o desenvolvimento, foram identificados problemas diretamente relacionados à programação em nível de arquitetura:
- Alinhamento da Pilha: chamadas a funções da Windows API exigem que a pilha esteja alinhada em 32 bytes antes de cada instrução call. O não cumprimento dessa regra causava falhas silenciosas e fechamento inesperado da janela;
- Convenção de Chamada: o uso incorreto de registradores e deslocamentos na pilha resultava em parâmetros inválidos enviados às funções, impedindo a criação de controles;
- Sintaxe e Tamanho de Operandos: especificadores de tamanho redundantes em instruções de movimentação causavam erros de montagem, exigindo estrita observância às regras do montador NASM.
Funcionamento Final
A versão corrigida apresenta janela visível imediatamente ao ser executada, com visor funcional e todos os botões reagindo corretamente aos cliques. As quatro operações aritméticas funcionam conforme esperado, com tratamento de erro para divisão por zero e reinicialização completa ao acionar o botão de limpeza.
Conclusão
Este trabalho demonstrou a viabilidade e a complexidade da construção de uma aplicação gráfica funcional utilizando exclusivamente linguagem Assembly e chamadas diretas ao sistema operacional. Foi possível compreender em detalhe a estrutura de janelas, o fluxo de mensagens, a convenção de chamada da arquitetura x64 Windows e a forma como o sistema operacional interage com as aplicações.
Embora essa abordagem demande conhecimento aprofundado da arquitetura do processador e das funções do sistema, ela oferece total controle sobre o comportamento do programa, resultando em executáveis extremamente leves e sem dependências externas. Os desafios encontrados — especialmente quanto ao alinhamento da pilha e à passagem de parâmetros — evidenciam a importância de dominar os fundamentos da arquitetura de computadores para o desenvolvimento de software robusto.
Como trabalhos futuros, sugere-se a ampliação da precisão numérica com suporte a ponto flutuante, a implementação de funções matemáticas adicionais, o suporte a entrada por teclado e o aprimoramento da apresentação visual por meio de recursos gráficos avançados da API.
Referências
- RUSSINOVICH, M. E.; SOLOMON, D. A. Windows Internals: Parte 1. 7. ed. Microsoft Press, 2021.
- FOG, A. Optimizing Subroutines in Assembly Language. Disponível em: https://www.agner.org/optimize/, 2024.
- MICROSOFT. Windows API Documentation. Disponível em: https://learn.microsoft.com/windows/win32/api/, 2026.
- NASM Development Team. NASM — The Netwide Assembler Documentation. Disponível em: https://nasm.us/, 2026.
- MINGW-W64 Project. MinGW-w64: GCC for Windows. Disponível em: https://www.mingw-w64.org/, 2026.
Repositório:➖ https://github.com/fydelis2025/Calculadora_ASM


