PureBasic Forum
https://www.purebasic.fr/english/

how to push local variables onto the stack?
https://www.purebasic.fr/english/viewtopic.php?f=35&t=62688
Page 1 of 2

Author:  Keya [ Fri Jul 31, 2015 5:52 pm ]
Post subject:  how to push local variables onto the stack?

I just found out that we cant push local variables :(
The helpfile says:
Quote:
Local variables in PureBasic are directly indexed by the stack pointer, which means if the stack pointer change via an ASM instruction (like PUSH, POP etc..) the variable index will be wrong and direct variable reference won't work anymore.

But it doesn't give any suggestions or workarounds

I hope you won't tell me i have to use a debugger and manually fiddle around with "p.v_var+4", "p.v_var+8" etc trying to get the stack alignment correct as that is a really ugly laborious slow and errorprone way, and i thought that is job for the compiler not programmer so i hope Purebasic has a practical solution :). Or if we cant use local variables should I simply be using a different type, like Global, or...?
Thankyou for any tips

Code:
Procedure Test()
  Protected xvar1.l = $11
  Protected xvar2.l = $22
  Protected xvar3.l = $33 
  PrintN("xvar1=" + Hex(xvar1))  ;$11
  PrintN("xvar2=" + Hex(xvar2))  ;$22
  PrintN("xvar3=" + Hex(xvar3))  ;$33
  EnableASM
  ! int 3
  ! push dword [p.v_xvar1]  ;$11
  ! push dword [p.v_xvar2]  ;should be $22 but is $11
  ! push dword [p.v_xvar3]  ;should be $33 but is $11
  DisableASM
EndProcedure
 
OpenConsole()
Test()

Author:  wilbert [ Fri Jul 31, 2015 6:08 pm ]
Post subject:  Re: how to push local variables onto the stack?

You can usually work around it by moving values first to registers and push those or use mov to put values on the stack.
In this case I have no idea what to advice since I have no idea what you are trying to do. Pushing three variables without correcting the stack pointer seems like asking for problems to me.

Author:  Keya [ Fri Jul 31, 2015 6:27 pm ]
Post subject:  Re: how to push local variables onto the stack?

for example to push parameters before calling the address of an API function directly

Author:  wilbert [ Fri Jul 31, 2015 7:05 pm ]
Post subject:  Re: how to push local variables onto the stack?

Two possible workarounds.
Code:
Procedure.i calloc(num, size)
  !extrn _calloc
  !mov eax, [p.v_size]
  !mov ecx, [p.v_num]
  !push eax
  !push ecx
  !call _calloc
  !add esp, 8
  ProcedureReturn
EndProcedure

Debug calloc(4, 50)


Code:
Procedure.i calloc(num, size)
  !extrn _calloc
 
  !mov eax, [p.v_size]
  !mov [esp - 4], eax
 
  !mov eax, [p.v_num]
  !mov [esp - 8], eax
 
  !sub esp, 8
  !call _calloc
  !add esp, 8
 
  ProcedureReturn
EndProcedure

Debug calloc(4, 50)

Author:  Keya [ Fri Jul 31, 2015 7:09 pm ]
Post subject:  Re: how to push local variables onto the stack?

Excellent, thankyou very much! :)
It seems I can also use the Prototype function for this, but i like to also know how to do it properly myself!

Author:  Thorium [ Sun Aug 02, 2015 9:14 am ]
Post subject:  Re: how to push local variables onto the stack?

You just need to add the right value to the variables stack index.
On x86 that would be 4 byte per push and on x64 8 byte per push.

So something like this:
Code:
Procedure Test()
 
  Protected TestVar1
  Protected TestVar2
 
  TestVar1 = 1
  TestVar2 = 2
 
  !push qword [p.v_TestVar1]
  !push qword [p.v_TestVar2+8]
 
 
  !pop qword [p.v_TestVar2+8]
  !pop qword [p.v_TestVar1]
 
 
  Debug TestVar1
  Debug TestVar2
   
EndProcedure

Test()


If you push something to the stack, the stack pointer changes and you need to correct local variable accesses like that.

Author:  Keya [ Sun Aug 02, 2015 9:45 am ]
Post subject:  Re: how to push local variables onto the stack?

the PB compiler should do be doing those adjustments for us before it sends to FASM. How it is at the moment is very restrictive as you have to keep track of every variable in its position on the stack, and then never change the code, or if you do you have to restart and debug it all again, yucky!

