Author Topic: Hello World Program In Windows/NASM  (Read 37892 times)

Offline RagingGrim

  • Jr. Member
  • *
  • Posts: 28
Hello World Program In Windows/NASM
« on: December 16, 2014, 05:21:07 PM »
I'm using a 64 bit version of Windows 7 ultimate.
I wrote a small batch script to make the assembling go a little smoother.
Code: [Select]

@echo off
color 0a
title NasmWrapper
cls
set /p Name="Enter A Project Name-> "
goto Compile
exit
:Compile
title Compiling
nasm -f win32 Projects\%Name%\%Name%.asm -o Projects\%Name%\%Name%.o
H:\MinGW\bin\ld Projects\%Name%\%Name%.o -o Projects\%Name%\%Name%.exe
echo Press Enter To Compile Again
echo Enter Exit To Quit
echo Enter Debug To Test.
set /p Choice=
if "%Choice%"=="Exit" (goto Exit)
if "%Choice%"=="Debug" (goto Debug)
goto Compile

:Debug
title Debugging
set %ErrorLevel% = "0"
start Projects\%Name%\%Name%.exe
echo Process Returned With Errorlevel : %ErrorLevel%
echo Press Enter To Test Again
echo Or Compile To Recompile
set /p Choice=
if "%Choice%"=="Exit" (
goto Exit)
if "%Choice%"=="Compile" (
goto Compile)
goto Debug

:Exit
cls
echo Closing...
pause

I tried this bit of code ( random guessing XD )
Code: [Select]
start:
JMP loop
ret 0

loop:
JMP loop

So it works fine. Opens the console and keeps it open and all. I know the ret call is never reached. I've been searching since last night and I just can't find any working examples of basic console program for windows using nasm. How do i output to the screen using the winapi? I understand i have to use the extern keyword followed by a function name and then with "ld" use the -l/*LibraryName*/ to use functions. I suppose it would be the same if I tried to use functions in the winapi.

I also had a nice little program I wrote in C that used nasm but I deleted that last night after I decided the trouble wasn't worth the reward.
I'm eager to learn. Please help ^^

Offline rkhb

  • Jr. Member
  • *
  • Posts: 7
  • Country: de
Re: Hello World Program In Windows/NASM
« Reply #1 on: December 16, 2014, 08:43:42 PM »
Please report trouble. I could test it only on WinXP.

Code: [Select]
; Name:     hello.asm
; Assemble: nasm.exe -fwin32 hello.asm
; Link:     ld hello.obj -emain -lkernel32 --enable-stdcall-fixup %SYSTEMROOT%\system32\kernel32.dll
; Run:      a.exe

BITS 32
extern _GetStdHandle
extern _WriteFile
extern _ExitProcess

SECTION .data
    str:    db "Hello world!"
    strlen  equ $-str

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

    ; 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

    ; ExitProcess (0)
    push 0
    call _ExitProcess

viele grüße
ralph

Offline RagingGrim

  • Jr. Member
  • *
  • Posts: 28
Re: Hello World Program In Windows/NASM
« Reply #2 on: December 16, 2014, 08:53:23 PM »
Thanks Ralph
The Errors I get are all undefined references to those functions.

Undefined reference to GetStdHandle,WriteFile and ExitProcess.

Sorry! Missed the link options :O
It works fine if i compile it with the additional params ^^
Could you maybe explain this to me? I get the general idea but i'd like to know more ^^

I had to insert this
Code: [Select]
JMP loop
ret 0

loop:
JMP loop

To get my program to pause :P there must be a better way?
« Last Edit: December 16, 2014, 09:00:15 PM by RagingGrim »

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Hello World Program In Windows/NASM
« Reply #3 on: December 16, 2014, 09:10:58 PM »
Hi RagingGrim,

Good to see you here! I saw your question at SO the other day, and was going to suggest that we might have some examples in the "Examples" section (duh!). Turns out that we don't have a simple console example. We should!

I haven't touched Windows since Win98, but digging through the dusty archives I came up with this. As I recall, it "worked", but it is not correct!
Code: [Select]
; nasm -f win32 hw32cons.asm
; link /entry:start /subsystem:console hw32cons.obj <wherever>\kernel32.lib

