How to write hello world in assembler under Windows?

前端 未结 8 905
情书的邮戳
情书的邮戳 2020-11-22 12:01

I wanted to write something basic in assembly under Windows, I\'m using NASM, but I can\'t get anything working.

How to write and compile hello world without the he

相关标签:
8条回答
  • 2020-11-22 12:50

    These are Win32 and Win64 examples using Windows API calls. They are for MASM rather than NASM, but have a look at them. You can find more details in this article.

    This uses MessageBox instead of printing to stdout.

    Win32 MASM

    ;---ASM Hello World Win32 MessageBox
    
    .386
    .model flat, stdcall
    include kernel32.inc
    includelib kernel32.lib
    include user32.inc
    includelib user32.lib
    
    .data
    title db 'Win32', 0
    msg db 'Hello World', 0
    
    .code
    
    Main:
    push 0            ; uType = MB_OK
    push offset title ; LPCSTR lpCaption
    push offset msg   ; LPCSTR lpText
    push 0            ; hWnd = HWND_DESKTOP
    call MessageBoxA
    push eax          ; uExitCode = MessageBox(...)
    call ExitProcess
    
    End Main
    

    Win64 MASM

    ;---ASM Hello World Win64 MessageBox
    
    extrn MessageBoxA: PROC
    extrn ExitProcess: PROC
    
    .data
    title db 'Win64', 0
    msg db 'Hello World!', 0
    
    .code
    main proc
      sub rsp, 28h  
      mov rcx, 0       ; hWnd = HWND_DESKTOP
      lea rdx, msg     ; LPCSTR lpText
      lea r8,  title   ; LPCSTR lpCaption
      mov r9d, 0       ; uType = MB_OK
      call MessageBoxA
      add rsp, 28h  
      mov ecx, eax     ; uExitCode = MessageBox(...)
      call ExitProcess
    main endp
    
    End
    

    To assemble and link these using MASM, use this for 32-bit executable:

    ml.exe [filename] /link /subsystem:windows 
    /defaultlib:kernel32.lib /defaultlib:user32.lib /entry:Main
    

    or this for 64-bit executable:

    ml64.exe [filename] /link /subsystem:windows 
    /defaultlib:kernel32.lib /defaultlib:user32.lib /entry:main
    

    Why does x64 Windows need to reserve 28h bytes of stack space before a call? That's 32 bytes (0x20) of shadow space aka home space, as required by the calling convention. And another 8 bytes to re-align the stack by 16, because the calling convention requires RSP be 16-byte aligned before a call. (Our main's caller (in the CRT startup code) did that. The 8-byte return address means that RSP is 8 bytes away from a 16-byte boundary on entry to a function.)

    Shadow space can be used by a function to dump its register args next to where any stack args (if any) would be. A system call requires 30h (48 bytes) to also reserve space for r10 and r11 in addition to the previously mentioned 4 registers. But DLL calls are just function calls, even if they're wrappers around syscall instructions.

    Fun fact: non-Windows, i.e. the x86-64 System V calling convention (e.g. on Linux) doesn't use shadow space at all, and uses up to 6 integer/pointer register args, and up to 8 FP args in XMM registers.


    Using MASM's invoke directive (which knows the calling convention), you can use one ifdef to make a version of this which can be built as 32-bit or 64-bit.

    ifdef rax
        extrn MessageBoxA: PROC
        extrn ExitProcess: PROC
    else
        .386
        .model flat, stdcall
        include kernel32.inc
        includelib kernel32.lib
        include user32.inc
        includelib user32.lib
    endif
    .data
    caption db 'WinAPI', 0
    text    db 'Hello World', 0
    .code
    main proc
        invoke MessageBoxA, 0, offset text, offset caption, 0
        invoke ExitProcess, eax
    main endp
    end
    

    The macro variant is the same for both, but you won't learn assembly this way. You'll learn C-style asm instead. invoke is for stdcall or fastcall while cinvoke is for cdecl or variable argument fastcall. The assembler knows which to use.

    You can disassemble the output to see how invoke expanded.

    0 讨论(0)
  • 2020-11-22 12:51

    If you want to use NASM and Visual Studio's linker (link.exe) with anderstornvig's Hello World example you will have to manually link with the C Runtime Libary that contains the printf() function.

    nasm -fwin32 helloworld.asm
    link.exe helloworld.obj libcmt.lib
    

    Hope this helps someone.

    0 讨论(0)
提交回复
热议问题