-1

I'm now programming some Windows native assembly, using NASM 2.12.01 and GCC 4.8.1 as a linker.

However, this simple HelloWorld program compiles & links without any complaints, but doesn't output anything to console screen.

It seems that GetStdHandle doesn't return a valid handle to a current console, so the output doesn't get shown up.

But problem might be some other.

Code:

; Name:     hello.asm
; Assemble: nasm.exe -fwin32 hello.asm
; Link:     gcc -mwindows -o hello hello.obj -lkernel32 -lmsvcrt
; Run:      a.exe

BITS 32
extern _GetStdHandle@4
extern _WriteFile@20
extern _ExitProcess@4
extern __getch
extern _puts

SECTION .data
    str:    db `Hello world!\n`         ; C-like strings in NASM with backticks
    strlen  equ $-str
    pause:  db "Do you know where the ANY key is? :-)",0

SECTION .text
GLOBAL _main
_main:
; Stack frame for NumberOfBytesWritten
push ebp
sub esp, 4

; http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231.aspx
; HANDLE WINAPI GetStdHandle(
;   _In_  DWORD nStdHandle
; );
push -11
call _GetStdHandle@4

; http://msdn.microsoft.com/en-us/library/windows/desktop/aa365747.aspx
; BOOL WINAPI WriteFile(
;   _In_         HANDLE hFile,
;   _In_         LPCVOID lpBuffer,
;   _In_         DWORD nNumberOfBytesToWrite,
;   _Out_opt_    LPDWORD lpNumberOfBytesWritten,
;   _Inout_opt_  LPOVERLAPPED lpOverlapped
; );
push 0              ; lpOverlapped,
lea ebx, [ebp-4]    ; EBX: address of NumberOfBytesWritten
push ebx            ; lpNumberOfBytesWritten,
push strlen         ; nNumberOfBytesToWrite
push str            ; lpBuffer,
push eax            ; hFile (result from GetStdHandle
call _WriteFile@20

; msvcrt.dll (C library)
push pause
call _puts          ; http://msdn.microsoft.com/library/tf52y4t1.aspx
add esp, 4
call __getch        ; http://msdn.microsoft.com/library/078sfkak.aspx

; ExitProcess (0)
push 0
call _ExitProcess@4
hakeris1010
  • 285
  • 1
  • 5
  • 12
  • *"But problem might be some other."* - Why not implement error handling if only to stop guessing? – IInspectable Oct 12 '16 at 16:46
  • @IInspectable And how exactly would you implement it in a hello world ASM program? – hakeris1010 Oct 12 '16 at 17:01
  • Is there a Windows tool that can trace all the system calls a process makes? In Linux/Unix, `strace` is great for debugging things like this. (See [example output in this random blog post](http://www.thegeekstuff.com/2011/11/strace-examples)). – Peter Cordes Oct 12 '16 at 17:09
  • The same way as you do it in any other Windows application. By following the documented contract and evaluating return values. – IInspectable Oct 12 '16 at 17:09
  • 1
    @IInspectable: If you're just learning asm, you're more likely to create *more* bugs by clobbering a register or unbalancing the stack while writing the error-handling code. I'd recommend using a debugger or tracing tool to look at API-call return values while single-stepping, instead of trying to write code in the program to check them. You can't just insert a debug-print into an asm program without potentially introducing new bugs. (unless you have a very elaborate macro that saves/restores everything, including flags). – Peter Cordes Oct 12 '16 at 17:11
  • @PeterCordes: Error checking is really no more involved than `or eax, eax` followed by a `jz Terminate`. Hard to get that wrong. Of course that's useless without a debugger. But I was assuming, that if you want to learn, you are using *the* most important tool at your disposal. – IInspectable Oct 12 '16 at 17:14
  • @IInspectable: In 64-bit code, that truncates RAX to 32-bit (because you used `or` when you should have used `test`). So it's certainly possible to get stuff wrong. I totally agree you need to use a debugger, though, and that's what I was saying the whole time. – Peter Cordes Oct 12 '16 at 17:42
  • @PeterCordes: That may be true for 64-bit code. The code in the question, however, contains `BITS 32`, so the error handling is really as simple as I outlined. Of course, if you wanted to get fancy, you could simply push an error code (unique for each API call), and jump to the `ExitProcess` call. That way you wouldn't even need a debugger to find out, which API call failed. – IInspectable Oct 12 '16 at 19:04

2 Answers2

1

In order to generate a console application, you must use the -mconsole option to GCC. See the online documentation, section 3.18.55, x86 Windows Options.

You're using -mwindows which creates a GUI application. Windows does not create a console or set the standard handles when launching GUI applications.

Harry Johnston
  • 35,639
  • 6
  • 68
  • 158
0

You never set up the stack frame correctly!

This is not the proper way:

push ebp
sub esp, 4

Are you missing something? Your stack is messed up!

The prolouge should be :

push ebp
  mov   ebp, esp
  sub   esp, 4 

For the epilouge, just reverse that.

Gunner
  • 5,780
  • 2
  • 25
  • 40
  • There is no requirement to set the base pointer to any particular value. It is purely a convenience, to more easily access locals as well as arguments. In fact, omitting the frame pointer is one of the very common optimizations for any high level language compiler. I'm sorry, but this does not answer the question (I don't know who up-voted this or why). – IInspectable Oct 12 '16 at 18:17