Author Topic: Using NASMX generates invalid executable  (Read 5534 times)

Offline aVoX

  • Jr. Member
  • *
  • Posts: 13
Using NASMX generates invalid executable
« on: September 13, 2013, 09:50:40 PM »
Hi!

This is the first time i try NASMX, so I tried to write the smallest program possible:
Code: [Select]
%include "inc\nasmx.inc"
%include "inc\win32\windows.inc"
%include "inc\win32\kernel32.inc"
%include "inc\win32\user32.inc"

[section .text]
proc WinMain,   ptrdiff_t hInstance,        \
                ptrdiff_t hPrevInstance,    \
                ptrdiff_t lpCmdLine,        \
                dword     nCmdShow
locals none
    NOP
endproc

ENTRY example
proc example,    dword     arg_count,        \
                ptrdiff_t arg_var
locals none

    invoke  GetModuleHandleA, NULL
    invoke  WinMain, eax, NULL, NULL, SW_SHOWNORMAL
    invoke  ExitProcess, 0

endproc

After building using this script:
Code: [Select]
@echo off
nasm.exe -o example.obj -f win32 -Ox example.asm

if errorlevel 1 goto err_asm

golink.exe /mix /console /entry example /fo example.exe example.obj kernel32.dll user32.dll

if errorlevel 1 goto err_link

echo Build succeeded
goto end

:err_asm
echo An assembly error occured!
echo.
pause
goto end

:err_link
echo An error occured while linking!
echo.
pause
goto end

:end
I get an executable, as expected. But when I try to run it, Windows tells me "example.exe is not a valid Win32 application."

How am I using NASMX wrong in not even 30 lines of code?
Thanks in advance!
« Last Edit: September 13, 2013, 10:12:00 PM by aVoX »

Offline Rob Neff

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 430
  • Country: us
Re: Using NASMX generates invalid executable
« Reply #1 on: September 14, 2013, 01:02:14 AM »
You have linkage issues, not necessarily NASMX issues.

Change the linker line in your script from this:

Code: [Select]
golink.exe /mix /console /entry example /fo example.exe example.obj kernel32.dll user32.dll

to this:

Code: [Select]
golink.exe /entry _main /fo example.exe example.obj kernel32.dll user32.dll

One thing that the ENTRY macro does is help ensure the correct starting point for your program regardless of OS.  For Windows this becomes "_main" ( on Linux it is just "main" without the underscore prefix ).   It's just one of those things you must always do.  We can't automate this in build scripts you write.

Unfortunately Jeremy's http://www.godevtool.com website is currently down so I can't refer you to the documentation on the /mix command line argument which is also causing you issues.  That command line argument won't become necessary until you start "mixing" Win32 with C calls ( eg: different name mangling schemes ).

The GoLink /console arg is OK if you're about to build a console-only app.  This helps the linker in not pulling in the graphic library stuff.  Just stick with the linker line I provided above until you need further help.  :)

Offline aVoX

  • Jr. Member
  • *
  • Posts: 13
Re: Using NASMX generates invalid executable
« Reply #2 on: September 14, 2013, 09:29:20 AM »
Hey Rob, thanks a lot for your input!
I played around a lot with my build script in the meantime, (incuding toggling /mix and /console switches), but nothing changed. Now I exchanged /entry example for /entry _main and removed /mix, but still, the error message stays the same (the output executable, or at least its size, also stays exactly the same, the linker always creates a file of 1,536 bytes). I also tried to re-use a build script from NASMX' "demos" directory, again with the same result. For these reasons I believed, that it must be a problem with NASMX.
Wrong. I just linked everything using MSVC's LINK utility, which produces a slightly larger, but at least working executable (not cool, I want to use distributable freeware). So, any ideas on that?

By the way, I actually want to mix STDCALLs (for Win32 stuff) and CDECLs (for the functions in my own program), at least this is what I am used to, coming from a C world. (Or is there a good reason not to use CDECL everywhere possible?)

About the /console switch - for debugging reasons I want a console I can dump my debug info in, when everything is in a state I am satisfied with, I am going to remove the console (in which case the code stays the same, but the build scripts /console switch has to go, if I understand correctly)

Thanks, and bye.

Edit:
Now I programmed a small MessageBox program manually, not using NASMX, with the same build script and it worked. Another case where it looks like the usage of NASMX destroys the executable, even though I know now, that's not the case. Strange stuff going on...

Edit 2:
Sorry for swearing, but what the f*** is going on? Now I put something I don't even reference into the data section and it works like expected.
« Last Edit: September 14, 2013, 09:38:02 AM by aVoX »

Offline Rob Neff

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 430
  • Country: us
Re: Using NASMX generates invalid executable
« Reply #3 on: September 14, 2013, 09:08:18 PM »
Hey Rob, thanks a lot for your input!
I played around a lot with my build script in the meantime, (incuding toggling /mix and /console switches), but nothing changed. Now I exchanged /entry example for /entry _main and removed /mix, but still, the error message stays the same (the output executable, or at least its size, also stays exactly the same, the linker always creates a file of 1,536 bytes). I also tried to re-use a build script from NASMX' "demos" directory, again with the same result. For these reasons I believed, that it must be a problem with NASMX.
Wrong. I just linked everything using MSVC's LINK utility, which produces a slightly larger, but at least working executable (not cool, I want to use distributable freeware). So, any ideas on that?

Edit 2:
Sorry for swearing, but what the f*** is going on? Now I put something I don't even reference into the data section and it works like expected.

