flat assembler
Message board for the users of flat assembler.

flat assembler > Main > about fasm macro

Author
Thread Post new topic Reply to topic
Step9



Joined: 22 Oct 2018
Posts: 5
Hello:
I'm new to FASM.I'm trying to understand how FASM macro works.
I see the macro define in "macro\com32.inc" as following:
Code:
macro interface name,[proc]
 { common
    struc name \{
    match , @struct \\{ define field@struct .,name, \\}
    match no, @struct \\{ . dd ?
    virtual at 0
   forward
    .#proc dd ?
   common
    .\#\\.com.object = name#.com.interface
    end virtual \\} \}
    virtual at 0
   forward
     name#.#proc dd ?
   common
     name#.com.interface = $ shr 2
    end virtual }
    

I can not understand these macro code.
Can some one give me some hints on what's look like after this macro is expanded?

thanks.
Post 22 Oct 2018, 14:18
View user's profile Send private message Reply with quote
DimonSoft



Joined: 03 Mar 2010
Posts: 553
Location: Belarus
You may want to take a look at prepsrc utility that is provided within FASM package. Compile it and use to analyze how preprocessor sees your progam. The utility takes .fas file as its input and produces a text file as its output. To produce .fas file for your program use Ctrl+F8 if you use FASMW. For me it turned out to be more useful than any explanations in the documentation or this forum. Better once to see than hundred times to hear.
Post 22 Oct 2018, 15:44
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 7310
Location: Kraków, Poland
You can use PREPSRC tool that comes with fasm to take a look at lines generated by the preprocessor.

Take this simple source:
Code:
macro interface name,[proc]
 { common
    struc name \{
    match , @struct \\{ define field@struct .,name, \\}
    match no, @struct \\{ . dd ?
    virtual at 0
   forward
    .#proc dd ?
   common
    .\#\\.com.object = name#.com.interface
    end virtual \\} \}
    virtual at 0
   forward
     name#.#proc dd ?
   common
     name#.com.interface = $ shr 2
    end virtual }

interface ITest,\
           QueryInterface,\
           AddRef,\
           Release

testing ITest    
After assembling it with "-s" option (or Ctrl+F8 in fasmw) you can extract preprocessed source from .FAS file with PREPSRC.

I'm going to comment on the text it generates, to explain what it means.

First, there is the definition of the macro, it is registered by preprocessor but otherwise left untouched. The lines that went through preprocessor but are not then passed to assembler are preceded with semicolon in PREPSRC output:
Code:
;macro interface name,[proc]
;{common
; struc name \{
; match,@struct \\{ define field@struct .,name,\\}
; match no,@struct \\{ . dd ?
; virtual at 0
; forward
; .#proc dd ?
; common
; . \# \\.com.object=name#.com.interface
; end virtual \\} \}
; virtual at 0
; forward
; name#.#proc dd ?
; common
; name#.com.interface=$ shr 2
; end virtual}    


Next, there is the line that calls the macro. This is also seen by preprocessor only and not passed to the assembler:
Code:
;interface ITest,QueryInterface,AddRef,Release    


Next, there are lines generated by this instance of the macro. First there are lines that define STRUC-type macro. Note how FORWARD block is processed for every argument in the list:
Code:
;struc ITest{
; match,@struct \{ define field@struct .,ITest,\}
; match no,@struct \{ . dd ?
; virtual at 0
;
; .QueryInterface dd ?
;
; .AddRef dd ?
;
; .Release dd ?
;
; .#\.com.object=ITest.com.interface
; end virtual \}}    

Then there are some lines that finally generate something for the assembler. Again, there is a FORWARD block to generate DD line for every argument in the list:
Code:
virtual at 0

ITest.QueryInterface dd ?

ITest.AddRef dd ?

ITest.Release dd ?

ITest.com.interface=$ shr 2
end virtual    


Finally, the STRUC-type macro "ITest" is called. This line looks a bit strange, this is because of some quirks of fasm's preprocessor, not important at the moment:
Code:
;testing:;ITest    

The "Itest" macro, as defined above, generates definitions of MATCH blocks, which are in fact a single-use macros:
Code:
;match,@struct{define field@struct testing,ITest,}
;match no,@struct{testing dd ?
; virtual at 0
; testing.QueryInterface dd ?
; testing.AddRef dd ?
; testing.Release dd ?
; testing.com.object=ITest.com.interface
; end virtual}    
And finally the lines generated by the MATCH macro (only the second one got processed, first one did not have a match):
Code:
testing dd ?
virtual at 0
testing.QueryInterface dd ?
testing.AddRef dd ?
testing.Release dd ?
testing.com.object=ITest.com.interface
end virtual    
Post 22 Oct 2018, 15:57
View user's profile Send private message Visit poster's website Reply with quote
Step9



Joined: 22 Oct 2018
Posts: 5
Thanks very much,this is just what I want.
Thank you.
Post 22 Oct 2018, 23:11
View user's profile Send private message Reply with quote
Step9