%define ExitProcess _ExitProcess@4
%define WriteFile _WriteFile@20

                global  _start

                extern  ExitProcess
                extern  WriteFile

                section .text
_start:

                push    dword 0
                push    dword num_chars
                push    dword MSGLEN
                push    dword msg
                push    dword -11
                call    WriteFile

exit_ok:        push    dword 0
exit:           call    ExitProcess

                section .data
num_chars       dd      0
msg             db      'Hello, Console.', 13, 10
MSGLEN          equ     $ - msg

I think the correct way to do it is:
Code: [Select]
; nasm -f win32 hw32cons.asm
; link /entry:start /subsystem:console hw32cons.obj <wherever>\kernel32.lib

%define ExitProcess _ExitProcess@4
%define GetStdHandle _GetStdHandle@4
%define WriteFile _WriteFile@20

                global  _start

                extern  ExitProcess
                extern GetStdHandle
                extern  WriteFile

                section .text
_start:

                push -11 ; defined as "STDIN" somewhere, no doubt
                call GetStdHandle
; should return our handle in eax
                push    dword 0
                push    dword num_chars
                push    dword MSGLEN
                push    dword msg
                push    eax
                call    WriteFile

exit_ok:        push    dword 0
exit:           call    ExitProcess

                section .data
num_chars       dd      0
msg             db      'Hello, Console.', 13, 10
MSGLEN          equ     $ - msg
That's untested, but I think it "should work".

I am unable to advise what the command line to ld should be. I think I got it to work (using Cygwin, not MinGW) by pointing it to a library I got from Hutch's "MASM32" package once...

The NASMX package - http://nasmx.sf.net - contains some macros and a lot of "%defines" and examples, but I don't think it has any actual libraries. It uses Golink rather than ld, and in that case we can just list the .dlls we need on the command line. Perhaps MinGW includes the libraries you need? (Might need to use the uppercase "-L/path/to/library" switch as well as the "-l thelib" switch?)

I apologize for not having a better answer for you. I'm pretty stubborn about "I don't use Windows anymore" (not even Wine). Maybe someone can provide a "known to work" example. Seems like a simple enough request...

Best,
Frank

Well, I see Ralph has posted a "better" example. Good luck!


Offline rkhb

  • Jr. Member
  • *
  • Posts: 7
  • Country: de
Re: Hello World Program In Windows/NASM
« Reply #4 on: December 16, 2014, 10:02:16 PM »
Could you maybe explain this to me? I get the general idea but i'd like to know more ^^

--enable-stdcall-fixup is a MinGW-Windows-issue. You can find an explanation in the official manual of ld: https://sourceware.org/binutils/docs/ld/Options.html#Options. Short: without that option you have to use _GetStdHandle@4, _WriteFile@20, _ExitProcess@4 and so on for every WinAPI function. I will show it in the following example.

-emain determines the procedure named main as entry point.

-lkernel32 forces LD to look for a library called libkernel32.a. There it can find further "hints" for calling the functions of kernel32.dll.

Quote
To get my program to pause :P there must be a better way?

There are many ways. I'll show you a way that uses the MS-C-library (msvcrt.dll):

Code: [Select]
; Name:     hello.asm
; Assemble: nasm.exe -fwin32 hello.asm
; Link:     ld hello.obj -emain -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

viele grüße
ralph
« Last Edit: December 16, 2014, 10:56:34 PM by rkhb »

Offline RagingGrim

  • Jr. Member
  • *
  • Posts: 28
Re: Hello World Program In Windows/NASM
« Reply #5 on: December 17, 2014, 05:45:15 AM »
Thanks for all the replies!

Would it be a good idea to play around with these functions in an easier language before i start using them in assembly? I have a C compiler and I'm comfortable with the language ^^

Code: [Select]
BITS 32
extern _GetStdHandle
extern _ExitProcess
extern _WriteFile
section .Text
GLOBAL main
main:
mov eax,3



ret 0

I was just messing around with trying to create a skeleton from memory so the mov eax,3 is just random. But it triggers my antivirus XD Is there any specific reason for that because mov eax,5 does not XD

Offline RagingGrim

  • Jr. Member
  • *
  • Posts: 28
Re: Hello World Program In Windows/NASM
« Reply #6 on: December 17, 2014, 03:17:00 PM »
I'm really into assembly ! I even got myself a book to make notes in XD
Not even C deserved a book...XD

