Executando verificação de segurança...
11

Explorando Assembly: Rodando 'Hello, World!' usando Docker

Assembly é uma linguagem de baixo nível que permite escrevermos código diretamente em instruções de máquina. Neste texto, vamos explorar como criar um simples programa "Hello, World!" em Assembly x86 e executá-lo em um ambiente Docker.

Como funciona o código

O código fornecido é escrito em Assembly x86 e utiliza as interrupções do sistema operacional para realizar a escrita de uma mensagem na saída padrão e, em seguida, sair do programa.

Aqui está uma explicação simplificada de como o código funciona:

  1. A seção .data:

    • O trecho hello db 'Hello, World!',10 define uma variável chamada hello que armazena a mensagem "Hello, World!" seguida do caractere 10 (que representa uma quebra de linha).
    • O trecho helloLen equ $ - hello define uma variável chamada helloLen que calcula o tamanho da string hello subtraindo o endereço atual ($) do início da variável hello.
  2. A seção .text:

    • O trecho _start: marca o ponto de entrada do programa.

    • mov eax, 4 define o número da interrupção 4 (sys_write), que é utilizada para escrever na saída padrão.

    • mov ebx, 1 define o descritor de arquivo 1, que representa a saída padrão (stdout).

    • mov ecx, hello carrega o endereço inicial da mensagem hello no registrador ecx.

    • mov edx, helloLen carrega o tamanho da mensagem hello no registrador edx.

    • int 0x80 gera a interrupção 0x80, que aciona a chamada do sistema para escrever a mensagem na saída padrão.

    • xor ebx, ebx define o valor 0 no registrador ebx.

    • mov eax, 1 define o número da interrupção 1 (sys_exit), que é utilizada para encerrar o programa.

    • int 0x80 gera a interrupção 0x80, que aciona a chamada do sistema para encerrar o programa.

  3. A função write(1, hello, helloLen) escreve a string hello na saída padrão utilizando a chamada do sistema sys_write.

  4. A função exit(0) encerra o programa, utilizando a chamada do sistema sys_exit e retornando o valor 0.

No geral, o programa carrega os valores apropriados nos registradores para invocar as chamadas do sistema necessárias (sys_write e sys_exit) por meio da interrupção 0x80, resultando na impressão da mensagem "Hello, World!" na saída padrão e no encerramento do programa com código de saída igual a zero.

Preparando o ambiente Docker

