Ir para conteúdo

Hello world em MASM no Windows


Fernando Mercês

Posts Recomendados

Segue um "Hello, world" em MASM no Windows para os interessados. A graça do MASM é que, mesmo programando em Assembly, é possível chamar as funções da API do Windows (e de outras bibliotecas) usando o comando invoke.

1. Baixar e instalar o MASM32 SDK do site oficial (já vem o compilador, linker e também um editor).

2. Depois de instalado, abra o MASM32 Editor. Copie e cole o seguinte código:

; fonte: https://stackoverflow.com/questions/4568306/outputting-hello-world-in-masm-using-win32-functions

.386
.model flat, stdcall
option casemap: none

include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

.data
    szCaption   db  'Hello', 0
    szText      db  'Hello, World!', 0

.code
    start:
            invoke MessageBox, NULL, offset szText, offset szCaption, MB_OK
            invoke ExitProcess, NULL        
    end start

3. Salve o arquivo como hello.asm, clique em Project -> Assemble & Link. Um hello.exe será gerado.

Explicando:

.386 define o conjunto de instruções suportados pelo teu programa. O mínimo pra um EXE de 32-bits é .386, mas o MASM tem suporte à vários outros conjuntos de instruções (.386, .486, .586, .686, .mmx, etc).

.model flat, stdcall

flat diz respeito ao modelo de endereçamento de memória linear e vai fazer o compilador gerar EXE de 32-bits. Já stdcall, diz respeito à calling convention (como o Assembler vai gerar o código para chamadas de função, limpeza da pilha, passagem de argumentos, etc). Da documentação do MASM:

59d289e451bd2_ScreenShot2017-10-02at15_31_32.thumb.png.6c8f31316d1a6acd4e8874fca6cc55f5.png

option casemap:none

Ativa o case sensitive, necessário para chamar as funções da API do Windows já que seus nomes são sensíveis ao caso.

include

Inclui as os headers (como se fossem os .h do C) já prontos do MASM para usar as bibliotecas do Windows.

inbludelib

Inclui o código compilado necessário para chamar tais bibliotecas da maneira que o MASM chama. É que quem desenvolve o MASM já escreveu e deixou tudo isso pronto para uso.

.data

Cria uma nova seção de dados no arquivo. O db define um ou mais bytes. À esquerda dele é o nome (como se fosse o nome de uma variável) que você escolhe e à direita os dados em si, no caso, uma sequência de bytes representando uma string terminada em NULL (byte 0x00). Há também o dw (para dword), dd (para double word), etc.

.code

Inicia uma seção de código. O label .start marca o início dela (o MASM requer o end start no fim).

invoke

Sendo parte da linguagem de alto nível do MASM, permite chamar as funções de acordo com a calling convention definida sem se preocupar em como os parâmetros serão passados, quem vai limpar a pilha, etc. Basicamente te permite programar em Assembly no estilo do C (o compilador trata das convenções). Os parâmetros são passados para a função depois do nome delas, separados por vírgula.

O código fica lindo ó:

masmhelloolly.thumb.png.9b7676d2bea7c80853f833ce806e415f.png

Seria bem trabalhoso fazer tudo isso com outro assembler. Sei que o fasm tem umas facilidades também mas em nasm por exemplo seria loko.

Só para colocar mais lenha na fogueira (de quem não gosta de HLA - High Level Assembly), o MASM tem umas macros maneiras pra ajudar quando criando loops, condicionais... Por exemplo, a macro .if/.endif substitui os loops com instruções CMP e Jcc:

    start:
            mov eax, 0deadbeefh
            .if eax == 2017
                invoke MessageBox, NULL, offset szText, offset szCaption, MB_OK
            .endif
            invoke ExitProcess, NULL        
    end start

O resultado é:

beef.thumb.png.879cf9482ef9b2711f5336b2513bc927.png

Claro que para quem está estudando Assembly é legal também trabalhar sem as macros e para isso o MASM funciona normalmente - basta usar as instruções direto. Você tem o poder da escolha se vai querer seus fontes raiz ou Nutella. :D

Link para o comentário
Compartilhar em outros sites

  • 3 semanas depois...
  • 1 mês depois...

