These two things are not quite the same.

One assembles and runs fine with NASM whereas the other crashes with an access violation.
What's the difference? Which one crashes?

Exhibit 1



section .bss

lpMsg: istruc MSG iend ;28 bytes
lpwc: istruc WNDCLASS iend ;40 bytes
pHwnd: resd 1
phInst: resd 1
lplpMsgBuf resd 1

..............................................................................................................
..
..

section .text

wininvoke CreateWindowExA, 0, lpszClassName, "Like My Window?", WS_OVERLAPPEDWINDOW |WS_VISIBLE, 0, 0, 640, 480, 0, 0, , 0





Exhibit 2




section .bss

lpMsg: istruc MSG iend ;28 bytes
lpwc: istruc WNDCLASS iend ;40 bytes
pHwnd: resd 1
lplpMsgBuf resd 1
phInst: resd 1
..............................................................................................................
..
..

section .text

wininvoke CreateWindowExA, 0, lpszClassName, "Like My Window?", WS_OVERLAPPEDWINDOW |WS_VISIBLE, 0, 0, 640, 480, 0, 0, , 0



(Note: For those who aren't used to NASM, all labels are automatically pointers. That explains both my naming convention and the manner in which I treat them. Wininvoke is a macro of my own creation that behaves a bit like MASM invoke)


You probably had to do a double take because the two aren't very different. The first one crashes as soon as it gets to the CreateWindowEx call whereas the other one runs without a hitch. The function seems to choke on the phInst variable. According to the debugger it attempted a read at fffffffffetc. The only difference is the order in which I reserve the bytes. phInst has changed places with lplpMsgBuf.

I am quite new to x86 ASM (but not to Win32 programming in general) and boy, have I been banging my head against a wall for days. I feel good to have found the problem but I still don't know WHY it happens. I shudder having my programs crash inexplicably just because a variable isn't at the "right" address. Could it be an alignment issue? I must admit, I am quite dumb when it comes to that.

Do you MASM and FASM users run into problems like this? I like NASM's paucity of keywords and directives as well as its consistent treatment of labels but if its hindering me I'll have to switch. Basically, I'm scared to start a substantial program becuase bugs like this are VERY tough to pin down. After all, there is nothing logically wrong with your program yet it crashes poof!

As usual your input is much appreciated. :)
Posted on 2002-09-13 17:24:59 by Thanatos
Thats very funny, but there must be something else happening. Whats the macro doing, it seems to be allowing inline strings :confused: .
Posted on 2002-09-13 18:28:50 by Eóin
Heh...NASM's fancy smancy preprocessor allows such wizardry..




;Call a stdcall Win32 API function, bypassing IAT stub

%imacro wininvoke 1-*
%rep %0-1
%rotate -1
%ifstr %1
private_macrO_pUsh_Str_1 %1
%else
push dword %1
%endif
%endrep
%rotate -1
extern __imp__%1
call [__imp__%1]
%endmacro



%macro private_macrO_pUsh_Str_1 1
[SECTION .rdata]
%%str_addr: db %1, 0
__SECT__
push dword %%str_addr
%endmacro



Basically wininvoke rotates the macro args to the right until it gets to the function name. Each rotation, it uses the %ifstr directive to test if the argument is a string literal. If it is, it calls the private macro which switches to the rdata section, defines a string with a unique macro-local label, goes back to the code section (the __SECT__ macro does that) and pushes the address of the string unto the stack. So to cut a long story short, the macro creates the appropriate entry in the data section for me. The side effect is that if you pass the same string n times it will get added to the data section n times. But that would be silly...heh.

Anyway....I did a version without the inline string to see if it had any effect at all and it didn't. The program crashed under the same conditions.




wininvoke CreateWindowExA, 0, lpszClassName, lpszWindowName,
WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 640, 480, 0, 0, [phInst], 0



This was the only change from the previous version. Even the string lpszWindowName was already defined in the data section even though I didn't use it.
Posted on 2002-09-13 20:09:05 by Thanatos
My guess is that somewhere lplpMsgBuf is being used as a message buffer. You end up clobbering phInst and any function using phInst fails.
Posted on 2002-09-13 22:17:55 by tenkey
I can attach the source if anyone wants to see it. It's nothing top secret.

Anyway, that suggestion sounds quite reasonable tenkey...I had to ponder it for a while. I don't think it's a problem though. lplpMsgBug is just a DWORD pointer that gets set to the address of a dynamically allocated byte array by the FormatMessage win32 API function. In case one of the api calls fail (gracefully), I use it to print out a (supposedly) useful error message.

So lplpMsgBuf only gets used if a previous win32 API function call fails. Furthermore, no memory sequentially beyond the pointer should be used because the memory is heap memory. I have to call LocalFree to get rid of it when I'm done. Given the scenario, It seems unlikely that overwriting phInst would be the problem. However, I'm not against being wrong. At least I'd have a reason for this really strange behaviour.
Posted on 2002-09-13 23:27:04 by Thanatos
I think I found the problem. The structure definitions must be doing something screwy under certain situations. istruc and iend and are implemented as macros and apparently my usage of them is incorrect. They are usually defined in the data section and all the members are usually filled out (with zeros if necessary). I figured that they could go in the bss section and it would result in the allocation of the right number of bytes. Apparently not.

This code works.




section .bss

lpMsg: resb MSG_size
lpwc: resb WNDCLASS_size
pHwnd: resd 1
phInst: resd 1
lplpMsgBuf resd 1



I'll be using it from now on.

NASM was designed to eliminate MASM's quirks but it sure has a few of its own. I still don't know exactly why flipping the order of phInst and lplpMsgBuf stopped the access violation but at least I know how to avoid something like that in the future.
Posted on 2002-09-14 00:48:33 by Thanatos