Page 2 of 2

Re: how to push local variables onto the stack?

Posted: Mon May 08, 2017 12:49 pm
by Tristano
I've done some testing to get a clearer picture.

I've written this PB code (PB 5.60 Win x86) and compiled it via CLI with the /COMMENTED option to create the ASM source file output and peek in it:

Code: Select all

; PB 5.60 x86

Declare TestProc()

a = 10
b = 20
c = 30

TestProc()

Procedure TestProc()
  Protected aa = 10
  Protected bb = 20
  Protected cc = 30
  
! MOV dword [p.v_cc], 99
EndProcedure
If my understdaing of the output ASM source is correct, the vars a, b, and c in the code main body are allocated on the heap. In the final ASM source they are found toward the end, inside the .bss section (abridged code, lines 136–):

Code: Select all

section '.bss' readable writeable
_PB_BSSSection:
align 4
; [ ... ]
PB_DataPointer rd 1
v_a rd 1
v_b rd 1
v_c rd 1
; [ ... ]
I_BSSEnd:
The TestProc() in the source is (lines 83-108):

Code: Select all

; Procedure TestProc()
_Procedure0:
  PS0=16
  XOR    eax,eax
  PUSH   eax
  PUSH   eax
  PUSH   eax
; Protected aa = 10
  MOV    dword [esp],10
; Protected bb = 20
  MOV    dword [esp+4],20
; Protected cc = 30
  MOV    dword [esp+8],30
; 
; ! MOV dword [p.v_cc], 99
p.v_aa equ esp+0
p.v_bb equ esp+4
p.v_cc equ esp+8
  MOV    dword [p.v_cc], 99
; EndProcedure
_EndProcedureZero1:
  XOR    eax,eax
_EndProcedure1:
  ADD    esp,12
  RET
; 
... so it seems that PB's approach is to first fill the stack by PUSHing some 0 valued DWs (as many as the number of local variables about to create) and then fill the stack with the local vars by MOVing their values by using ESP-relative addressing (ie: ESP, ESP+4, ESP+8).

The local variables names are then defined as symbolic constants, using the same ESP-relative principle:

Code: Select all

p.v_aa equ esp+0
p.v_bb equ esp+4
p.v_cc equ esp+8
From Fasm documentation:
2.3.2 Symbolic constants

The symbolic constants are different from the numerical constants, before the assembly process they are replaced with their values everywhere in source lines after their definitions, and anything can become their values.

The definition of symbolic constant consists of name of the constant followed by the equ directive. Everything that follows this directive will become the value of constant. If the value of symbolic constant contains other symbolic constants, they are replaced with their values before assigning this value to the new constant.
So, if I've understood correctly, every time p.v_aa is referenced, it's value will be computed based on the value of ESP at the time it's being referenced --- and not at the value of ESP at the time of the constant declaration! Is it so?

Wasn't there a way to define the constant so that it's value is immutable, regardless of value changes in ESP after declaration -- ie: that all further references are not influenced by ESP? I feel like I'm missing out something here ...



NOTE 1: p.v_aa, p.v_bb and p.v_cc vars will only be created if there some inline ASM code that handles them. If from the above PB source you remove the inline-ASM line of code, those variables will just be put on the stack, but no constants will be created for referencing them by name.

Re: how to push local variables onto the stack?

Posted: Mon May 08, 2017 1:02 pm
by Fig
I didn't understand your question...
your local variables are part of the stack already
As i said earlier, local variable are relative to Esp and created in the stack at the beginning of each procedure.
So they are not "equ" constants in asm, equ can't be set with a register as it's a constant, of course !! (like constants in purebasic can't be set by a variable)
That's why i statued that we better use "Mov" to save local variables instead of using "push/pop" that change Esp and mess with others local variables.

And, by the way, when you use parameters to a fonction(x.i, y.i ,x.i...), they are also store on the stack and refered by Esp.

Re: how to push local variables onto the stack?

Posted: Mon May 08, 2017 3:22 pm
by Tristano
Fig wrote:I didn't understand your question...
Sorry, I didn't formulate my question well enough. As stated: I'm learning Fasm, so I'm trying to get a clearer picture of PB inner-workings, and to get straight Fasm terminology --- that's why I quoted the Fasm documentation.
Fig wrote:So they are not "equ" constants in asm, equ can't be set with a register as it's a constant, of course !! (like constants in purebasic can't be set by a variable).
... this is exactly the point that got me confused in Fasm documentation, and I was trying to understand if PB variable names for Fasm are defined as labels or constants.

Beyond the passage I quoted, the Fasm documentation provides some examples of symbolic contants using registers (ie: d equ edx):

Code: Select all

    d equ dword
    NULL equ d 0
    d equ edx
After these three definitions the value of NULL constant is dword 0 and the value of d is edx. So, for example, push NULL will be assembled as push dword 0 and push d will be assembled as push edx. And if then the following line was put:

Code: Select all

d equ d,eax
the d constant would get the new value of edx,eax. This way the growing lists of symbols can be defined.
... the above quoted text and examples gave me the impression that symbolic constants can be set with a register.

So, when in the asm code produce by pbcompiler we find:

Code: Select all

p.v_aa equ esp+0
What is this? Isn't it a symbolic constant? And do the different occurences of p.v_aa point to different stack locations depending on the current ESP, or is its offset defined just one, in the above line, and further references are not affected by ESP changes?

... this was the issue I was trying to understand.

Re: how to push local variables onto the stack?

Posted: Mon May 08, 2017 6:31 pm
by Fig
Well, as you can read in Fasm Documentation, the chapter is named 2.3 Preprocessor directives
So it's preprocesssed. Meaning a constant can't be set by a register value.
First point

So you understand that "equ" doesn't only define numerical constant but symbolics constants as well.
The documentation explicits by the exemple:
2.3.2 Symbolic constants
The symbolic constants are different from the numerical constants, before the assembly process they are replaced with their values everywhere in source lines after their definitions, and anything can become their values.
The definition of symbolic constant consists of name of the constant followed by the equ directive. Everything that follows this directive will become the value of constant. If the value of symbolic constant contains other symbolic constants, they are replaced with their values before assigning this value to the new constant. For example:

Code: Select all

    d equ dword
    NULL equ d 0
    d equ edx
After these three definitions the value of NULL constant is dword 0 and the value of d is edx. So, for example, push NULL will be assembled as push dword 0 and push d will be assembled as push edx.
So,

Code: Select all

d equ edx
means the symbol "d" will be replace by "edx" (the 3 letters not the value of the register !) in the plain text BEFORE (preprocess) beeing assemblied.

Re: how to push local variables onto the stack?

Posted: Mon May 08, 2017 9:00 pm
by Tristano
Fig wrote: So,

Code: Select all

d equ edx
means the symbol "d" will be replace by "edx" (the 3 letters not the value of the register !) in the plain text BEFORE (preprocess) beeing assemblied.
thanks, this is the answer I was looking for regarding symbolic constants (it wasn't clear to me from Fasm documentation).