Em tempo, hoje tava dando uma olhada nas ferramentas de linha de comando que vêm com o Visual Studio e descobri o MASM lá (ml.exe). Aqui fica em: C:\Program Files\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.11.25503\bin\Hostx86\x86 (a versão de 32-bits). Compilei o mesmo programa do post original do tópico com a seguinte linha:

> ml.exe hello.asm /link /subsystem:windows

O resultado do disassembly:

masm14.thumb.png.1968360c1408e3247b96904b8c5075fb.png

Link para o comentário
Compartilhar em outros sites

12 horas atrás, Fernando Mercês disse:

Em tempo, hoje tava dando uma olhada nas ferramentas de linha de comando que vêm com o Visual Studio e descobri o MASM lá (ml.exe). Aqui fica em: C:\Program Files\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.11.25503\bin\Hostx86\x86 (a versão de 32-bits). Compilei o mesmo programa do post original do tópico com a seguinte linha:


> ml.exe hello.asm /link /subsystem:windows

O resultado do disassembly:

masm14.thumb.png.1968360c1408e3247b96904b8c5075fb.png

 

VS2013, VS2015 posso confirmar que já tem o MASM integrado também. Acho bem prático desenvolver asm no visual studio.

Segue um guia de como compilar x86, x64 no visual studio http://kipirvine.com/asm/gettingStartedVS2013/index.htm#CreatingProject

Extensão highlight pra masm no visual studio (com uma boa configuração fica good): https://marketplace.visualstudio.com/items?itemName=Trass3r.AsmHighlighter#review-details

 

Link para o comentário
Compartilhar em outros sites

Eis porque não gosto muito de criar aplicações diretamente em assembly: Praticamente não há vantagem alguma em fazê-lo. Experimente criar o mesmo programinha em C, compilá-lo e linká-lo extirpando os símbolos desnecessários e faça o mesmo com o seu código com o MASM. É possível que obtenha executáveis com o mesmíssimo tamanho.

Outro detalhe é quanto à "versão" do Windows em uso... No Win64 a convenção de chamada é diferente, usando os registradores RCX, RDX, R8 e R9 para os 4 primeiros argumentos de uma chamada, ao invés da pilha (que é o padrao de cdecl e stdcall no modo i386 - ou Win32). Eis um código igual ao acima, para Win64, mas usando o NASM:

bits 64

section .rodata

msg:
  db  "Hello!",0
caption:
  db  "Hello Windows App",0

section .text

  ; Importado de user32.dll
  extern __imp_MessageBoxA

  global WinMain
WinMain:
  sub   rsp,40        ; Isso é necessário.
                      ; Estranhamente é preciso avançar RSP
                      ; por causa dos argumentos de WinMain e
                      ; o endereço de retorno... senão dá crash!

  xor   ecx,ecx       ; hWnd = NULL
  lea   rdx,[msg]     ; msg ptr
  lea   r8,[caption]  ; caption ptr
  mov   r9d,0x40      ; MB_OK | MB_ICONINFORMATION
  call  [__imp_MessageBoxA] 

  xor   eax,eax       ; return 0L;

  add   rsp,40        ; Retorna a pilha para o lugar original.

  ret

Note que MessageBoxA está sendo chamada indiretamente, via o ponteiro que é inicializado ao importar as bibliotecas libkernel32.a e libuser32.a (que contém código e links para late biding com as respectivas DLLs)... A macro "invoke" faz o que fiz acima (mas, no caso, usei a convenção para Win64).

Para compilá-lo, usando o MinGW64 (no Linux), pode-se usar o seguinte Makefile:

CC=x86_64-w64-mingw32-gcc

hellowin.exe: hellowin.o
	$(CC) -Wl,--subsystem=windows -s -o $@ $^ -luser32 -lkernel32

hellowin.o: hellowin.asm
	nasm -fwin64 -o $@ $<

Isso ai vai gerar um hellowin.exe com apenas 16 KiB (a mesma coisa que seria gerada com um arquivo em C) e funciona direitinho:

5a2409c5d7cff_Screenshot2017-12-03122501.png.7a7d783f68ea50aa63c92088048dccbe.png

Link para o comentário
Compartilhar em outros sites

  • 5 meses depois...
Microsoft (R) Macro Assembler Version 6.14.8444
Copyright (C) Microsoft Corp 1981-1997.  All rights reserved.

 Assembling: C:\masm32\hello.asm