Joined: 22 Oct 2018
Posts: 5
But still have a question:
I did follow your instruction,but I can't find how the follow macro works:
match , @struct \\{ define field@struct .,name, \\}
match no, @struct \\{ . dd ?
Can you give me som hints on it ?

Thanks
Post 24 Oct 2018, 04:13
View user's profile Send private message Reply with quote
ProMiNick



Joined: 24 Mar 2012
Posts: 353
Location: Russian Federation, Sochi
When line of code located in struct definition variable @struct is defined as blank, outside of struct variable @struct is undefined (value of variable equal to its name).

These lines left macro struct unchanged, but adds ability to declare any struct member as interface.
Post 24 Oct 2018, 07:44
View user's profile Send private message Send e-mail Reply with quote
Step9



Joined: 22 Oct 2018
Posts: 5
Thank you.
But I'm still can not understand clearly.
How to make "match , @struct" condition to be true? What's the "@struct" meaning? or how is it defined?
Post 24 Oct 2018, 13:28
View user's profile Send private message Reply with quote
ProMiNick



Joined: 24 Mar 2012
Posts: 353
Location: Russian Federation, Sochi
Code:
macro struct name
 { virtual at 0
   define @struct ; @struct is defined here as blank
   field@struct equ name
   match child parent, name \{ restore field@struct
                               field@struct equ child,fields@\#parent \}
   sub@struct equ
   struc db [val] \{ \common define field@struct .,db,<val> \}
   struc dw [val] \{ \common define field@struct .,dw,<val> \}
   struc du [val] \{ \common define field@struct .,du,<val> \}
   struc dd [val] \{ \common define field@struct .,dd,<val> \}
   struc dp [val] \{ \common define field@struct .,dp,<val> \}
   struc dq [val] \{ \common define field@struct .,dq,<val> \}
   struc dt [val] \{ \common define field@struct .,dt,<val> \}
   struc rb count \{ define field@struct .,db,count dup (?) \}
   struc rw count \{ define field@struct .,dw,count dup (?) \}
   struc rd count \{ define field@struct .,dd,count dup (?) \}
   struc rp count \{ define field@struct .,dp,count dup (?) \}
   struc rq count \{ define field@struct .,dq,count dup (?) \}
   struc rt count \{ define field@struct .,dt,count dup (?) \}
   macro db [val] \{ \common \local anonymous
                     define field@struct anonymous,db,<val> \}
   macro dw [val] \{ \common \local anonymous
                     define field@struct anonymous,dw,<val> \}
   macro du [val] \{ \common \local anonymous
                     define field@struct anonymous,du,<val> \}
   macro dd [val] \{ \common \local anonymous
                     define field@struct anonymous,dd,<val> \}
   macro dp [val] \{ \common \local anonymous
                     define field@struct anonymous,dp,<val> \}
   macro dq [val] \{ \common \local anonymous
                     define field@struct anonymous,dq,<val> \}
   macro dt [val] \{ \common \local anonymous
                     define field@struct anonymous,dt,<val> \}
   macro rb count \{ \local anonymous
                     define field@struct anonymous,db,count dup (?) \}
   macro rw count \{ \local anonymous
                     define field@struct anonymous,dw,count dup (?) \}
   macro rd count \{ \local anonymous
                     define field@struct anonymous,dd,count dup (?) \}
   macro rp count \{ \local anonymous
                     define field@struct anonymous,dp,count dup (?) \}
   macro rq count \{ \local anonymous
                     define field@struct anonymous,dq,count dup (?) \}
   macro rt count \{ \local anonymous
                     define field@struct anonymous,dt,count dup (?) \}
   macro align    \{ \local anonymous
                     define field@struct anonymous,align, \}
   macro union \{ field@struct equ ,union,<
                  sub@struct equ union \}
   macro struct \{ field@struct equ ,substruct,<
                  sub@struct equ substruct \} }    


Code:
macro ends
 { match , sub@struct \{ 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,struct,align
                         irpv fields,field@struct \\{ restore field@struct
                                                      \\common define fields@struct fields \\}
                         match name tail,fields@struct, \\{ if $
                                                            display 'Error: definition of ',\\`name,' contains illegal instructions.',0Dh,0Ah
                                                            err
                                                            end if \\}
                         match name=,fields,fields@struct \\{ restore @struct ; here @struct defined again to not blank undefined state
                                                              make@struct name,fields
                                                              define fields@\\#name fields \\}
                         end virtual \}
   match any, sub@struct \{ tmp@struct equ field@struct
                            restore field@struct
                            field@struct equ tmp@struct> \}    


so
... here @struct value will be =@struct
Code:
;after use of macro struct, variable @struct became blank
struct MYSTRUC
 a interface IUnknown ; interface will be declared as member of MYSTRUC
;after use of macro ends, variable @struct restored to previos value, in our case again to undefined state equal to =@struct
ends    

... here @struct value will be again =@struct
Code:
a  interface IClassFactory ; here interface will be declared as is    
Post 24 Oct 2018, 15:06
View user's profile Send private message Send e-mail Reply with quote
Step9



Joined: 22 Oct 2018
Posts: 5
Thank you very much.
Post 24 Oct 2018, 20:35
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2019, Tomasz Grysztar.

Powered by rwasa.