0

I am currently trying to learn assembly programming with MASM64. I have managed to get WriteConsoleA to work, but am stuck trying to use C functions like printf or puts. It should be noted that I am using ml64.exe and link.exe outside of Visual Studio and know that I can create executables successfully.

Here is my code:

includelib <kernel32.lib>
includelib <ucrt.lib>
includelib <legacy_stdio_definitions.lib>
includelib <legacy_stdio_wide_specifiers.lib>
includelib <msvcrt.lib>
includelib <vcruntime.lib>

EXTERN puts: PROC
EXTERN ExitProcess: PROC
EXTERN _CRT_INIT: PROC

.data
message BYTE "Another message! Longer this time!", 0

.code
main PROC
    mov rsp, 32    ; Reserve shadow space.

    call _CRT_INIT ; Here I call _CRT_INIT because I'm using a custom entry point.
                   ; I know that this call works because commenting it out causes the
                   ; app to crash instantly instead of opening, printing nothing, but
                   ; still waiting a second.

    add rsp, 32    ; Remove shadow space.

    lea rcx, message ; Load the pointer to my message to the rcx register.

    sub rsp, 32      ; Reserve shadow space.

    call puts        ; Call puts, I know it only takes in a BYTE PTR from the docs.
                     ; The command windows does not crash, it stays open for a moment
                     ; as if the message had been printed, but it is not.
                     ; printf behaves exactly the same as puts here.

    add rsp, 32      ; Remove shadow space.

    xor rcx, rcx     ; Zero out rcx.

    call ExitProcess ; End the process.
main ENDP

END

Neither the assembler nor the linker raises an error. As mentioned, my GetStdHandle and WriteConsoleA both work fine. I have tried omitting the _CRT_INIT but that causes the command window to crash instantly upon opening.

Thank you in advance!

UPDATE: For any future traveller (or me) reading this: Please see @RbMm's comment down below, as well as my comment. It turns out that printf definitely did work - it is just that, unlike WriteConsoleA, it causes the window to terminate the exact moment that the printing is complete! Adding a call to Sleep solved everything.

  • 3
    `mov rsp, 32 ; Reserve shadow space` this is error - at first - not `mov` but `sub`, at second your stack not aligned to 16*n at this point, but `rsp == 16*n+8`. so you need how minimum `sub rsp, 40`. and you not need do this before and after every call but once - in function prolog and epilog – RbMm Apr 03 '22 at 13:02
  • Configure your dev environment to keep output windows open after the program exits, and/or single-step in a debugger, instead of having to mess up every program you write with a sleep or getchar. – Peter Cordes Apr 04 '22 at 01:38

1 Answers1

0

Thanks @RbMm, not sure how I had managed to use mov instead of sub. Oddly enough, I tried to run it via a VSCode task that simply called the executable through the shell - and that did end up printing my message to the console! For some reason this simply will not work unless the executable is called by a different shell.

In fact, I can also call it via PowerShell and get the output I want. And this is still the case regardless of if I reserve shadow space or skip initializing the CRT.

TLDR; Clicking the .exe does nothing, calling it via a shell works.