While pushing the address of variables relative to stack, the assembler uses the lea instruction destroying the content of eax :
lea eax,var
push eax
Inspired by GoAsm's method, I wrote a simple macro and modified my custom invoke macro to preserve eax while pushing the addresses to the stack :
push ebp
sub DWORD PTR [esp],offset_to_ebp
The @p macro calculates the offsets and this information is used by the custom invoke macro to pass the adress :
WinMain PROC hInst:DWORD,hPrevInst:DWORD,CmdLine:DWORD,CmdShow:DWORD
lcounter=0
LOCAL @p(wc,WNDCLASSEX) : WNDCLASSEX
LOCAL @p(msg,MSG) : MSG
LOCAL @p(hwnd,DWORD) : DWORD
@p MACRO _name,_type
lcounter=lcounter+SIZEOF(_type)
@CatStr(<bytes>,<_name>) = lcounter
EXITM <_name>
ENDM
Interesting idea :t
00401095 ³. 55 push ebp
00401096 ³. 832C24 30 sub dword ptr [esp], 30 ; ÚpWndclassex => offset LOCAL.12
0040109A ³. E8 B8000000 call <jmp.&USER32.RegisterClassExA> ; ÀUSER32.RegisterClassExA
:t
@p MACRO _name,_type
lcounter=lcounter+SIZEOF(_type)
@CatStr(<bytes>,<_name>) = lcounter
EXITM <_name : _type >
ENDM
...
LOCAL @p(wc,WNDCLASSEX) : WNDCLASSEX
Maybe better
include \masm32\include\masm32rt.inc ; plain Masm32
include local.mac
.code
somecode proc argText, argTitle, argMode
Local_ rc:RECT, buffer[8]:BYTE, L1:DWORD, @ ; last arg marks end of locals
mov L1, 12345678h
mov rc.left, 11111111h
mov rc.top, 22222222h
mov rc.right, 33333333h
mov rc.bottom, 44444444h
; int 3
invoke_ lstrcpy, addr buffer, argText
print hex$(L1), "h is the DWORD var", 13, 10
print hex$(rc.left), "h is rc.left", 13, 10
print hex$(rc.top), "h is rc.top", 13, 10
print hex$(rc.right), "h is rc.right", 13, 10
print hex$(rc.bottom), "h is rc.bottom", 13, 10
invoke_ MessageBox, 0, addr buffer, argTitle, argMode
ret_
somecode endp
start:
print "let's do a little test", 13, 10
invoke_ somecode, chr$("text567"), chr$("title"), MB_OK
inkey "we are done here"
exit
end start
00401029 ³. CC int3
0040102A ³. FF75 08 push dword ptr [ebp+8] ; ÚSrc = "text567"
0040102D ³. 55 push ebp ; ³
0040102E ³. 830424 E8 add dword ptr [esp], -18 ; ³Dest => offset LOCAL.6
00401032 ³. E8 11020000 call <jmp.&kernel32.lstrcpyA> ; ÀKERNEL32.lstrcpy
Tested with MASM 6.14 and some others ;)
Hi mabdelouahab,
Thanks for the modification. It looks like that I missed that notation.
Hi Jochen,
Nice work. Me too, I have a custom version of the LOCAL statement.
Hi
@habran/johnsa: is there a way to get the offsets of local vars from ebp or another address, like the proc entry point?
Regards, Biterider
Hi,
I don't believe so, we would need to implement some sort of operator for it, which isn't a bad idea.. perhaps something like:
myProc PROC
LOCAL aVar:DWORD
mov eax,STACKOFS(aVar) ; if stackbase=ebp this is the offset relative to ebp post prologue, else esp.
mov eax,[ebp+eax]
mov eax,[ebp+STACKOFS(aVar)]
...
Hi
Yes, I like the idea. I would suggest FRAMEOFS or LOCALOFS or something similar.
Biterider
www.terraspace.co.uk/uasm242.zip (http://www.terraspace.co.uk/uasm242.zip)
supporting FRAMEOFS operator. Can be used as follows in 32bit and 64bit :
main proc c aParam:dword
local dwWritten:dword
local hConsole:dword
mov eax,FRAMEOFS(dwWritten)
mov eax,[ebp+FRAMEOFS(hConsole)]
;for comparison
mov eax,hConsole
mov ebx,dwWritten
mov eax,FRAMEOFS(aParam)
mov eax,aParam
Hi johnsa,
Thanks for the FRAMEOFS operator. It works fine with my custom invoke macro :
IF ((OPATTR(@SubStr(%arg,5+1))) EQ 98) OR ((OPATTR(@SubStr(%arg,5+1))) EQ 34)
add DWORD PTR [esp],FRAMEOFS(@SubStr(%arg,5+1))
Hi John
I tested FRAMEOFS with a standard prologue & epilogue and all work well.
In case of an non existing FRAME and you want to access hte proc parameters using esp, you have to decrement the offset by 4.
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
TestProc proc dArg1:DWORD, dArg2:DWORD
mov eax, [esp + FRAMEOFS(dArg1)-4]
mov edx, [esp + FRAMEOFS(dArg2)-4]
ret
TestProc endp
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
Regards, Biterider
Please test again..
www.terraspace.co.uk/uasm242.zip (http://www.terraspace.co.uk/uasm242.zip)
Hi John
Now I have to add 4 --> [esp + FRAMEOFS(Arg) + 4]
Attached the test file.
Biterider
Hi,
Try again.. same URL for download.
The problem actually wasn't the FRAMEOFS but a bug in the proc handling itself. When FPO is on or there is no prologue, there should be no stack frame setup.. but the parameters were still using ebp/rbp instead of esp to reference. that is fixed and this now works 100%:
include c:\masm32\include\masm32rt.inc
.code ;Begin Code segment
TestProc1 proto :DWORD, :DWORD
TestProc2 proto :DWORD, :DWORD
TestProc1 proc dArg1:DWORD, dArg2:DWORD
local dLoc1:DWORD
local dLoc2:DWORD
mov dLoc1, 100h
mov dLoc2, 200h
mov eax, dArg1
mov edx, dArg2
mov eax, [ebp + FRAMEOFS(dArg1)]
mov edx, [ebp + FRAMEOFS(dArg2)]
mov eax, [ebp + FRAMEOFS(dLoc1)]
mov edx, [ebp + FRAMEOFS(dLoc2)]
ret
TestProc1 endp
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
TestProc2 proc dArg1:DWORD, dArg2:DWORD
mov eax, [esp + FRAMEOFS(dArg1)]
mov edx, [esp + FRAMEOFS(dArg2)]
mov eax, dArg1
mov edx, dArg2
ret
TestProc2 endp
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
start: ;Program entry point
invoke TestProc1, 1, 2
invoke TestProc2, 3, 4
invoke ExitProcess, 0 ;Exit program returning 0 to Windows OS
end start ;End of code and define the program entry point
I added a few extra regular movs just to check offsets/stack locations and values.
Hi John
Perfect. No extra add/sub needed anymore! :t
Biterider