It is possible to write a Windows program using "just" Nasm. You have to create the necessary headers "by hand". NaGoA has some macros to simplify it. Much more practical is to use Nasm plus a linker. Unfortunately, linkers differ, and I don't know much about 'em. Jeremy Gordon's "Golink" seems to be the popular one, these days. Long ago, I used to use Nasm's "-f obj" output mode, and Alink... with mixed success... This is an obsolete way to make a Windows file!
; nasm -f obj hwcons.asm
;%define WriteFile _WriteFile@20
extern WriteFile
import WriteFile kernel32.dll
;%define ExitProcess _ExitProcess@4
extern ExitProcess
import ExitProcess kernel32.dll
section _TEXT use32 class=CODE
..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 use32 class=DATA
num_chars dd 0
msg db 'Hello, Console.', 13, 10
MSGLEN equ $ - msg
That used to work, but is incorrect! This is an untested(!) attempt to correct it:
; nasm -f obj hwcons.asm
; alink -oPE hwcons.obj ? may need "-subsys:console" or something?
extern WriteFile
import WriteFile kernel32.dll
extern GetStdHandle
import GetStdHandle kernel32.dll ; ?
extern ExitProcess
import ExitProcess kernel32.dll
section _TEXT use32 class=CODE
..start
push -11
call [GetStdHandle]
mov [hstdout], eax
push dword 0
push dword num_chars
push dword MSGLEN
push dword msg
push dword [hstdout]
call [WriteFile]
exit_ok:
push dword 0
exit:
call [ExitProcess]
section _DATA use32 class=DATA
num_chars dd 0
hstdout dd 0
msg db 'Hello, Console.', 13, 10
MSGLEN equ $ - msg
I would suggest that you figure out how to do this with "-f win32" output, if you can! "import" is known to Nasm only in "-f obj" mode. There's an "import" macro in the NASMX package - I don't think it's quite the same(?). Note that this uses "call [SomeAPI]" - in most cases, "call SomeAPI" will be correct, but this particular "style" needs the square brackets.
As Christian says, DJGPP is for 32-bit extended dos, not for Windows. You may want the "MinGW" package. It includes a port of gcc - which you probably don't want - and a port of ld, which you might want. As I recall, I never figured out where they put the libraries, but I had some success linking against "win32.lib" from Hutch's MASM32 package.
If you want to get "lower level" than "call SomeAPI", forget about Windows or any other "protected" OS - they're "protected" against US! Dos is okay - kind of a lame OS, but a very full-featured second-stage loader!
Dos under Windows is "fake dos", and is somewhat limited in what you can do (but pretty close). Real real-mode dos is "wide open". Linux allows us to interface with the kernel with "int 80h" - which may seem a little "lower level", but really isn't - there's always a "black box" at the end of the line! With Windows, you don't have much choice but "call SomeAPI". (consult MicroSoft for the APIs and how to use 'em)
The NASMX package includes examples, but IMHO too much is "hidden" behind macros. Maybe it'll satisfy you - doesn't satisfy me. Great for "production code", not as good for learning what goes on under the hood. "push, push, push, call SomeAPI" gets old pretty quick... but "invoke" isn't a CPU instruction! Just my opinion...
Best,
Frank