flat assembler
Message board for the users of flat assembler.
Index
> Macroinstructions > solved:define name subnames (like structure)at preprocessing |
Author |
|
Tomasz Grysztar 03 Feb 2023, 18:04
Coming from fasmg+CALM it's not easy to go back to constructing complex fasm 1 macros. Perhaps you could reduce this to a set of smaller problems that would be easier to wrap one's head around?
|
|||
03 Feb 2023, 18:04 |
|
ProMiNick 03 Feb 2023, 21:46
Thanks anyway.
Looks like I found solution: setup environment for macro & test Code: use32
include 'win32a.inc' helper macros hold whole logic Code: macro recurse@structurise { macro structurise target,source,dummy,[field,type,def] \{ match any,field \\{ match any,target\#.fields \\\{ target\#.fields equ target\#.fields , \\\} ; 2 lines for later restoring symbols target\#.fields equ target\#.fields target\#.\#field ; target\#.\#field equ target + source\#.\#field define try target\#.\#field match _field,try \\\{ recurse@substruct _field substruct type restruc substruct \\\} \\} match ,field \\{ recurse@structurise structurise target,source,def purge structurise \\} \} } recurse@structurise macro recurse@substruct { struc substruct name \{ match any =, more,fields@\#name \\{ match fields,fields@\#name \\\{ recurse@structurise structurise .,name,, fields purge structurise \\\} \\} \} } recurse@substruct just syntax decoration of helper macros Code: struc struct name { .: .#.fields equ . substruct name } test piece Code: struct RECT2 a RECT union b RECT struct c RECT d RECT ends ends ends rectR struct RECT2 mov eax, [rectR] mov eax, [rectR.a] mov eax, [rectR.a.left] mov eax, [rectR.a.top] mov eax, [rectR.a.right] mov eax, [rectR.a.bottom] mov eax, [rectR.b] mov eax, [rectR.b.left] mov eax, [rectR.b.top] mov eax, [rectR.b.right] mov eax, [rectR.b.bottom] mov eax, [rectR.c] mov eax, [rectR.c.left] mov eax, [rectR.c.top] mov eax, [rectR.c.right] mov eax, [rectR.c.bottom] mov eax, [rectR.d] mov eax, [rectR.d.left] mov eax, [rectR.d.top] mov eax, [rectR.d.right] mov eax, [rectR.d.bottom] successfull compilation mean: 1. all structuring attached to symbol rectR, 2. all members of rectR assigned size too from struct members futher test: Code: irp all, rectR.fields { match any,all \{restore any \} } mov eax, [rectR] rectR.a = 0 mov eax, [rectR.a] mov eax, [rectR.a.left] mov eax, [rectR.a.top] mov eax, [rectR.a.right] mov eax, [rectR.a.bottom] mov eax, [rectR.b] ; Error: undefined symbol 'rectR.b'. mov eax, [rectR.b.left] succesfull crash mean: 1. members are preprocessor symbols, not labels and could be redefined 2. bad - member childs not in rectR.fields because of no error at mov eax, [rectR.a.left] So left 5 smaller problem - 1. Is it realy work, or I just got luck and some structs could crash my algo? (need shurance) 2. Child members of substructures in code logic passed to rectR.fields, but something goes wrong and they not passed. (need help) 3. May be something in logic could be reduced or cutted off without suffer pof logic (need advise) 4. of cource all compiled, but is values compiled correctly? Is "target\#.\#field equ target + source\#.\#field" was right solution or I should use define instead of equ? (need advise) 5. in test example rectR defined is label, but in future it supposed to be movable variable, that in other pieces of code have different values and struct members should follow move of rectR (related to problem 4) Main reason of constructing of all of it - moving variable with whole structure of child fields names. by the way I hope Code: rectR struct RECT2 Code: virtual rectR RECT2 end virtual; it is far from abilities of previous one, but is most similar by action for case where is not supposed to move structure _________________ I don`t like to refer by "you" to one person. My soul requires acronim "thou" instead. |
|||
03 Feb 2023, 21:46 |
|
ProMiNick 04 Feb 2023, 21:46
helper macros modification:
Code: macro recurse@structurise { macro structurise target,source,dummy,[field,type,def] \{ match any,field \\{ match any,target\#.fields \\\{ target\#.fields equ target\#.fields , \\\} target\#.fields equ target\#.fields target\#.\#field target\#.\#field equ target + source\#.\#field define try target\#.\#field match _field,try \\\{ recurse@substruct _field substruct type match any =, rest, _field\\\#.fields \\\\{ target\#.fields equ target\#.fields , _field\\\#.fields \\\\} ; this line added it collects subfields restruc substruct \\\} \\} match ,field \\{ recurse@structurise structurise target,source,def purge structurise \\} \} } now futher test crash in proper place: Code: irp all, rectR.fields { match any,all \{restore any \} } mov eax, [rectR] rectR.a = 0 mov eax, [rectR.a] mov eax, [rectR.a.left] ; Error: undefined symbol 'rectR.a.left'. mov eax, [rectR.a.top] mov eax, [rectR.a.right] mov eax, [rectR.a.bottom] mov eax, [rectR.b] mov eax, [rectR.b.left] succesfull crash mean: 1. members are preprocessor symbols, not labels and could be redefined 2. all preprocessor symbols that created by "rectR struct RECT2" are cleared with "irp all, rectR.fields { match any,all \{restore any \} }" So left 5 smaller problem - ... [Solved] 2. Child members of substructures in code logic passed to rectR.fields, but something goes wrong and they not passed. ... |
|||
04 Feb 2023, 21:46 |
|
ProMiNick 06 Feb 2023, 23:32
i called unit STRUCTEX.INC
Code: ; Macroinstructions for structurised naming without defining of data macro recurse@structurise { macro structurise target,source,dummy,[field,type,def] \{ match any,field \\{ match any,target\#.fields \\\{ target\#.fields equ target\#.fields , \\\} target\#.fields equ target\#.fields target\#.\#field target\#.\#field equ target + source\#.\#field define try target\#.\#field match _field,try \\\{ recurse@substruct _field substruct type match any =, rest, _field\\\#.fields \\\\{ target\#.fields equ target\#.fields , _field\\\#.fields \\\\} ; this line added it collects subfields restruc substruct \\\} \\} match ,field \\{ recurse@structurise structurise target,source,def purge structurise \\} \} } recurse@structurise macro recurse@substruct { struc substruct name \{ match any =, more,fields@\#name \\{ match fields,fields@\#name \\\{ recurse@structurise structurise .,name,, fields purge structurise \\\} \\} \} } recurse@substruct than test it on procedure like definition(named STACK.INC): Code: use32 format binary as 'dll' ; just for convinience, I have disassembler is in the shell for dll files to see output include 'struct.inc' include 'structex.inc' varbase equ esp ; tested only principles, so varbase so simple macro stack@arg arg { local @proxy,@depth @depth = stack@depth match name rest,arg: \{ name equ varbase+@depth define @proxy name stack@depth = stack@depth+4 \} match name:type,arg \{ match _name,@proxy \\{ _name substruct type match any =, rest, _name\\#.fields \\\{ _locals equ _locals , _name\\#.fields \\\} \\} if defined sizeof.\#type stack@depth = stack@depth+sizeof.\#type-4 end if \} } macro RTL_C [arg] { common ret@address equ varbase stack@depth = 4 forward stack@arg arg } macro LTR_pascal [arg] { common ret@address equ varbase stack@depth = 4 reverse stack@arg arg } struct RECT left dd ? top dd ? right dd ? bottom dd ? ends hello: LTR_pascal a:RECT,b,c,d mov eax,[a.top] mov eax,[b] mov eax,[c] mov eax,[d] than test it on locals like definition (named LOCALS.INC): Code: use32 format binary as 'dll' include 'struct.inc' include 'structex.inc' varbase equ esp macro recurse@localunion { macro localunion depth,dummy,[field,type,def] \{ \common \local @depth @depth = depth \forward match any,field \\{ virtual at 0 type def if @depth+$ > stack@depth stack@depth = @depth+$ end if end virtual _locals equ _locals , field field equ varbase+@depth define try field match _field,try \\\{ _field substruct type match any =, rest, _field\\\#.fields \\\\{ _locals equ _locals , _field\\\#.fields \\\\} \\\} \\} match ,field \\{ recurse@localunion localunion @depth,def purge localunion \\} \} } recurse@localunion macro localroot dummy,[field,type,def] { local @depth @depth = stack@depth match any,field \{ virtual at 0 type def stack@depth = @depth+$ end virtual _locals equ _locals , field field equ varbase+@depth define try field match _field,try \\{ _field substruct type match any =, rest, _field\\#.fields \\\{ _locals equ _locals , _field\\#.fields \\\} \\} \} match ,field \{ recurse@localunion localunion @depth,def purge localunion \} } macro locals { macro union \{ macro endu \\{ purge endu,ends field@struct reequ field@struct> restore sub@struct \\} macro ends \\{ endu \\} field@struct equ ,subunion,< sub@struct equ subunion \} macro endl \{ restruc db,dw,du,dd,dp,dq,dt restruc rb,rw,rd,rp,rq,rt purge db,dw,du,dd,dp,dq,dt purge rb,rw,rd,rp,rq,rt purge union,endl irpv fields,field@struct \\{ restore field@struct \\common restore @struct stack@depth = 0 localroot ,fields \\} end virtual \} irp d@,db,dw,du,dd,dp,dq,dt \{ struc d@ [val] \\{ \\common define field@struct .,d@,<val> \\} macro d@ [val] \\{ \\common \\local anonymous define field@struct anonymous,d@,<val> \\} \} irp r@,rb,rw,rd,rp,rq,rt \{ match d@,def.\#r@ \\{ struc r@ count \\\{ \\\local offset,size define field@struct .,d@,count dup (?) \\\} macro r@ count \\\{ \\\local anonymous define field@struct anonymous,d@,count dup (?) \\\} \\} \} define @struct sub@struct equ virtual at 0 } struct RECT left dd ? top dd ? right dd ? bottom dd ? ends locals A RECT b rb 256 union c rb 40 D RECT endu l dd 4 endl mov eax,[A.top] mov al,[b+30] mov eax,[c] mov eax,[D] mov eax,[D.top] mov eax,[l] And I love in that syntax from first sight as alternative to proc definition & local definition. Advantages: STRUCTEX.INC not limited with architecture or birness, STACK.INC limited only 32 bit environment as target, LOCALS.INC again not limited with architecture or birness. |
|||
06 Feb 2023, 23:32 |
|
ProMiNick 17 Feb 2023, 13:57
Code: use32 format binary as 'dll' include 'helper.inc' include 'struct.inc' include 'structex.inc' eax@frame=0 ebx@frame=0 ecx@frame=0 edx@frame=0 esi@frame=0 edi@frame=0 esp@frame=1 ebp@frame=0 track@offset=0 track@frame=0 stack@offset=0 stack@top equ eax*eax@frame+ebx*ebx@frame+ecx*ecx@frame+edx*edx@frame+esi*esi@frame+edi*edi@frame+(esp+%s)*esp@frame+ebp*ebp@frame+track@offset*track@frame+stack@offset struc align arg { .:align arg } ; this or ;struc align arg { align arg } ; this - no matter caller = 0 callee = 0 macro stack@init arg& { stackorg off_macro stack@init } macro stack@retaddr { match , @struct \{ define field@struct ret@address,dd,? \} match no, @struct \{ ret@address equ stack@top + anchor@stack stack@depth = 4 \} } macro stack@arg arg { match , @struct \{ match name rest,arg: \\{ match :type:,rest \\\{ name type \\\} match :,rest \\\{ define field@struct name,dd,? \\\} \\} \} match no, @struct \{ \local @proxy,@depth @depth = stack@depth match name rest,arg: \\{ name equ stack@top+@depth + anchor@stack define @proxy name stack@depth = stack@depth+4 \\} match name:type,arg \\{ match _name,@proxy \\\{ _name substruct type match any =, rest, _name\\\#.fields \\\\{ _locals equ _locals , _name\\\#.fields \\\\} \\\} if defined sizeof.\\#type stack@depth = stack@depth+sizeof.\\#type-4 end if \\} \} } macro RTL_C [arg] { common ;stack@init anchor@stack = -%s stack@retaddr forward stack@arg arg common match no, @struct \{ callee = stack@depth \} } macro LTR_pascal [arg] { common ;stack@init anchor@stack = -%s stack@retaddr reverse stack@arg arg common match no, @struct \{ callee = stack@depth \} } macro stack_cleanup SC:callee { if ~SC retn else retn SC end if } macro frame reg:esp { local localsize, ct lock_macro frame macro endf \{ ct codetype localsize = (stack@depth + (ct-1)) and not (ct-1) purge endf \} ; again cancel nesting macro exitf \{ if ~reg eq esp if defined localsize & localsize mov esp, reg end if pop reg else if defined localsize & localsize add esp, localsize end if \} match any =esp rest,:reg esp: \{ match :,rest \\{ macro via_sp instruction& \\\{ track@frame=0 esp@frame=1 reg#@frame=0 match i,instruction \\\\{ i \\\\} track@frame=1 esp@frame=0 reg#@frame=1 \\\} \\} match :,any \\{ macro via_sp instruction& \\\{ match i,instruction \\\\{ i \\\\} \\\} \\} \} if defined localsize & localsize sub esp, localsize end if if ~reg eq esp push reg mov reg, esp track@offset=%s track@frame=1 esp@frame=0 reg#@frame=1 end if } macro recurse@varlocal { macro varlocal field,type,def \{ \local ..depth match any,field \\{ _locals equ _locals , field field equ stack@top+..depth ..depth type def define try field match _field,try \\\{ _field substruct type match any =, rest, _field\\\#.fields \\\\{ _locals equ _locals , _field\\\#.fields \\\\} \\\} restore try \\} match ,field \\{ recurse@localunion localunion def purge localunion \\} \} } ;recurse@varlocal macro recurse@localunion { macro localunion dummy,[field,type,def] \{ \common \local size size = 0 \forward virtual recurse@varlocal varlocal field,type,<def> purge varlocal if $ > size size = $ end if end virtual \common rb size \} } ;recurse@localunion macro localroot dummy,[field,type,def] { recurse@varlocal varlocal field,type,<def> purge varlocal } macro locals { macro union \{ macro endu \\{ purge endu,ends field@struct reequ field@struct> restore sub@struct \\} macro ends \\{ endu \\} field@struct equ ,subunion,< sub@struct equ subunion \} macro endl \{ restruc db,dw,du,dd,dp,dq,dt restruc rb,rw,rd,rp,rq,rt purge db,dw,du,dd,dp,dq,dt purge rb,rw,rd,rp,rq,rt purge union,endl,align,uses irpv fields,field@struct \\{ restore field@struct \\common restore @struct virtual at -%s localroot ,fields stack@depth = $-$$ end virtual \\} end virtual \} macro align amount \{ \local anonymous define field@struct anonymous,align,amount \} macro uses regs \{ irps reg,regs \\{ \\local anonymous define field@struct anonymous,dd,? \\} \} irp d@,db,dw,du,dd,dp,dq,dt \{ struc d@ [val] \\{ \\common define field@struct .,d@,<val> \\} macro d@ [val] \\{ \\common \\local anonymous define field@struct anonymous,d@,<val> \\} \} irp r@,rb,rw,rd,rp,rq,rt \{ match d@,def.\#r@ \\{ struc r@ count \\\{ \\\local offset,size define field@struct .,d@,count dup (?) \\\} macro r@ count \\\{ \\\local anonymous define field@struct anonymous,d@,count dup (?) \\\} \\} \} ;stack@offset=-%s define @struct sub@struct equ virtual at 0 } macro flush [args] { irp arg, args \{ match all, arg \\{restore all \\} \} } macro flush_locals { unlock_macro frame purge exitf,via_sp flush _locals irpv any, _locals \{restore _locals \} ; otherwise memory leak at preprocessor stage callee = 0 } Code: struct RECT left dd ? top dd ? right dd ? bottom dd ? ends hello2: RTL_C g2,h2,i2,j2 push edx hello: LTR_pascal a1:RECT,b1,c1,d1,f1 ;stack@init ;stackorg ;stack@retaddr frame ebp locals A RECT b rb 256 union c rb 40 D RECT union d rb 40 E RECT union e rb 40 F RECT endu endu endu l dd 4 ;align $200 q dd ? uses ebp ebx esi endl endf sub esp,$10 locals N RECT endl mov eax,[a1.top] mov eax,[b1] mov eax,[c1] mov eax,[d1] push edx mov eax,[a1.top] mov eax,[b1] mov eax,[c1] mov eax,[d1] via_sp mov [A.top],2 via_sp mov [b+30],3 via_sp mov [e],4 via_sp mov dword[F],5 via_sp mov [F.top],6 mov [q],7 mov [N.left],8 mov [A.top],2 mov [b+30],3 mov [e],4 mov dword[F],5 mov [F.top],6 mov [q],7 mov [N.left],8 via_sp mov [q],7 push esi via_sp mov [A.top],2 via_sp mov [b+30],3 via_sp mov [e],4 via_sp mov dword[F],5 via_sp mov [F.top],6 mov [q],7 mov [N.left],8 via_sp mov [q],7 via_sp mov [N.left],8 exitf stack_cleanup callee ;stack_cleanup caller flush_locals ;mov eax,[A.top] output: Code: L_00000000: push edx L_00000001: sub esp, 0x124 L_00000007: push ebp L_00000008: mov ebp, esp L_0000000A: sub esp, 0x10 L_0000000D: mov eax, [ebp+0x140] L_00000013: mov eax, [ebp+0x138] L_00000019: mov eax, [ebp+0x134] L_0000001F: mov eax, [ebp+0x130] L_00000025: push edx L_00000026: mov eax, [ebp+0x140] L_0000002C: mov eax, [ebp+0x138] L_00000032: mov eax, [ebp+0x134] L_00000038: mov eax, [ebp+0x130] L_0000003E: mov dword [esp+0x18], 0x2 L_00000046: mov byte [esp+0x42], 0x3 L_0000004B: mov byte [esp+0x124], 0x4 L_00000053: mov dword [esp+0x124], 0x5 L_0000005E: mov dword [esp+0x128], 0x6 L_00000069: mov dword [ebp+0x114], 0x7 L_00000073: mov dword [ebp-0x10], 0x8 L_0000007A: mov dword [ebp+0x4], 0x2 L_00000081: mov byte [ebp+0x2e], 0x3 L_00000085: mov byte [ebp+0x110], 0x4 L_0000008C: mov dword [ebp+0x110], 0x5 L_00000096: mov dword [ebp+0x114], 0x6 L_000000A0: mov dword [ebp+0x114], 0x7 L_000000AA: mov dword [ebp-0x10], 0x8 L_000000B1: mov dword [esp+0x128], 0x7 L_000000BC: push esi L_000000BD: mov dword [esp+0x1c], 0x2 L_000000C5: mov byte [esp+0x46], 0x3 L_000000CA: mov byte [esp+0x128], 0x4 L_000000D2: mov dword [esp+0x128], 0x5 L_000000DD: mov dword [esp+0x12c], 0x6 L_000000E8: mov dword [ebp+0x114], 0x7 L_000000F2: mov dword [ebp-0x10], 0x8 L_000000F9: mov dword [esp+0x12c], 0x7 L_00000104: mov dword [esp+0x8], 0x8 L_0000010C: mov esp, ebp L_0000010E: pop ebp L_0000010F: ret 0x24 compiled in fasm with additions described in addition "stack tracing |
|||
17 Feb 2023, 13:57 |
|
ProMiNick 17 Feb 2023, 23:24
Code: ; Simple text editor - fasm example program format PE GUI 4.0 entry start include 'win32a.inc' macro lock_macro [name] { name equ name macro name \{ err \} } macro off_macro [name] { name equ name macro name arg& \{ \} } macro unlock_macro [name] { irpv any,name \{ purge name restore name \} } ; revolution, x86 struc codetype { virtual at 0 inc ax . = 1 shl $ end virtual } macro recurse@structurise { macro structurise target,source,dummy,[field,type,def] \{ match any,field \\{ match any,target\#.fields \\\{ target\#.fields equ target\#.fields , \\\} target\#.fields equ target\#.fields target\#.\#field target\#.\#field equ target + source\#.\#field define try target\#.\#field match _field,try \\\{ recurse@substruct _field substruct type match any =, rest, _field\\\#.fields \\\\{ target\#.fields equ target\#.fields , _field\\\#.fields \\\\} ; this line added it collects subfields restruc substruct \\\} \\} match ,field \\{ recurse@structurise structurise target,source,def purge structurise \\} \} } recurse@structurise macro recurse@substruct { struc substruct name \{ match any =, more,fields@\#name \\{ match fields,fields@\#name \\\{ recurse@structurise structurise .,name,, fields purge structurise \\\} \\} \} } recurse@substruct macro invoke args& { local s s=%s invoke args stackorg s} esp@frame=1 ebp@frame=0 track@offset=0 track@frame=0 stack@top equ (esp+%s)*esp@frame+ebp*ebp@frame+track@offset*track@frame caller = 0 callee = 0 struc align arg { .:align arg } ; this or macro stack@init arg& { stackorg off_macro stack@init } macro stack@retaddr { match , @struct \{ define field@struct ret@address,dd,? \} match no, @struct \{ ret@address equ stack@top + anchor@stack stack@depth = 4 \} } macro stack@arg arg { match , @struct \{ match name rest,arg: \\{ match :type:,rest \\\{ name type \\\} match :,rest \\\{ define field@struct name,dd,? \\\} \\} \} match no, @struct \{ \local @proxy,@depth @depth = stack@depth match name rest,arg: \\{ name equ stack@top+@depth + anchor@stack define @proxy name stack@depth = stack@depth+4 \\} match name:type,arg \\{ match _name,@proxy \\\{ _name substruct type match any =, rest, _name\\\#.fields \\\\{ _locals equ _locals , _name\\\#.fields \\\\} \\\} if defined sizeof.\\#type stack@depth = stack@depth+sizeof.\\#type-4 end if \\} \} } macro RTL_C [arg] { common stack@init anchor@stack = -%s stack@retaddr forward stack@arg arg common match no, @struct \{ callee = stack@depth-4 \} } macro LTR_pascal [arg] { common stack@init anchor@stack = -%s stack@retaddr reverse stack@arg arg common match no, @struct \{ callee = stack@depth-4 \} } macro stack_cleanup SC:callee { if ~SC retn else retn SC end if } macro frame reg:esp { local localsize, ct lock_macro frame macro endf \{ ct codetype localsize = (stack@depth + (ct-1)) and not (ct-1) purge endf \} ; again cancel nesting macro exitf \{ if ~reg eq esp if defined localsize & localsize mov esp, reg end if pop reg else if defined localsize & localsize add esp, localsize end if \} match any =esp rest,:reg esp: \{ match :,rest \\{ macro via_sp instruction& \\\{ track@frame=0 esp@frame=1 reg#@frame=0 match i,instruction \\\\{ i \\\\} track@frame=1 esp@frame=0 reg#@frame=1 \\\} \\} match :,any \\{ macro via_sp instruction& \\\{ match i,instruction \\\\{ i \\\\} \\\} \\} \} anchor@stack = -%s if defined localsize & localsize sub esp, localsize end if if ~reg eq esp push reg mov reg, esp track@offset=%s track@frame=1 esp@frame=0 reg#@frame=1 end if } macro recurse@varlocal { macro varlocal field,type,def \{ \local ..depth,..stack match any,field \\{ _locals equ _locals , field field equ stack@top+..depth+..stack ..stack = -%s ..depth type def define try field match _field,try \\\{ _field substruct type match any =, rest, _field\\\#.fields \\\\{ _locals equ _locals , _field\\\#.fields \\\\} \\\} restore try \\} match ,field \\{ recurse@localunion localunion def purge localunion \\} \} } macro recurse@localunion { macro localunion dummy,[field,type,def] \{ \common \local size size = 0 \forward virtual recurse@varlocal varlocal field,type,<def> purge varlocal if $ > size size = $ end if end virtual \common rb size \} } macro localroot dummy,[field,type,def] { recurse@varlocal varlocal field,type,<def> purge varlocal } macro locals { macro union \{ macro endu \\{ purge endu,ends field@struct reequ field@struct> restore sub@struct \\} macro ends \\{ endu \\} field@struct equ ,subunion,< sub@struct equ subunion \} macro endl \{ restruc db,dw,du,dd,dp,dq,dt restruc rb,rw,rd,rp,rq,rt purge db,dw,du,dd,dp,dq,dt purge rb,rw,rd,rp,rq,rt purge union,endl,align,uses irpv fields,field@struct \\{ restore field@struct \\common restore @struct virtual at 0;-%s localroot ,fields stack@depth = $-$$ end virtual \\} end virtual \} macro align amount \{ \local anonymous define field@struct anonymous,align,amount \} macro uses regs \{ irps reg,regs \\{ \\local anonymous define field@struct anonymous,dd,? \\} \} irp d@,db,dw,du,dd,dp,dq,dt \{ struc d@ [val] \\{ \\common define field@struct .,d@,<val> \\} macro d@ [val] \\{ \\common \\local anonymous define field@struct anonymous,d@,<val> \\} \} irp r@,rb,rw,rd,rp,rq,rt \{ match d@,def.\#r@ \\{ struc r@ count \\\{ \\\local offset,size define field@struct .,d@,count dup (?) \\\} macro r@ count \\\{ \\\local anonymous define field@struct anonymous,d@,count dup (?) \\\} \\} \} ;stack@offset=-%s define @struct sub@struct equ virtual at 0 } macro flush [args] { irp arg, args \{ match all, arg \\{restore all \\} \} } macro flush_locals { unlock_macro frame purge exitf,via_sp flush _locals irpv any, _locals \{restore _locals \} ; otherwise memory leak at preprocessor stage callee = 0 } via esp frame, we could comment & uncomment pair frame exitf Code: IDR_ICON = 17 IDR_MENU = 37 IDM_NEW = 101 IDM_EXIT = 102 IDM_ABOUT = 901 section '.text' code readable executable start: RTL_C invoke GetModuleHandle,0 mov [wc.hInstance],eax invoke LoadIcon,eax,IDR_ICON mov [wc.hIcon],eax invoke LoadCursor,0,IDC_ARROW mov [wc.hCursor],eax invoke RegisterClass,wc test eax,eax jz error invoke LoadMenu,[wc.hInstance],IDR_MENU invoke CreateWindowEx,0,_class,_title,WS_VISIBLE+WS_OVERLAPPEDWINDOW,144,128,256,256,NULL,eax,[wc.hInstance],NULL test eax,eax jz error msg_loop: invoke GetMessage,msg,NULL,0,0 cmp eax,1 jb end_loop jne msg_loop invoke TranslateMessage,msg invoke DispatchMessage,msg jmp msg_loop error: invoke MessageBox,NULL,_error,NULL,MB_ICONERROR+MB_OK end_loop: invoke ExitProcess,[msg.wParam] flush_locals WindowProc: RTL_C hwnd,wmsg,wparam,lparam ;frame push ebx esi edi mov eax,[wmsg] cmp eax,WM_CREATE je .wmcreate cmp eax,WM_SIZE je .wmsize cmp eax,WM_SETFOCUS je .wmsetfocus cmp eax,WM_COMMAND je .wmcommand cmp eax,WM_DESTROY je .wmdestroy .defwndproc: invoke DefWindowProc,[hwnd],[wmsg],[wparam],[lparam] jmp .finish .wmcreate: invoke GetClientRect,[hwnd],client invoke CreateWindowEx,WS_EX_CLIENTEDGE,_edit,0,WS_VISIBLE+WS_CHILD+WS_HSCROLL+WS_VSCROLL+ES_AUTOHSCROLL+ES_AUTOVSCROLL+ES_MULTILINE,[client.left],[client.top],[client.right],[client.bottom],[hwnd],0,[wc.hInstance],NULL or eax,eax jz .failed mov [edithwnd],eax invoke CreateFont,16,0,0,0,0,FALSE,FALSE,FALSE,ANSI_CHARSET,OUT_RASTER_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FIXED_PITCH+FF_DONTCARE,NULL or eax,eax jz .failed mov [editfont],eax invoke SendMessage,[edithwnd],WM_SETFONT,eax,FALSE xor eax,eax jmp .finish .failed: or eax,-1 jmp .finish .wmsize: invoke GetClientRect,[hwnd],client invoke MoveWindow,[edithwnd],[client.left],[client.top],[client.right],[client.bottom],TRUE xor eax,eax jmp .finish .wmsetfocus: invoke SetFocus,[edithwnd] xor eax,eax jmp .finish .wmcommand: mov eax,[wparam] and eax,0FFFFh cmp eax,IDM_NEW je .new cmp eax,IDM_ABOUT je .about cmp eax,IDM_EXIT je .wmdestroy jmp .defwndproc .new: invoke SendMessage,[edithwnd],WM_SETTEXT,0,0 jmp .finish .about: invoke MessageBox,[hwnd],_about_text,_about_title,MB_OK jmp .finish .wmdestroy: invoke DeleteObject,[editfont] invoke PostQuitMessage,0 xor eax,eax .finish: pop edi esi ebx ;exitf stack_cleanup callee flush_locals section '.data' data readable writeable _title TCHAR 'MiniPad',0 _about_title TCHAR 'About MiniPad',0 _about_text TCHAR 'This is Win32 example program created with flat assembler.',0 _error TCHAR 'Startup failed.',0 _class TCHAR 'MINIPAD32',0 _edit TCHAR 'EDIT',0 wc WNDCLASS 0,WindowProc,0,0,NULL,NULL,NULL,COLOR_BTNFACE+1,NULL,_class edithwnd dd ? editfont dd ? msg MSG client RECT section '.idata' import data readable writeable library kernel,'KERNEL32.DLL',\ user,'USER32.DLL',\ gdi,'GDI32.DLL' import kernel,\ GetModuleHandle,'GetModuleHandleA',\ ExitProcess,'ExitProcess' import user,\ RegisterClass,'RegisterClassA',\ CreateWindowEx,'CreateWindowExA',\ DefWindowProc,'DefWindowProcA',\ SetWindowLong,'SetWindowLongA',\ RedrawWindow,'RedrawWindow',\ GetMessage,'GetMessageA',\ TranslateMessage,'TranslateMessage',\ DispatchMessage,'DispatchMessageA',\ SendMessage,'SendMessageA',\ LoadCursor,'LoadCursorA',\ LoadIcon,'LoadIconA',\ LoadMenu,'LoadMenuA',\ GetClientRect,'GetClientRect',\ MoveWindow,'MoveWindow',\ SetFocus,'SetFocus',\ MessageBox,'MessageBoxA',\ PostQuitMessage,'PostQuitMessage' import gdi,\ CreateFont,'CreateFontA',\ DeleteObject,'DeleteObject' section '.rsrc' resource data readable ; resource directory directory RT_MENU,menus,\ RT_ICON,icons,\ RT_GROUP_ICON,group_icons,\ RT_VERSION,versions ; resource subdirectories resource menus,\ IDR_MENU,LANG_ENGLISH+SUBLANG_DEFAULT,main_menu resource icons,\ 1,LANG_NEUTRAL,icon_data resource group_icons,\ IDR_ICON,LANG_NEUTRAL,main_icon resource versions,\ 1,LANG_NEUTRAL,version menu main_menu menuitem '&File',0,MFR_POPUP menuitem '&New',IDM_NEW menuseparator menuitem 'E&xit',IDM_EXIT,MFR_END menuitem '&Help',0,MFR_POPUP + MFR_END menuitem '&About...',IDM_ABOUT,MFR_END icon main_icon,icon_data,'minipad.ico' versioninfo version,VOS__WINDOWS32,VFT_APP,VFT2_UNKNOWN,LANG_ENGLISH+SUBLANG_DEFAULT,0,\ 'FileDescription','MiniPad - example program',\ 'LegalCopyright','No rights reserved.',\ 'FileVersion','1.0',\ 'ProductVersion','1.0',\ 'OriginalFilename','MINIPAD.EXE' same but via ebp frame Code: WindowProc: RTL_C hwnd,wmsg,wparam,lparam frame ebp push ebx esi edi mov eax,[wmsg] cmp eax,WM_CREATE je .wmcreate cmp eax,WM_SIZE je .wmsize cmp eax,WM_SETFOCUS je .wmsetfocus cmp eax,WM_COMMAND je .wmcommand cmp eax,WM_DESTROY je .wmdestroy .defwndproc: invoke DefWindowProc,[hwnd],[wmsg],[wparam],[lparam] jmp .finish .wmcreate: invoke GetClientRect,[hwnd],client invoke CreateWindowEx,WS_EX_CLIENTEDGE,_edit,0,WS_VISIBLE+WS_CHILD+WS_HSCROLL+WS_VSCROLL+ES_AUTOHSCROLL+ES_AUTOVSCROLL+ES_MULTILINE,[client.left],[client.top],[client.right],[client.bottom],[hwnd],0,[wc.hInstance],NULL or eax,eax jz .failed mov [edithwnd],eax invoke CreateFont,16,0,0,0,0,FALSE,FALSE,FALSE,ANSI_CHARSET,OUT_RASTER_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FIXED_PITCH+FF_DONTCARE,NULL or eax,eax jz .failed mov [editfont],eax invoke SendMessage,[edithwnd],WM_SETFONT,eax,FALSE xor eax,eax jmp .finish .failed: or eax,-1 jmp .finish .wmsize: invoke GetClientRect,[hwnd],client invoke MoveWindow,[edithwnd],[client.left],[client.top],[client.right],[client.bottom],TRUE xor eax,eax jmp .finish .wmsetfocus: invoke SetFocus,[edithwnd] xor eax,eax jmp .finish .wmcommand: mov eax,[wparam] and eax,0FFFFh cmp eax,IDM_NEW je .new cmp eax,IDM_ABOUT je .about cmp eax,IDM_EXIT je .wmdestroy jmp .defwndproc .new: invoke SendMessage,[edithwnd],WM_SETTEXT,0,0 jmp .finish .about: invoke MessageBox,[hwnd],_about_text,_about_title,MB_OK jmp .finish .wmdestroy: invoke DeleteObject,[editfont] invoke PostQuitMessage,0 xor eax,eax .finish: pop edi esi ebx exitf stack_cleanup callee flush_locals and even everything via ebp frame accessing something via esp is still allowed: Code: WindowProc: RTL_C hwnd,wmsg,wparam,lparam frame ebp push ebx esi edi mov eax,[wmsg] cmp eax,WM_CREATE je .wmcreate cmp eax,WM_SIZE je .wmsize cmp eax,WM_SETFOCUS je .wmsetfocus cmp eax,WM_COMMAND je .wmcommand cmp eax,WM_DESTROY je .wmdestroy .defwndproc: via_sp invoke DefWindowProc,[hwnd],[wmsg],[wparam],[lparam] jmp .finish .wmcreate: via_sp invoke GetClientRect,[hwnd],client via_sp invoke CreateWindowEx,WS_EX_CLIENTEDGE,_edit,0,WS_VISIBLE+WS_CHILD+WS_HSCROLL+WS_VSCROLL+ES_AUTOHSCROLL+ES_AUTOVSCROLL+ES_MULTILINE,[client.left],[client.top],[client.right],[client.bottom],[hwnd],0,[wc.hInstance],NULL or eax,eax jz .failed mov [edithwnd],eax invoke CreateFont,16,0,0,0,0,FALSE,FALSE,FALSE,ANSI_CHARSET,OUT_RASTER_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FIXED_PITCH+FF_DONTCARE,NULL or eax,eax jz .failed mov [editfont],eax invoke SendMessage,[edithwnd],WM_SETFONT,eax,FALSE xor eax,eax jmp .finish .failed: or eax,-1 jmp .finish .wmsize: via_sp invoke GetClientRect,[hwnd],client invoke MoveWindow,[edithwnd],[client.left],[client.top],[client.right],[client.bottom],TRUE xor eax,eax jmp .finish .wmsetfocus: invoke SetFocus,[edithwnd] xor eax,eax jmp .finish .wmcommand: via_sp mov eax,[wparam] and eax,0FFFFh cmp eax,IDM_NEW je .new cmp eax,IDM_ABOUT je .about cmp eax,IDM_EXIT je .wmdestroy jmp .defwndproc .new: invoke SendMessage,[edithwnd],WM_SETTEXT,0,0 jmp .finish .about: via_sp invoke MessageBox,[hwnd],_about_text,_about_title,MB_OK jmp .finish .wmdestroy: invoke DeleteObject,[editfont] invoke PostQuitMessage,0 xor eax,eax .finish: pop edi esi ebx exitf stack_cleanup callee flush_locals of cource everything is compilable via fasm with additions described in addition "stack tracing" & result exe is valid. I shrink stack@top complexity to esp & ebp only as usable ones, but macro success operate frame eax, frame ebx and so on if stack@top would have all 8 regs. All my life I never used fasm feature of skipping unused procedures - I never spend time to code procedures which I not going to use, so wrapping procedure head & body into if used block should goes directly if needed. Code: if used WindowProc WindowProc: RTL_C hwnd,wmsg,wparam,lparam ... end if in my concept procedures is not more exists there are only code thunks with localy visibly names ended with flush_locals, that blocks could be started from RTL_C, from LTR_pascal or from locals macros, and in one code thunk can be multuple count of code thunk entries that share single code thunk. |
|||
17 Feb 2023, 23:24 |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.