Author:  DoubleDutch [ Wed Sep 23, 2015 9:00 am ]
Post subject:  Re: how to push local variables onto the stack?

Can't you just copy the stack pointer to another register, then use that as the index to the local variables?

You will be able to push/pop from the stack as much as you like then (as long as the position is back to normal before the return).

Author:  Tenaja [ Wed Sep 23, 2015 4:05 pm ]
Post subject:  Re: how to push local variables onto the stack?

Keya wrote:
the PB compiler should do be doing those adjustments for us before it sends to FASM. How it is at the moment is very restrictive as you have to keep track of every variable in its position on the stack, and then never change the code, or if you do you have to restart and debug it all again, yucky!

The compiler does not "process" or "evaluate" your hand-written asm. It only outputs it directly.

PB uses [the register typically used as a frame pointer] for general use, to increase his number of registers available. This gives him another reg for optimizing his PB-generated code. I believe he investigated using it a few years back (IIRC, when looking into gosub/return within procs), and decided it was too much of an overhaul to implement.

Quote:
Can't you just copy the stack pointer to another register, then use that as the index to the local variables?

You will be able to push/pop from the stack as much as you like then (as long as the position is back to normal before the return).

That sounds like a great alternative, if you need more space than Wilbert's method allows, with limited registers.

Author:  wilbert [ Wed Sep 23, 2015 4:35 pm ]
Post subject:  Re: how to push local variables onto the stack?

I believe it won't work.
Local variables are defined relative to the esp/rsp register.
For example
Code:
%define p.v_test esp+40

So if you change the stack register, you can't use the defined p.v_test anymore unless you compensate for it like Thorium suggested.
You can of course copy the stack register value to another register but you don't know what the relative offset should be.

Author:  Tristano [ Sat May 06, 2017 2:49 pm ]
Post subject:  Re: how to push local variables onto the stack?

Interesting thread...

May I ask why the use of "Protected" keyword?

My understanding is that this keyword is needed to create a local (ie: local to the procedure) variable having the same name as an already existing global var. But I see it often used in procedure using ASM, so I was wondering if there are some added benefits from using Protected" when no naming conflict with a global variable is present. Are there?

Author:  Tenaja [ Sat May 06, 2017 8:43 pm ]
Post subject:  Re: how to push local variables onto the stack?

Tristano wrote:
Interesting thread...

May I ask why the use of "Protected" keyword?

My understanding is that this keyword is needed to create a local (ie: local to the procedure) variable having the same name as an already existing global var. But I see it often used in procedure using ASM, so I was wondering if there are some added benefits from using Protected" when no naming conflict with a global variable is present. Are there?


It is good practice to always use protected (local) variables within procedures, because you never know when you might reuse the code in another program that might have a conflicting global var name. Or, you might improve your code...etc.

Author:  Fig [ Sat May 06, 2017 8:48 pm ]
Post subject:  Re: how to push local variables onto the stack?

I am not sure to fully understand, forgive me if i am wrong.

Using pop and push is equivalent to increment/decrement (+/-4/8) Esp and Mov from [Esp+/-4/8] to register.
You can assume stack memory is in L1 cache (your local variables are part of the stack already), instead of pushing and poping, you would better Mov again you local variable in your register after you call function you need.

So, instead of

Code:
Protected xvar1.l = $11
Mov Eax,DWORD [p.v_xvar1]
...
Push Eax
...
Pop Eax

You can do
Code:
Protected xvar1.l = $11
Mov Eax,DWORD [p.v_xvar1]
...
Mov DWORD [p.v_xvar1],Eax
...
Mov Eax,DWORD [p.v_xvar1]


So you can create local variables and use them to store your registers instead of using push/pop, use Mov.

It will be as fast (or close enough) and safer.
Image

Author:  Tristano [ Mon May 08, 2017 9:06 am ]
Post subject:  Re: how to push local variables onto the stack?

Forgive my question, but I'm still learning FASM:

wilbert wrote:
I believe it won't work.
Local variables are defined relative to the esp/rsp register.
For example
Code:
%define p.v_test esp+40

... but you don't know what the relative offset should be.


... so local variables are macros, not labels?

This means that at each occurence of the (above) variable p.v_test its value is actually replaced by esp+40, thus making its value always realtive?

Author:  Fig [ Mon May 08, 2017 9:19 am ]
Post subject:  Re: how to push local variables onto the stack?

Yep, that's why using "push" (or changing Esp in any way) messes with local variables.

Page 1 of 2 All times are UTC + 1 hour
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/