how to push local variables onto the stack?

Bare metal programming in PureBasic, for experienced users
User avatar
Keya
Addict
Addict
Posts: 1864
Joined: Thu Jun 04, 2015 7:10 am

how to push local variables onto the stack?

Post by Keya »

I just found out that we cant push local variables :(
The helpfile says:
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: Select all

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()
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3737
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: how to push local variables onto the stack?

Post by wilbert »

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.
macOS 10.15 Catalina, Windows 10
User avatar
Keya
Addict
Addict
Posts: 1864
Joined: Thu Jun 04, 2015 7:10 am

Re: how to push local variables onto the stack?

Post by Keya »

for example to push parameters before calling the address of an API function directly
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3737
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: how to push local variables onto the stack?

Post by wilbert »

Two possible workarounds.

Code: Select all

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: Select all

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)
macOS 10.15 Catalina, Windows 10
User avatar
Keya
Addict
Addict
Posts: 1864
Joined: Thu Jun 04, 2015 7:10 am

Re: how to push local variables onto the stack?

Post by Keya »

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!
Thorium
Addict
Addict
Posts: 1268
Joined: Sat Aug 15, 2009 6:59 pm

Re: how to push local variables onto the stack?

Post by Thorium »

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: Select all

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.
User avatar
Keya
Addict
Addict
Posts: 1864
Joined: Thu Jun 04, 2015 7:10 am

Re: how to push local variables onto the stack?

Post by Keya »

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!
User avatar
DoubleDutch
Addict
Addict
Posts: 3197
Joined: Thu Aug 07, 2003 7:01 pm
Location: United Kingdom
Contact:

Re: how to push local variables onto the stack?

Post by DoubleDutch »

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).
https://deluxepixel.com <- My Business website
https://reportcomplete.com <- School end of term reports system
User avatar
Tenaja
Addict
Addict
Posts: 1816
Joined: Tue Nov 09, 2010 10:15 pm

Re: how to push local variables onto the stack?

Post by Tenaja »

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.
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.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3737
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: how to push local variables onto the stack?

Post by wilbert »

I believe it won't work.
Local variables are defined relative to the esp/rsp register.
For example

Code: Select all

%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.
macOS 10.15 Catalina, Windows 10
User avatar
Tristano
Enthusiast
Enthusiast
Posts: 191
Joined: Thu Nov 26, 2015 6:52 pm
Location: Italy
Contact:

Re: how to push local variables onto the stack?

Post by Tristano »

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?
The PureBASIC Archives: FOSS Resources:
User avatar
Tenaja
Addict
Addict
Posts: 1816
Joined: Tue Nov 09, 2010 10:15 pm

Re: how to push local variables onto the stack?

Post by Tenaja »

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.
User avatar
Fig
Enthusiast
Enthusiast
Posts: 348
Joined: Thu Apr 30, 2009 5:23 pm
Location: Côtes d'Azur, France

Re: how to push local variables onto the stack?

Post by Fig »

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: Select all

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

Code: Select all

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
Last edited by Fig on Mon May 08, 2017 9:25 am, edited 2 times in total.
There are 2 methods to program bugless.
But only the third works fine.

Win10, Pb x64 5.71 LTS
User avatar
Tristano
Enthusiast
Enthusiast
Posts: 191
Joined: Thu Nov 26, 2015 6:52 pm
Location: Italy
Contact:

Re: how to push local variables onto the stack?

Post by Tristano »

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: Select all

%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?
The PureBASIC Archives: FOSS Resources:
User avatar
Fig
Enthusiast
Enthusiast
Posts: 348
Joined: Thu Apr 30, 2009 5:23 pm
Location: Côtes d'Azur, France

Re: how to push local variables onto the stack?

Post by Fig »

Yep, that's why using "push" (or changing Esp in any way) messes with local variables.
There are 2 methods to program bugless.
But only the third works fine.

Win10, Pb x64 5.71 LTS
Post Reply