flat assembler
Message board for the users of flat assembler.

Index > Windows > [Help] Proc, without stack frame?

Author
Thread Post new topic Reply to topic
bobsobol



Joined: 31 May 2010
Posts: 18
Location: U.K.
bobsobol 05 Jul 2010, 05:50
If I code
Code:
section '.text' code readable executable
align 4
proc WinMain, hCurrInstance,hPrevInstance,lpCmdLine,nCmdShow,ShowState
  ret
endp    


Then I look at my executable, that isn't translated as an entry point with a ret, but as
Code:
WinMain:  ; INT Game.WinMain(guessed hCurrInstance,hPrevInstance,CmdLine,ShowState)
push ebp
mov ebp,esp
leave
ret 14h    
Okay... I don't want to push ebp on the stack, or load the stack pointer into it, so my only hope is to then code a pointless
Code:
pop ebp    
immediately after entry. I don't want it to "leave" and I asked it to "ret" not "ret 14h".

So why not use a label?
Code:
WinMain:
ret    
Well, because I would like to use labels local to that procedure, for jumps and loops and so on.

I'm sure it's documented somewhere. Most of my questions get a RTFM response, but I read the manual, I search the manual and find lots of key words and phrases that are absolutely nothing to do with my issue at all, so I guess I'm just not used to the writing style employed by the manual.

In short... is there a way I can gain local re-usable labels ".mainloop:" ".innerloop:" etc. (which I think the documentation says I can) and would like to refer to "ESP+4" as "hCurrInstance" etc. without using Proc, or am I better off redefining the "Proc" macro to operate without automatically creating frames? Can I (maybe) create a new "NoFrameProc" macro for when I want Procedures that don't mess with stack frames and local storage but do allow local labels that could mean something different outside of that Proc - Endp block?

I'm not an x86 noob, (I used TASM on DOS, and have been using a combination of the Assembler released separately from OllyDbg and GoASM) but I am *very* new to the FASM way, please excuse my ignorance. I am keen not to need completely unique labels across the entire project, but need to keep stack frames under my own strict control. I'm loving the GUI, and the ability to declare what goes in what section and what binary format to produce all in the source without making Make files and passing linker directives as parameters... but other things are not only new and exciting, but also strange and confusing to me. Sad

What's my best way to proceed? FASM Gurus, please help. :s
Post 05 Jul 2010, 05:50
View user's profile Send private message Reply with quote
Tyler



Joined: 19 Nov 2009
Posts: 1216
Location: NC, USA
Tyler 05 Jul 2010, 06:06
> is there a way I can gain local re-usable labels
Use a global label(w/o a '.') and every local label(w/ a '.') after it can be reused until you declare the next global label.

Example
Code:
glob:
.loc: ; glob.loc
jmp .loc ; jmp glob.loc

glob2:
.loc:
jmp .loc ; jmp glob2.loc
jmp glob.loc ; jumps to .loc if glob
    


As for controlling the stack frame, just use labels instead of procs and create it yourself.

I don't want to read all that, anymore ?s, just ask clearly Smile.
Post 05 Jul 2010, 06:06
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20486
Location: In your JS exploiting you and your system
revolution 05 Jul 2010, 07:42
You should be returning from WinMain with ret 0x14 to properly release the stack frame. But Windows will likely be lenient to the error anyway when you use retn instead, but it is bad practice really.

The fasm macros define ret to produce the proper retn XX code (as you saw). So if, for some reason, you don't want the frame return code (ret XX) then use retn instead.
Post 05 Jul 2010, 07:42
View user's profile Send private message Visit poster's website Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4624
Location: Argentina
LocoDelAssembly 05 Jul 2010, 15:56
But is this a PE or a MS COFF source? If it is a PE then those parameters are pretty much invalid, the entry point has nothing. If it is a MS COFF you'll need to link to some library that calls your WinMain because if it is the executable entry point then you're in the same trouble again.

[edit]For "proc" documentation and related stuff check here: http://flatassembler.net/docs.php?article=win32 [/edit]
Post 05 Jul 2010, 15:56
View user's profile Send private message Reply with quote
bobsobol



Joined: 31 May 2010
Posts: 18
Location: U.K.
bobsobol 05 Jul 2010, 22:40
It is a PE... but it is not the entry point.

It's attempting to create a source listing (in assembler) for a program written in Visual C++ 6.

The code produced by VC6 doesn't produce a stack frame for the WinMain() routine, but does pass the normal parameters to it, as my example code follows. Much of the VC6 entry point is pretty useless, checking to see what CPU the PE is designed for in x86 32-bit code etc... when clearly the PE wouldn't have been executed if it wasn't running on an x86 32-bit compatible CPU. It also sets up a Structured Exception Handler, which I have coded an equivalent for, creates some heap storage etc.

But crucially, WinMain() doesn't create a separate stack frame, so LEAVEing and releasing it on return is not an issue. The WinMain() compiled by VC6, returns with a simple RET (or RETN, as in a flat file all returns are near XD)

