1

I am using MASM in x64 Windows operating system. I wanted to call Windows APIs and then output some strings to the screen.

I am learning x64 assembly programming in Windows operating system. Today I wanted to print some result to the console. However, unlike linux operating system, in windows we can use syscalls directly without any pain. I've written the following program to print a hello world message to the console but it doesn't show anything. I couldn't figure out what is wrong with this code.


GetStdHandle PROTO
ExitProcess PROTO
WriteConsoleA PROTO

.data
    message         DB "Hello World",0
    message_size    DW SIZEOF message

.code
    main PROC
        SUB RSP, 5 * 8  
        
        MOV RCX, -11           
        CALL GetStdHandle

        MOV RCX, RAX     
        LEA RDX, message
        MOV R8, SIZEOF message - 1
        LEA R9, message_size  
        MOV  QWORD PTR [RSP + 4 * SIZEOF QWORD], 0
        CALL WriteConsoleA

        MOV RCX, 0      
        CALL ExitProcess
    main ENDP
END

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
Homayoon
  • 13
  • 3
  • Does this answer your question? [How to write hello world in assembly under Windows?](https://stackoverflow.com/questions/1023593/how-to-write-hello-world-in-assembly-under-windows) – Simon Mourier Jan 02 '23 at 16:43
  • Generally I write a C program and have Visual Studio produce assembly code so I can see the actual code used for the Windows API. – rcgldr Jan 02 '23 at 16:53
  • The code looks correct (including stack alignment, home space, and parameter usage). I have assembled and linked the code here and had it run correctly. What options did you pass to the assembler and linker to produce the program? – Michael Petch Jan 02 '23 at 16:58
  • 1
    @vitsoft `message_size` is a DWORD as parameter 4 is a pointer to that DWORD (LPDWORD) so at a minimum it should be changed to DD (DQ is extra). The 5th parameter which is on the stack is zeroed out with `MOV QWORD PTR [RSP + 4 * SIZEOF QWORD], 0` – Michael Petch Jan 02 '23 at 17:53
  • @MichaelPetch I think that `LEA R9, message_size` should load the 4th parameter with 64bit address pointing at 64bit memory variable, but it points at 16bit variable only. However, it might work anyway. – vitsoft Jan 02 '23 at 18:00
  • It is an LPDWORD so it is a pointer to a DWORD (32-bit value). The pointer is 64-bit but the data it points at should be at least 32-bits (DWORD). So a minimum would be DD, but DQ would work too but it is an extra 4 unneeded bytes. The `LEA` instruction is properly loading the 64-bit pointer into R9. While pointer sizes changed in 64-bit Windows to 64-bit, the width/size of a WORD&DWORD did not. – Michael Petch Jan 02 '23 at 18:04
  • 1
    probably main error really in not *CUI* subsystem. however much better use `EXTERN __imp_SomeAPI:QWORD` for function declaration, instead `SomeAPI PROTO`, `message` can be in `.CONST` section, and message_size must be local variable in stack. and of course need check result of api calls – RbMm Jan 02 '23 at 18:11
  • @RbMm : Yep that was my opinion as well, which is why I wanted to know which options they were using when running the linker. – Michael Petch Jan 02 '23 at 18:31
  • @MichaelPetch You're right, 64bit WriteConsole writes 32 bits only to the variable specified by 4th parameter, I just verified this in x64dbg. To make the program work, I had to **change segment name** from `.code` to `.text`. It seems that linker doesn;t grant .code segment with RX privilege. – vitsoft Jan 02 '23 at 18:37
  • @vitsoft - no, task not in segment name. and no in execute flag. `.CODE` is correct – RbMm Jan 02 '23 at 19:21

2 Answers2

1

Are you linking it as a console app? Windows distinguishes between console apps that write to stdout (which is what yours is doing) and GUI apps that create windows and run a message loop.

You need to specify /subsystem:console as a linker flag. There might be a MASM option/directive that does the same.

Seva Alekseyev
  • 59,826
  • 25
  • 160
  • 281
  • An aplication linked to graphic subsystem creates a new console. Nevertheless, in this case the console window is destroyed instantly when the program exits, usually before the user is able to read it. – vitsoft Jan 02 '23 at 17:47
  • 3
    @vitsoft *An aplication linked to graphic subsystem creates a new console.* only if code call `AllocConsole` and here no such call – RbMm Jan 02 '23 at 17:50
0

The code works fine after adding an assembler-language file to an existing Visual Studio C++ project, a console /SUBSYSTEM:CONSOLE X64 application. enter image description here

YangXiaoPo-MSFT
  • 1,589
  • 1
  • 4
  • 22