Can you attach the source and build script you used that led up to your EDIT#2 issue?  I would like to see for myself what is going on.  It definitely sounds like linker issues to me, possibly segment related, given that LINK worked but GoLink did not.  I've noticed all our demos include at least a .data and/or .bss section.  Or perhaps GoLink just doesn't like you!  ;D

By the way, I actually want to mix STDCALLs (for Win32 stuff) and CDECLs (for the functions in my own program), at least this is what I am used to, coming from a C world. (Or is there a good reason not to use CDECL everywhere possible?)

Programming Win32 assembly can be a pain but you can indeed mix STDCALL and CDECL within the same program using NASMX.  You simply need to ensure that you use the IMPORT, PROTO, and PROC macros properly so that function names are mangled and imported/exported properly.

Both conventions prepend an underscore to the function name.  STDCALL will append "@XX" to the function name where "XX" is the number of parameter bytes.  STDCALL also uses the Pascal function return convention ( eg: ret 8 ) where you don't need to "add esp, xxx" after each call to restore the stack like you do in CDECL.  Obviously you can never create a vararg function with STDCALL. 

NASMX, while not perfect, does its best to handle all that book-keeping stuff.  When you're calling your own functions use whatever convention gives you the smallest and/or fastest bits desired.

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2377
  • Country: us
Re: Using NASMX generates invalid executable
« Reply #4 on: September 15, 2013, 05:37:41 PM »
I've been doubtful from the start that NASMX could be the issue. NASMX is a macro set, it outputs code that Nasm will either assemble or barf on. If there were an error in NASMX, it might create incorrect code, but I don't see any reason that it should create incompatible code.

I suspect Rob's right that it's a linker issue. I recall that Nasm was accused of a "bug" wherein if we had a .bss section but no .data section, it would crash the loader (this was in Linux). Turned out that it was a certain version of ld - code from Gas did the same thing. An older or newer version of ld worked fine. Perhaps something similar here?

I can't run GoLink in Linux. I can, however run Alink (with some help from a poster Stewart(?) here - long ago - I got it to build on Linux). So I tried it. Avox's code as posted above... I had to flip the backslashes to forward slashes to get the includes to open, but otherwise left it alone. Got a couple of "unresolved external" errors. I remember hearing that we could create our own library by using the "import" directive and assembling as "-f obj". So I did so. I ASSumed that both were in kernel32.dll. This may not be correct. In any case, Alink produced an .exe. I have no idea if Windows will eat it or not. (I'm so stubborn I won't even run WINE!)  Can I attach an .exe? I'll try it... In general, I don't approve of downloading executables, but if anyone wants to try it - AT YOUR OWN RISK...

Edit: Okay, I can't attach an executable... so I zipped it up. Caution: unzips into current directory.

Best,
Frank

« Last Edit: September 15, 2013, 05:41:06 PM by Frank Kotler »

Offline aVoX

  • Jr. Member
  • *
  • Posts: 13
Re: Using NASMX generates invalid executable
« Reply #5 on: September 16, 2013, 05:03:35 PM »
Hey, I started coding all over in a new directory with empty files and I seem to be unable to reproduce the error without using /mix. I believe that the build script I talked about before did not get updated, when I saved (nearly impossible) or I edited a wrong build script from the beginning (also not very likely), however everything seems to be in order now.

Quote from: Frank Kotler
I've been doubtful from the start that NASMX could be the issue.
I've been too, but for reasons stated above (in my 1st post), it seemed almost obvious that the error is located within NASMX, and I ask to be excused about blaming NASMX ;D

Quote from: Frank Kotler
Alink produced an .exe. I have no idea if Windows will eat it or not.
No, it wouldn't, because Windows can't find _GetModuleHandleA@4 in kernel32.dll.

Anyways, thanks to all of you for your support, I'll head back if I happen to find something suspicious again.

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2377
  • Country: us
Re: Using NASMX generates invalid executable
« Reply #6 on: September 17, 2013, 04:30:37 PM »
I guess GeModuleHandle is in user32.dll(?). I knew I should have looked it up! Thanks for trying it and letting me know. Going back to Alink probably wouldn't be a good option anyway (no 64-bit support), but it's something I could try in Linux...

You're excused for blaming NASMX. The actual cause of the problem you encountered was - and is - confusing. If you discover what was doing it, let us know, but if it's working it's working!

Best,
Frank


Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: Using NASMX generates invalid executable
« Reply #7 on: October 18, 2013, 03:51:31 AM »
I can't run GoLink in Linux. I can, however run Alink (with some help from a poster Stewart(?) here - long ago - I got it to build on Linux). So I tried it. Avox's code as posted above... I had to flip the backslashes to forward slashes to get the includes to open, but otherwise left it alone. Got a couple of "unresolved external" errors. I remember hearing that we could create our own library by using the "import" directive and assembling as "-f obj". So I did so. I ASSumed that both were in kernel32.dll. This may not be correct. In any case, Alink produced an .exe. I have no idea if Windows will eat it or not.

I'm surprised you were able to get a working object file. NASMX does a lot of prep-work based on __OUTPUT_FORMAT__, but OMF/OBJ is not a format that NASMX has supported in many years. Last bit of OMF/OBJ support was in 2006 when it was dropped in favor of MS-COFF. While we're on the subject, around the same time I realized that DJGPP's LD doesn't work with NASMX (still doesn't) because it doesn't use MS-COFF, rather a custom COFF format.

(I'm so stubborn I won't even run WINE!)

You and me both brother. lol

About Bryant Keller
bkeller@about.me