So I was wondering what would happen if I repeatedly pop a register which is not on the stack. I tried this and my program crashed.
Then I tried pushing eax onto the stack before popping it and BAM - no crash.

My conclusion was that when you attempt to pop a register which is not currently on the program's stack your program will crash ( in a windows environment ). Would I be correct?

Offline Rob Neff

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 429
  • Country: us
Re: Hello World Program In Windows/NASM
« Reply #7 on: December 17, 2014, 03:44:44 PM »
So I was wondering what would happen if I repeatedly pop a register which is not on the stack. I tried this and my program crashed.
Then I tried pushing eax onto the stack before popping it and BAM - no crash.

My conclusion was that when you attempt to pop a register which is not currently on the program's stack your program will crash ( in a windows environment ). Would I be correct?

To understand the reason why your program crashed you need to understand the purpose and layout of the Call Stack

Once you have a firm grasp on that you should then study Calling Conventions



Offline RagingGrim

  • Jr. Member
  • *
  • Posts: 28
Re: Hello World Program In Windows/NASM
« Reply #8 on: December 17, 2014, 07:12:22 PM »
Once again thanks for all the replies I thought I'd just play around with calling kernel32 instructions. ^^ I went with beep as my victim :p

Code: [Select]
BITS 32
extern _Beep
global main
section .TEXT
main:
push 500
push 3000
call _Beep
add ebp,8 ;4*2
push 503
push 3003410
call _Beep
add ebp,8 ;4*2
ret

Code works fine and it beeps and all that. I was just curious ;After calling the beep function are those values removed from the stack? I read something about adding 4*NumberOfParams to the ebp register to clear the stack? Something like that?

Also if I do this:
Code: [Select]
BITS 32
extern _Beep
global main
section .TEXT
main:
push 500
push 3000
call _Beep
call _Beep
ret

The first beep would obviously execute fine but what about the second one ? My pc keeps beeping so I assume it's using values from memory that it shouldn't be using ? :O By not clearing the stack ? Is that why this happens?

Thanks!

Offline Rob Neff

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 429
  • Country: us
Re: Hello World Program In Windows/NASM
« Reply #9 on: December 17, 2014, 08:29:27 PM »
In your first example you are modifying the EBP register rather than the ESP register.  Normally, to remove values that you've pushed on the stack you would either POP the values off or "ADD ESP, XX" after the call where XX is the number of bytes pushed  prior to the call in order to keep the stack aligned and balanced.

However, for functions which are declared as StdCall in Windows you don't need to do anything after the call since the called function itself will restore the stack using the "ret XX" op-code.  This is why I recommend understanding calling conventions in order to know 1.) how the caller expects parameters to appear on the stack; and 2.) who's responsible for restoring the stack - the caller or the callee.
« Last Edit: December 17, 2014, 08:32:00 PM by Rob Neff »

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Hello World Program In Windows/NASM
« Reply #10 on: December 17, 2014, 10:51:48 PM »
Just a quicky, picky, comment besides what Rob has mentioned. "section .TEXT" - Nasm's keywords are generally case insensitive. You can say "section" or "SECTION" or "segment" or "SEGMENT" - all the same to Nasm. However, the "known names" - ".text", ".data", ".bss", etc. are case sensitive. In Windows output formats, "arbitrary names" are treated like ".text", so it won't do any harm. But "section .DATA" would also be treated like ".text" - that is, readonly. Since "section .data" is expected to be writable, this could cause a confusing error. Just thought I'd mention it...

Best,
Frank


Offline RagingGrim

  • Jr. Member
  • *
  • Posts: 28
Re: Hello World Program In Windows/NASM
« Reply #11 on: December 18, 2014, 06:51:20 AM »
Thanks Rob , I read the bit about the callee and the caller . I made a note about it under C Language Calling Convention ( I think I got it from a x86 Assembly Tutorial I found somewhere ) , I haven't memorised all of it just yet because I'm trying not to bore myself with all the theory just yet :P But I'll make a point of learning more theory everyday ^^

Thanks to you too Frank :P I don't understand what you said completely but maybe that's just my english. I'll read up more and look into the nasm manual as well. I guess I mean I get it..but I don't?
Thanks All!