C:\masm32\hello.asm(3) : error A2008: syntax error : .
C:\masm32\hello.asm(4) : error A2085: instruction or register not accepted in cu
rrent CPU mode

***********
ASCII build
***********

\masm32\include\windows.inc(78) : error A2119: language type must be specified
\masm32\include\windows.inc(79) : error A2119: language type must be specified
\masm32\include\windows.inc(80) : error A2119: language type must be specified
\masm32\include\windows.inc(81) : error A2119: language type must be specified
\masm32\include\windows.inc(82) : error A2119: language type must be specified
\masm32\include\windows.inc(83) : error A2119: language type must be specified
\masm32\include\windows.inc(84) : error A2119: language type must be specified
\masm32\include\windows.inc(85) : error A2119: language type must be specified
\masm32\include\windows.inc(86) : error A2119: language type must be specified
\masm32\include\windows.inc(87) : error A2119: language type must be specified
\masm32\include\windows.inc(88) : error A2119: language type must be specified
\masm32\include\windows.inc(89) : error A2119: language type must be specified
\masm32\include\windows.inc(90) : error A2119: language type must be specified
\masm32\include\windows.inc(91) : error A2119: language type must be specified
\masm32\include\windows.inc(92) : error A2119: language type must be specified
\masm32\include\windows.inc(93) : error A2119: language type must be specified
\masm32\include\windows.inc(94) : error A2119: language type must be specified
\masm32\include\windows.inc(95) : error A2119: language type must be specified
\masm32\include\windows.inc(96) : error A2119: language type must be specified
\masm32\include\windows.inc(97) : error A2119: language type must be specified
\masm32\include\windows.inc(98) : error A2119: language type must be specified
\masm32\include\windows.inc(99) : error A2119: language type must be specified
\masm32\include\windows.inc(100) : error A2119: language type must be specified
\masm32\include\windows.inc(101) : error A2119: language type must be specified
\masm32\include\windows.inc(102) : error A2119: language type must be specified
C:\masm32\hello.asm(13) : error A2013: .MODEL must precede this directive
C:\masm32\hello.asm(14) : error A2034: must be in segment block
C:\masm32\hello.asm(15) : error A2034: must be in segment block
C:\masm32\hello.asm(17) : error A2013: .MODEL must precede this directive
C:\masm32\hello.asm(18) : error A2034: must be in segment block
C:\masm32\hello.asm(19) : error A2034: must be in segment block
C:\masm32\hello.asm(19) : error A2006: undefined symbol : szCaption
C:\masm32\hello.asm(19) : error A2114: INVOKE argument type mismatch : argument
: 3
C:\masm32\hello.asm(19) : error A2006: undefined symbol : szText
C:\masm32\hello.asm(19) : error A2114: INVOKE argument type mismatch : argument
: 2
C:\masm32\hello.asm(20) : error A2034: must be in segment block
C:\masm32\hello.asm(21) : error A2006: undefined symbol : start
C:\masm32\hello.asm(21) : error A2148: invalid symbol type in expression : start

_
Assembly Error
Press any key to continue . . .

Tive esse problema uma semana atrás e vou tentar montar isto novamente, agora com a cabeça mais fresca, Os error que tive usando instruções passada por você!

Meu sistema windows 7 64 

Erro apos executar botão Assemble & Link

Sera que o ERRO esta nesta linha?  C:\masm32\hello.asm(3) : error A2008: syntax error : . 

Algo relacionado ao ponto (.)?

 

Link para o comentário
Compartilhar em outros sites

  • 2 semanas depois...
  • 1 ano depois...
  • 2 semanas depois...

Feedback muito bacana galera do bem!

Mais aí, alguém conseguiu compilar algum dos códigos das POCs do corkami ??

vou anexar os '.asm' usados no exemplo que tentei ( mini.exe )

os links dos .asm que tentei compilar são esses:

mini.asm

consts.inc

 

No mais.  vlw pela atenção @Fernando Mercês , @Leandro Fróes TMJ!

 

consts.inc mini.asm

Link para o comentário
Compartilhar em outros sites

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

  • Quem Está Navegando   0 membros estão online

    • Nenhum usuário registrado visualizando esta página.
×
×
  • Criar Novo...