Olá Mundo em Assembly no Ubuntu Linux, com Yasm Assembler
Olá Mundo em Assembly x86_64 no Ubuntu Linux, com Yasm Assembler
Fala pessoal! Neste tutorial vamos trabalhar um pouco com a linguagem Assembly, criando um programa bem simples para explorar suas instruções.
O programa será escrito em Assembly para a arquitetura Linux x86_64, usando o assembler Yasm (The Yasm Modular Assembler Project). O programa imprime a string “Olá Bóson” (ou qualquer outra que você queira) no terminal e depois encerra o programa.
Para escrever o código, abra um editor de texto de sua preferência (eu usei o editor Geany), digite o código a seguir e salve o arquivo com o nome de olaMundo.s em um diretório de sua preferência (a extensão .s é importante!)
Código
;olaMundo.s
section .data
msg db 'Ola Bóson'
nl db 0x0a
tamMsg equ $-msg
section .text
global _start
_start:
mov rax, 1
mov rdi, 1
mov rsi, msg
mov rdx, tamMsg
syscall
mov rax, 60
mov rdi, 0
syscall
A seguir mostro uma explicação detalhada do código, instrução por instrução.
Explicação do código
O código é organizado em duas seções principais: .data e .text, as quais são definidas a seguir:
Seção .data:
A seção .data é usada para declarar e alocar espaço para dados, como variáveis, constantes e buffers.
Dados declarados nesta seção são geralmente usados para armazenar valores que o programa irá usar durante sua execução, como por exemplo números inteiros, strings, arrays e outros tipos de dados.
Em nosso exemplo temos:
- msg db ‘Olá Bóson’: Define uma variável chamada msg que armazena a string “Olá Bóson”.
- nl db 0x0a: Define uma variável nl com o valor hexadecimal 0x0a, que representa uma nova linha na tabela ASCII.
- tamMsg equ $-msg: Calcula o tamanho da string msg subtraindo o endereço inicial de msg do endereço atual ($). Isso é usado para determinar o comprimento da string durante a execução.
Seção .text
Já a seção .text contém as instruções de código Assembly, ou seja, o programa real que é executado.
Esta seção contém a lógica do programa, incluindo operações aritméticas, controle de fluxo (condicionais, laços de repetição) e chamadas de funções, entre outras.
Em nosso código de exemplo:
- global _start: Ponto de entrada do programa é definido como _start.
- _start: Rótulo que define o ponto de entrada do programa. Indica onde a execução do programa começa.
- mov rax, 1: Grava o valor 1 em rax, que é o número do sistema para a syscall sys_write (escrever na saída padrão).
- mov rdi, 1: Grava o valor 1 no registrador rdi, indicando que a saída será no stdout (file descriptor 1), ou saída padrão.
- mov rsi, msg: Grava o endereço da string msg no registrador rsi, apontando para a mensagem a ser impressa.
- mov rdx, tamMsg: Ajusta o tamanho da mensagem em rdx, indicando quantos bytes devem ser escritos.
- syscall: Chamada de sistema para escrever a mensagem no terminal.
Após escrever a mensagem, o programa usa novamente syscall para chamar sys_exit (número do sistema 60) e encerrar o programa. O código de status de saída é 0, indicando que o programa terminou sem erros.
A primeira linha do código, ;olaMundo.s, é um comentário, e por conta disso é ignorada pelo compilador. Os comentários se iniciam com o caractere ; (ponto-e-vírgula), e se estendem até o final da linha.
Como executar esse programa? Veremos na próxima seção.
Como rodar o programa em Assembly
Para executar e testar o programa escrito, abra um terminal (alternativamente, execute direto a partir do editor de textos / IDE, se estiver configurado para tal), entre no diretório que contém o código-fonte criado anteriormente, e execute os comandos a seguir:
1 – Gerar um arquivo binário a partir do código-fonte:
$ yasm -f elf64 olaMundo.s
Esse comando lê o arquivo “olaMundo.s” contendo o código assembly digitado e gera um arquivo objeto binário ELF de 64 bits a partir dele, usando o assembler yasm. Será gerado o arquivo olaMundo.o.
A opção -f elf64 especifica o formato de saída desejado. Aqui, indica que o formato de saída deve ser ELF (Executable and Linkable Format) de 64 bits. Trata-se de um formato de arquivo comum usado em sistemas Unix e Linux para executáveis e bibliotecas compartilhadas.
2 – Vincular o arquivo objeto e gerar programa executável:
$ ld -o olaMundo olaMundo.o
O comando diz ao linker ld para usar o arquivo objeto olaMundo.o como entrada e gerar um arquivo executável de nome olaMundo como saída. O arquivo executável é a versão final do programa que pode ser executada no sistema operacional.
ld é o nome do vinculador (linker), que é uma ferramenta que combina um ou mais arquivos objeto em um único arquivo executável (mais sobre esse assunto nos próximos tutoriais).
3 – Vamos verificar o arquivo executável criado no diretório:
$ ls -l
Deve ter sido gerado um arquivo executável de nome olaMundo no diretório atual.
4 – Finalmente, rodamos o programa:
$ ./olaMundo
Resultado:
Olá Bóson
Excelente! Nosso primeiro programa em Assembly criado, compilado e executado com sucesso. Nos próximos artigos vamos explorar mais a linguagem de forma sistemática, para entender como funcionam suas diversas declarações, mnemônicos e estruturas lógicas, e assim criar programas mais complexos.
Até!
Escreva um comentário