There's no rule against saying "Nasm is better"! :)
Seriously, examining differences between Masm and Nasm, and between MASM32 and NASMX might be enlightening. To start with, Masm has "invoke" and "proc" (and "if" and "while" and "switch/case"?) "built in". If you want to use those in Nasm (and you probably do... or will), you'd need to include a file with macros to handle it. If you stick to "real instructions", no need. I don't think you "need" those includes in Masm, either - they're a convenience.
Lets look at Hutch's "minimum.asm":
; #########################################################################
.386
.model flat, stdcall
option casemap :none ; case sensitive
; #########################################################################
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
; #########################################################################
.code
start:
jmp @F
szDlgTitle db "Minimum MASM",0
szMsg db " --- Assembler Pure and Simple --- ",0
@@:
push MB_OK
push offset szDlgTitle
push offset szMsg
push 0
call MessageBox
push 0
call ExitProcess
; --------------------------------------------------------
; The following are the same function calls using MASM
; "invoke" syntax. It is clearer code, it is type checked
; against a function prototype and it is less error prone.
; --------------------------------------------------------
; invoke MessageBox,0,ADDR szMsg,ADDR szDlgTitle,MB_OK
; invoke ExitProcess,0
end start
"windows.inc" is the big one. Starts by defining "TRUE" and "FALSE"... and a bazillion other "long names for small integers". Then it has a bunch of structure definitions. "user32.inc" and "kernel32.inc" seem to be mostly "PROTO"s - a feature Nasm does not have. They provide some error-checking, and probably avoid having to specify sizes of parameters(?). Nice to have, but not necessary.
Then comes the "includelib" directives. I initially thought that this caused "ml" to pass the library names to "link" on the command line - but that's not how it's done! Look at a disassembly (Agner Fog's "objconv") of the resulting .obj file:
; Disassembly of file: min.obj
; Fri Aug 7 15:38:21 2009
; Mode: 32 bits
; Syntax: YASM/NASM
; Instruction set: 80386
global _start
extern _ExitProcess@4 ; near
extern _MessageBoxA@16 ; near
@comp.id equ 000E1C83H ; 924803
SECTION .text align=4 execute ; section number 1, code
_start: ; Function begin
jmp ?_001 ; 0000 _ EB, 33
szDlgTitle:
; dec ebp ; 0002 _ 4D
db 4DH
; imul ebp, dword [esi+69H], 544044397 ; 0003 _ 69. 6E, 69, 206D756D
db 69H, 6EH, 69H, 6DH, 75H, 6DH, 20H
; dec ebp ; 000A _ 4D
db 4DH
; inc ecx ; 000B _ 41
db 41H
; push ebx ; 000C _ 53
db 53H
; dec ebp ; 000D _ 4D
db 4DH
; Error: Instruction out of phase with next label
; add byte [eax], ah ; 000E _ 00
db 00H
szMsg:; and byte [eax], ah ; 000F _ 20. 20
db 20H, 20H
; sub eax, 1092627757 ; 0011 _ 2D, 41202D2D
db 2DH, 2DH, 2DH, 20H, 41H
; jnc 8BH ; 0016 _ 73, 73
db 73H, 73H
; Note: Prefix bit or byte has no meaning in this context
; insd ; 0018 _ 65: 6D
db 65H, 6DH
; Note: SIB byte unnecessary here
; Note: Address has scale factor but no index register
; bound ebp, dword [ebp+72H] ; 001A _ 62. 6C 65, 72
db 62H, 6CH, 65H, 72H
; and byte [eax+75H], dl ; 001E _ 20. 50, 75
db 20H, 50H, 75H
; jc 88H ; 0021 _ 72, 65
db 72H, 65H
; and byte [ecx+6EH], ah ; 0023 _ 20. 61, 6E
db 20H, 61H, 6EH
; and byte [fs:ebx+69H], dl ; 0026 _ 64: 20. 53, 69
db 64H, 20H, 53H, 69H
; insd ; 002A _ 6D
db 6DH
; jo 99H ; 002B _ 70, 6C
db 70H, 6CH
; Note: Absolute memory address without relocation
; and byte [gs:20202D2DH], ch ; 002D _ 65: 20. 2D, 20202D2D
db 65H, 20H, 2DH, 2DH, 2DH, 20H, 20H
; Error: Instruction out of phase with next label
; Note: Zero displacement could be omitted
; add byte [edx], ch ; 0034 _ 00
db 00H
?_001: push 0 ; 0035 _ 6A, 00
push szDlgTitle ; 0037 _ 68, 00000000(d)
push szMsg ; 003C _ 68, 00000000(d)
push 0 ; 0041 _ 6A, 00
call _MessageBoxA@16 ; 0043 _ E8, 00000000(rel)
push 0 ; 0048 _ 6A, 00
; Note: Function does not end with ret or jmp
call _ExitProcess@4 ; 004A _ E8, 00000000(rel)
; _start End of function
SECTION .data align=4 noexecute ; section number 2, data
resb 79 ; 0000 _
SECTION .drectve align=1 noexecute ; section number 3, const
db 2DH, 64H, 65H, 66H, 61H, 75H, 6CH, 74H ; 0000 _ -default
db 6CH, 69H, 62H, 3AH, 5CH, 6DH, 61H, 73H ; 0008 _ lib:\mas
db 6DH, 33H, 32H, 5CH, 6CH, 69H, 62H, 5CH ; 0010 _ m32\lib\
db 75H, 73H, 65H, 72H, 33H, 32H, 2EH, 6CH ; 0018 _ user32.l
db 69H, 62H, 20H, 2DH, 64H, 65H, 66H, 61H ; 0020 _ ib -defa
db 75H, 6CH, 74H, 6CH, 69H, 62H, 3AH, 5CH ; 0028 _ ultlib:\
db 6DH, 61H, 73H, 6DH, 33H, 32H, 5CH, 6CH ; 0030 _ masm32\l
db 69H, 62H, 5CH, 6BH, 65H, 72H, 6EH, 65H ; 0038 _ ib\kerne
db 6CH, 33H, 32H, 2EH, 6CH, 69H, 62H, 20H ; 0040 _ l32.lib
db 2DH, 65H, 6EH, 74H, 72H, 79H, 3AH, 73H ; 0048 _ -entry:s
db 74H, 61H, 72H, 74H, 20H ; 0050 _ tart
Nasm doesn't have "includelib", but we can do:
section .drectve
db "-defaultlib:blablabla"
So an "includelib" macro would probably be possible in Nasm. I don't know what, if any, linkers besides MS's would honor the ".drectve" section. Pretty neat trick!
Also notice that the .obj file uses the "true names" - "_MessageBoxA@16" (I remembered right!) and "_ExitProcess@4". I expected these to be defined in one of the include files, but the .lib files seem to be the only place these show up. Dunno how that works. "__imp__MessageBoxA@16" also appears in the .lib files. Cygwin's lib/win32api/libuser32.a does *not* appear to be the same thing. :(
I was going to post "DEMO1" from the predecessor to NASMX, NASM32, for comparison. But it's quite a different system. It uses "-f obj", which accepts the "import" directive, which gets us around having to use libraries. The "import" directive is hidden away in the "invoke" macro, so we don't see it and it "just works". Knowing which API is in which .dll - which "import" needs - is handled in the other include files, looks like. "TRUE", "FALSE", etc. and the structure definitions are in "windows.inc", similar to MASM32.
This is a fine system for "-f obj", but "-f win32" would be the more "modern" output format. I don't know what, if any, difference there is in the resulting executable, but... we wanna use "-f win32"!
I think the new NASMX has gone to "-f win32"... and "-f win64" probably. Some self-extracting executables can be extracted under Linux, apparently, but I haven't found the trick to extracting this one.
I say "-f win32" is more modern, but I have an ancient "package" that uses it:
http://home.comcast.net/~fbkotler/win32nasmbase.zipLooking again at this, that's pretty useless. That's not the "good" version of the file. I guess it's the "legal" version - missing the /bin directory, which includes "link.exe" (along with a really old version of Nasm!), and the /lib directory - which is what makes the whole thing go! (looks like it uses the .drectve trick) If you've got MASM32... I think it's the same thing...
Mingw ld ought to work, as well as gcc. The "-L" switch you have to give gcc (if you're using a makefile - that's really strange!) may be a partial clue. That gives you "printf, etc.", right? Libraries for the Windows API may be somewhere around there. I dunno.
Best,
Frank