Para preparar o ambiente Docker, siga estes passos:

  1. Instale o Docker: Visite o site oficial do Docker (https://www.docker.com) e siga as instruções de instalação específicas para o seu sistema operacional. Certifique-se de ter o Docker Engine instalado corretamente.

  2. Verifique a instalação: Após a instalação, abra um terminal ou prompt de comando e execute o seguinte comando para verificar se o Docker foi instalado corretamente:

    docker --version
    

    Ele deve exibir a versão do Docker instalada.

  3. Crie um diretório de trabalho: Crie um diretório em seu sistema onde você deseja armazenar seus arquivos do Docker, por exemplo, docker-workspace.

  4. Crie um arquivo Dockerfile: Dentro do diretório de trabalho, crie um arquivo chamado Dockerfile. Esse arquivo conterá as instruções para construir a imagem do Docker.

  5. Edite o Dockerfile: Abra o arquivo Dockerfile em um editor de texto e adicione o seguinte conteúdo:

    FROM ubuntu:latest
    WORKDIR /app
    COPY hello.asm /app
    RUN apt-get update && apt-get install -y nasm
    RUN nasm -f elf32 -o hello.o hello.asm
    RUN ld -m elf_i386 -s -o hello hello.o
    CMD ["./hello"]
    
  6. Crie o arquivo "hello.asm": No mesmo diretório de trabalho, crie um arquivo chamado hello.asm e adicione o código Assembly "Hello, World!" que você deseja executar. Por exemplo, o código que foi explicado anteriormente.

  7. Construa a imagem do Docker: No terminal ou prompt de comando, navegue até o diretório de trabalho e execute o seguinte comando para construir a imagem do Docker:

    docker build -t hello-assembly .
    

    Isso irá criar uma imagem com o nome hello-assembly a partir do Dockerfile.

Agora você tem um ambiente Docker configurado com uma imagem que contém o NASM instalado e seu código Assembly. Você pode executar o código Assembly dentro do contêiner Docker usando comandos adicionais do Docker, como docker run, para testar e executar seu programa "Hello, World!".

Criar um arquivo Makefile com os comandos para facilitar a construção

Criar um arquivo Makefile com os comandos para facilitar a construção, a publicação e a execução da imagem do container. O arquivo define uma variável NAME com o nome da imagem e três regras: build, pub e run. A regra build usa o comando docker build para construir a imagem a partir do Dockerfile. A regra pub usa o comando docker push para publicar a imagem em um repositório remoto. A regra run usa o comando docker run para executar o container em modo interativo e remover o container após a execução.

NAME := assembly_enviroment

build:
docker build -t $(NAME) .

pub: build
docker push $(NAME)

run:
docker run -it --rm $(NAME)

Executar o comando make run para construir a imagem do container, se necessário, e executar o container. O resultado esperado é a impressão de "Hello, World!" na tela.

$ make run
Hello, World!

Conclusão

Neste post, aprendemos como criar um simples "Hello, World!" na tela e como rodar ele em um container Docker. Deixe seu comentário abaixo. Até a próxima!

Carregando publicação patrocinada...
2
1
1

Assembly é lindo! Até onde conheço é a maneira mais próxima possivel para se conversar como computador.
É util? Não sei, mas é muito importante entender como funciona e ter noção disso.
Acredito que algumas aplicações bem específicas de hardware podem ser otimizadas usando trechos Assembly junto com outras linguagens.

2

@rbardal o Assembly serve geralmente pra dar suporte a programação em sistemas embarcados com recursos limitados ou quando você precisa ter acesso ao baixo nível em drivers ou executáveis críticos. Mas é sem dúvidas um conhecimento valioso.

1

Coisas que aprendi escrevendo Assembly:

  • Assembly nivela por baixo: Não existe bam bam bam quando o negocio é Assembly! Se não documentar, se lascou! Tanto numa calculadora simples, quanto no Assembly do kernel Linux, o que todos tem em comum é que são extramamente bem documentados.
  • Seja elegante!: Assembly é uma das linguagens(sintaxe) mais lindas que já vi. Todo código assembly além de bem documentado, é bem editado! e isso nos leva ao proximo tópico...
  • Seja paciente!: Essa eu levei pra vida! Programas em assembly as vezes são grandes e você vai precisar de paciencia para conclui-lo. Principalmente porque você vai escrever muitos comentarios, vai compila-los, recompilar e etc. E mesmo depois de escrever tudo direitinho, vai ter que documentar e comentar para não esquecer o que estava fazendo haha

Agora minha dica (não vale muita coisa, mas se está interessado..):

Apesar de muito legal esse post, não tem muita necessidade de usar Docker para aprender assembly(pelo menos no linux). Se você usa uma distribuição linux, ela provavelmente veio com o GCC, você pode criar scripts C e incluir Assembly neles(só falei por curiosidade mesmo, não é interessante fazer isso). Você também pode instalar o NASM e o FASM! NASM e FASM são compiladores e lincadores de Assembly, recomendo que aprenda o NASM. FASM é parte dos projetos da GNU e acho que vem junto com GCC, mas ele usa uma sintaxe diferente. Já o NASM usa tanto a sintaxe intel x86 quanto outras, sendo mais facil de escrever Assembly com ele!

NASM talvez esteja disponivel para Windows também, mas nunca usei Assembly/C/C++ no windows, então não sei como anda o desenvolvimento nessa plataforma. MAS se você usa Windows, sempre pode instalar o Docker, instalar uma imagem ubuntu e desenvolver seu Assembly tranquilamente :)