; adapt it for been compilable with fasm1 official package
macro stackorg n {%s=n} if ~definite %s
%s=0
end if
macro accum d,value {
d#. equ value
d = value }
macro reset d {
restore d#.
irpv any,d#. \{ \common d = d#.
rept 0 \{\} rept 1 \{ d=0 \} }
STACK_FRAMED = 0
STACKNOFRAME = 1
NULL = 0
espadressable = NULL ; assembly time variable with help of accum and reset able to store previous values and restore them
ebpadressable = NULL ; same
While normaly fasm is procedure oriented language with help of proc macro family I prefer different approach procedure chunk oriented (or code block oriented) programming, where each block related to vars accessed from it
macro new_code_block { local ID,espinit,ebpinit,accessedtype
ID = $
espinit = %s
ebpinit = -1
accessedtype = STACKNOFRAME
accum espadressable, ID
codeblock equ ID,espinit,ebpinit,accessedtype }
macro frame ebp { match ID=,espinit=,ebpinit=,accessedtype,codeblock \{
ebpinit = %s
accessedtype = STACK_FRAMED
accum ebpadressable, ID \} }
macro exitframe {
match ID1:Id2 ,espadressable#.:ebpadressable#. \{
match =ID1,Id2 \\{ rept 0 \\{\\} rept 1 \\{
restore codeblock
reset espadressable \\}
match ID=,espinit=,ebpinit=,accessedtype,codeblock \\{
ebpinit = -1
accessedtype = STACKNOFRAME
reset ebpadressable \\} \} }
macro var name,value { match ID=,espinit=,ebpinit=,accessedtype,codeblock \{
name equ value+-espinit+(%s+esp+(espadressable-ID)*eip)*accessedtype+(1-accessedtype)*(ebpinit+ebp+(ebpadressable-ID)*eip)
\}}
macro alignstack { new_code_block }
testcase
use32
stackorg 4
new_code_block
var a,0
pushd [a] ;via esp
frame ebp
var b,0
pushd [a] ;via ebp
pushd [b] ;via ebp
alignstack
pushd [a] ;via ebp
pushd [b] ;via ebp
var c,0
pushd [c] ;via esp
frame ebp
;pushd [a] ;must error unaccessible here
;pushd [b] ;must error unaccessible here
pushd [c] ;via ebp
var d,0
pushd [d] ;via ebp
exitframe
pushd [a] ;via ebp
pushd [b] ;via ebp
pushd [c] ;via esp
pushd [d] ;via esp
exitframe
pushd [a] ;via esp
pushd [b] ;via esp
;pushd [c] ;must error unaccessible here
;pushd [d] ;must error unaccessible here
with disassembly of output it is seen that every var addressed as in comment.
Above code have only practical sense in fasm compiler able to track stack changes and it shows principle of stack addressing mode switches. Shows only principle mean without producing assembly instruction related to that switch (like "and esp, not $F" for "alignstack" macro, or "push ebp","mov ebp,esp" for "frame ebp" macro, for clearity macro is "frame" but no matter)
mixing assembly and preprocessor stages was always difficult - that is one of example of that when vars used in equ statement are assembly time vars with = as value assignment, and they remain ability to make preprocessor time conditions over them.