Special thanks to Tyler, that helps a lot... but can I define names of the parameters passed on the stack with a label alone? (hCurrInstance, hPrevInstance, lpCmdLine, nCmdShow, ShowState) Or does that simply become too difficult for the Assembler (compiler) to keep track of when they are part of the active stack, and not part of the original frame passed to the procedure?
Post 05 Jul 2010, 22:40
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4624
Location: Argentina
LocoDelAssembly 05 Jul 2010, 23:48
You could dump proc and do this instead:
Code:
WinMain:
virtual at esp+4
  .hCurrInstance dd ?
  .hPrevInstance dd ?
  .lpCmdLine dd ?
  .nCmdShow dd ?
  .ShowState dd ?
end virtual

; The following instruction is just an example:
  mov eax, [.hCurrInstance]

ret    
Doing that however has the problem that every time you do something that affects ESP will make the labels offsets invalid and you'll have to compensate for that (for instance, "mov eax, [.hCurrInstance+delta]").

For returning with a simple "ret" you should do this:
Code:
proc WinMain c, hCurrInstance,hPrevInstance,lpCmdLine,nCmdShow,ShowState ; Notice the "c" after WinMain
  ret
endp    
But that won't prevent the PUSH EBP/MOV EBP, ESP prolog nor the LEAVE epilog because "proc" macro always uses EBP to take advantage of its invariability* in the execution of the body.

*Provided the programmer does not violates that assumption of course but with ESP it is impossible to hold if there are PUSH sequences.
Post 05 Jul 2010, 23:48
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8363
Location: Kraków, Poland
Tomasz Grysztar 06 Jul 2010, 09:12
LocoDelAssembly wrote:
But that won't prevent the PUSH EBP/MOV EBP, ESP prolog nor the LEAVE epilog because "proc" macro always uses EBP to take advantage of its invariability* in the execution of the body.

It is better to say, that it is the default prologue/epilogue set of macros that always uses EBP. You can still use some other setting and make "proc" macro work with completely different strategy.
See this thread for details: http://board.flatassembler.net/topic.php?t=10518
Post 06 Jul 2010, 09:12
View user's profile Send private message Visit poster's website Reply with quote
bobsobol



Joined: 31 May 2010
Posts: 18
Location: U.K.
bobsobol 07 Jul 2010, 03:20
Both excellent answers. Thank you LocoDelAssembly & Tomasz.

FASMs Macro capabilities are considerably more complex than I am used to in a Macro Assembler, and I guess that's part of why it's often referred to as a compiler. Yet it does still give me the native x86 feel, which I loose if I go as far as HLA. It will take me some time (I think) to understand the complete ins-and-outs of the default Proc Macro, and define one that suites my purposes. But it's clear to me that that is possible.

For now, I think I'll go with the label, and .label methods, and see how often I can make use of the "virtual - end virtual" syntax to improve readability.

Or, maybe store ESP+4 on entry, (somewhere) and then keep constants (EQUates) for the offset against that? That should work and empower the reader. No?
Code:
WinMain: 
  .Arg dd ?
  .hCurrInstance EQU 0
  .hPrevInstance EQU 4
  .lpCmdLine EQU 8
  .nCmdShow EQU 12
  .ShowState EQU 16
  mov .Arg,ESP+4
  mov EAX, .Arg
  add EAX, .lpCmdLine
  push EAX                   ; Arg.lpCmdLine
  push lpMyString
  call [lstrcmp]
  jnz .Invalid
  jmp .Continue
.Invalid
  ret
.Continue
  ...
  ...    

It is enough, to know that something can be done to make these Macros (or ones like them) fit the conventions used the High Level build method. (Don't ask why that's important... Long story.)
Post 07 Jul 2010, 03:20
View user's profile Send private message Reply with quote
bitshifter



Joined: 04 Dec 2007
Posts: 796
Location: Massachusetts, USA
bitshifter 09 Jul 2010, 04:28
That code has lots of problems i dont care to mention...
But if you want to do it the hard way, then here you go...
Code:
format PE GUI 4.0
entry start

include 'win32a.inc'

section '.code' code readable executable

  start:
        push    SW_SHOWNORMAL           ; WinMain: nShow
        call    [GetCommandLine]
        push    eax                     ; WinMain: lpszArgs
        push    NULL                    ; WinMain: hPrev (always NULL on Win32)
        push    NULL                    ; GetModuleHandle: hModule
        call    [GetModuleHandle]
        push    eax                     ; WinMain: hInst
        call    WinMain
        push    eax                     ; ExitProcess: nExitCode
        call    [ExitProcess]

  ; INT WINAPI WinMain ( HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArgs, INT nShow )
  WinMain:

    label .hInst    dword at esp+4
    label .hPrev    dword at esp+8
    label .lpszArgs dword at esp+12
    label .nShow    dword at esp+16

        push    MB_OK                   ; MessageBox: dwStyle      (bumped esp 4)
        push    _caption                ; MessageBox: lpszCaption  (bumped esp 8)
        push    [.lpszArgs+8]           ; MessageBox: lpszMessage
        push    HWND_DESKTOP            ; MessageBox: hwndOwner
        call    [MessageBox]
        xor     eax,eax                 ; WinMain: Return value
        retn    16

section '.data' data readable writeable

  _caption db 'Command line args...',0

section '.idata' import data readable

  library kernel32,'KERNEL32.DLL',\
          user32,'USER32.DLL'

  include 'api\kernel32.inc'
  include 'api\user32.inc'
    

_________________
Coding a 3D game engine with fasm is like trying to eat an elephant,
you just have to keep focused and take it one 'byte' at a time.
Post 09 Jul 2010, 04:28
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.