flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > Macro parameters for constant literals and variable

Goto page 1, 2  Next
Author
Thread Post new topic Reply to topic
fasmnewbie



Joined: 01 Mar 2011
Posts: 555
fasmnewbie 05 Aug 2013, 10:42
Hi people. I try to develop a super simple macro for COM that can take both a constant literal and a variable to print the value in hex, under one single parameter a

Code:
macro prthex a
{
   ;what to do or to use here?
   
   ;code for conversions
        pusha
        xor si, si
        
        mov si, a
        xor ax, ax
        mov ax, word[si]
        xor bx, bx
        mov bx, word[si+2]
        prtReg bx
        prtReg ax
        prtc 'H'
        popa
}

prthex 100h   ; a const literal
prthex myHEX ; a var

pquit
myHEX dd 100h    


The problem is that it works only for a variable and not if a is constant literal. But if I tried this code below, the result is the reverse... only constant works.. while the variable shows some funny result.

Code:
macro prthex a
{
        pusha
        local ..b
        xor si, si

        ;OPTION 1
        jmp @f
            ..b dd a
        @@:
        ;OPTION 2
        ;label b dword
        ;      dd a
        mov si, ..b
        ;mov si, a ;replace with b if other options
        xor ax, ax
        mov ax, word[si]
        xor bx, bx
        mov bx, word[si+2]
        prtReg bx
        prtReg ax
        prtc 'H'
        popa

}    


Is there any if settings or FASM features that can be used or is it even possible to do? I tried defined and eqtype but none worked.

If you are interested in testing the code, this is the macro file I use
Code:
;'macro16.inc'
macro prtReg a
{
        pusha
        local .go, .done, ..hextab
        mov cx, a
        xor si, si
        xchg ch, cl

        .go:
        mov bx, ..hextab
        ;Get the nibbles
        mov dl, cl
        mov dh, ch
        and cl, 0Fh
        and dl, 0F0h
        shr dl, 4
        ;Digit Translations
        mov al, dl
        xlat [bx]
        prtc al
        mov al, cl
        xlat [bx]
        prtc al
        inc si
        xor bx, bx
        cmp si, 2
        je .done
        xor bx, bx
        mov cl, dh ;get the other half
        jmp .go
        ..hextab db '0123456789ABCDEF'
        .done:
        popa
}
macro pquit
{
        mov ah,0h
        int 16h
        int 20h
}
macro prtc a
{
     push ax
     mov ah, 0eh
     if ~ a eq al ;prevent perfect
        mov al, a ;nop for mov al, al
     end if
     int 10h
     pop ax
}    


Thank you very much for your advises and comments.
Post 05 Aug 2013, 10:42
View user's profile Send private message Visit poster's website Reply with quote
shutdownall



Joined: 02 Apr 2010
Posts: 517
Location: Munich
shutdownall 05 Aug 2013, 12:24
That's quite easy to understand.
You are using a constant and a label (address) of a (possibly) constant.
That's not really the same.

Code:
prthex 100h   ; a const literal
prthex myHEX ; a var

pquit
myHEX dd 100h
    


In the first example your variable "a" is 100h and in the second call your variable "a" is the address of value 100h anywhere in memory.

So you can print "a" directly in the first example and have to use indirectly in second example.

Code:
mov si,a
mov ax,si
print ax 
(works for constant)

mov si,a
mov ax,[si]
print ax
(works for label)
    


To distinguish both in a macro you can use the example in this thread and handle it differently:

http://board.flatassembler.net/topic.php?t=14987

Code:
ThisIsConst = 10
ThisIsLabel:

if ThisIsConst relativeto $
  display "Label"
else
  display "Constant"
end if
    


I am not perfect in macros but someone could help you with distinguishing between constants and labels.
Post 05 Aug 2013, 12:24
View user's profile Send private message Send e-mail Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 555
fasmnewbie 05 Aug 2013, 13:19
Thanks for the reply shutdownall.

From what I debugged, my numeric constant "a" is passed to the macro as an address not as a value I am interested in displaying. So what I do is transform it (the constant) into a label inside the macro hoping that it would be addressable as a label from then on.

Code:
macro prthex a
{
    pusha
    local ..b   ;creates a local label for a
    
    jmp @f
      ..b dd a ;transform it into a local label and...
    
    @@: 
    mov si, ..b ; ..collect the address
    ...
}

prthex 256d         ;prints fine
prthex myhex      ;prints whatever
pquit 
myhex dd 256d
    


This is the point where this code gets the correct address of "..b" if my "a" was originally a constant. By using this option however, the other "a" real label passed to it will produce incorrect result. Kind of a classic "ying-yang" problem to me Laughing

I think this could be done by using an IF to distinguish between the two, but since I am not that advanced, for now, I have to use two different macros for displaying each. That "relativeto" example didn't work either.
Post 05 Aug 2013, 13:19
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 555
fasmnewbie 05 Aug 2013, 13:50
Just to make the problem clearer

Code:
macro prthex a
{
        pusha 
        xor si, si 
        
        if /a is a constant/ 
              ;steps necessary to make it addressable
              ;put the address into SI
              ;mov si, b 
        else
              ;just use the address and put into SI
              ; mov si, a
        end if
         
        xor ax, ax 
        mov ax, word[si] 
        xor bx, bx 
        mov bx, word[si+2] 
        prtReg bx 
        prtReg ax 
        prtc 'H' 
        popa 
}    


I am hoping that somebody can show me that IF part so that I don't have to come up with two different macros for printing a constant and a label parameter.

TQVM for your kind replies.
Post 05 Aug 2013, 13:50
View user's profile Send private message Visit poster's website Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 881
l_inc 06 Aug 2013, 15:10
fasmnewbie
Your problem is still not clear. Imagine, you're a macro. And I give you an argument 0x800 . Is it a constant or a variable address?
The answer is: it can be both. Thus you in fact need either different macros or a way to tell your single macro, how to handle the passed value.

Here's an example of a C-like syntax:
Code:
macro prthex a
{
        define address +
        define address -
        match *val,a \{
                restore address
                display \`val\#' is an address',13,10
        \}
        match -,address \{
                restore address
                display \`a\#' is a constant',13,10
        \}
        restore address
}
prthex 0x800
prthex *0x800    

_________________
Faith is a superposition of knowledge and fallacy
Post 06 Aug 2013, 15:10
View user's profile Send private message Reply with quote
dogman



Joined: 18 Jul 2013
Posts: 114
dogman 06 Aug 2013, 19:27
There are a couple ways this is usually done but I have no idea if fasm or any Intel assembler supports this. First you could use keywords and invoke the macro with different keywords depending on whether it's a constant or address. prthex addr=something or prthex constant. The other thing is if the macro language can see the symbol table then it can offer some way of querying the type of operand without a keyword in many cases and you create conditional code based on that. fasm's macro language is intergrated with the assembler, correct? Theoretically it could support this then if it can see the symbol table.
Post 06 Aug 2013, 19:27
View user's profile Send private message Reply with quote
BAiC



Joined: 22 Mar 2011
Posts: 272
Location: California
BAiC 07 Aug 2013, 11:06
you have dereferencing a pointer/address mixed up with reading its address. when you use the macro you need to dereference the address with brackets like this:
Code:
prthex 100h   ; a const literal
prthex [myHEX] ; a var     

the macro code will then use eqtype to distinguish between the types.
Code:
macro testing inp
{
    if (inp eqtype [0]) | (inp eqtype eax)
        ;code for variable
        display 'variable'
    end if

    if inp eqtype 0
        ;code for constant
        display 'constant'
    endif
}

testing [0]
testing eax
testing 123
    

_________________
byte me.
Post 07 Aug 2013, 11:06
View user's profile Send private message Visit poster's website Reply with quote
shutdownall



Joined: 02 Apr 2010
Posts: 517
Location: Munich
shutdownall 07 Aug 2013, 16:23
BAiC wrote:
you have dereferencing a pointer/address mixed up with reading its address. when you use the macro you need to dereference the address with brackets like this:
Code:
prthex 100h   ; a const literal
prthex [myHEX] ; a var     

the macro code will then use eqtype to distinguish between the types.


Yes, that's it.
You should know it when placing the parameter to the macro.

Internally in fasm labels are definetely coded different to constants.
But I am not sure if there is (by 'now') a possibility to test a macro parameter on it's type.
Eqtype could be a candidate for this and would be probably the best.
Post 07 Aug 2013, 16:23
View user's profile Send private message Send e-mail Reply with quote
shutdownall



Joined: 02 Apr 2010
Posts: 517
Location: Munich
shutdownall 07 Aug 2013, 16:51
By the way - it does work this way.
Here is an example:

Code:
                                        macro prthex a
                                        {
                                          virtual
                                          @@: dw 0
                                          end virtual
                                          if a eqtype @b
                                            db 0
                                          else
                                            db 1
                                          end if
                                        }
                                        
0000: [0000] 00 00                      lab1   dw 0
0002: [0002] 00 00 00 00                lab2   dd 0
                                        
0006: [0006] 01                                 prthex [lab1]
0007: [0007] 01                                 prthex [lab2]
0008: [0008] 00                                 prthex 0
    


I did put the listing as it shows more detailed what happen.
First you define a (anonymous) label in your macro (@@).
Then you make a eqtype between the variable a and the anonymous label (referenced with @b).
This will put either a databyte 0 if a is any label and databyte 1 if a is any constant.

This isn't necessary for your code anymore as a holds the contents of the labels already but this could be helpful maybe for some other issues when distingushing between label and constant.


And by the way, why do you always clear register before loading it ? This is not neccessary and has no effect.
Wink

Code:
xor ax,ax
mov ax,si
    
Post 07 Aug 2013, 16:51
View user's profile Send private message Send e-mail Reply with quote
BAiC



Joined: 22 Mar 2011
Posts: 272
Location: California
BAiC 07 Aug 2013, 18:14
shutdownall: you should avoid using @@ in macros since it will interfere with something like the following:
Code:
@@: ;continue label.
macro_invocation
jmp @b    

this type of bug is very difficult to debug.

FASMs eqtype doesn't distinguish between labels and constants so you don't need an anonymous label. you can simply use 0.
Post 07 Aug 2013, 18:14
View user's profile Send private message Visit poster's website Reply with quote
dogman



Joined: 18 Jul 2013
Posts: 114
dogman 07 Aug 2013, 18:53
shutdownall wrote:
And by the way, why do you always clear register before loading it ? This is not neccessary and has no effect.
Wink

Code:
xor ax,ax
mov ax,si
    


Oh it definitely has an effect. It makes his code run 90% slower Razz

_________________
Sources? Ahahaha! We don't need no stinkin' sources!
Post 07 Aug 2013, 18:53
View user's profile Send private message Reply with quote
shutdownall



Joined: 02 Apr 2010
Posts: 517
Location: Munich
shutdownall 07 Aug 2013, 21:06
BAiC wrote:

FASMs eqtype doesn't distinguish between labels and constants so you don't need an anonymous label. you can simply use 0.

I wouldn't say that for all cases.
It does distinguish between constants and memory locations referenced by labels.
Didn't you check my example ? Wink
Post 07 Aug 2013, 21:06
View user's profile Send private message Send e-mail Reply with quote
BAiC



Joined: 22 Mar 2011
Posts: 272
Location: California
BAiC 07 Aug 2013, 22:54
shutdownall: of course eqtype distinguishes between 0 and [0], that's not the point! eqtype does NOT distinguish between "label:" and "label = $".
Post 07 Aug 2013, 22:54
View user's profile Send private message Visit poster's website Reply with quote
shutdownall



Joined: 02 Apr 2010
Posts: 517
Location: Munich
shutdownall 08 Aug 2013, 19:55
If you refer to previous answers you don't have to repeat my name. Razz

eqtype distinguishes between constants and memory references (address expressions).
And that's GREAT. Cool
Post 08 Aug 2013, 19:55
View user's profile Send private message Send e-mail Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 555
fasmnewbie 10 Aug 2013, 12:59
Ok guys thanks for the participation...

I think I have to narrow down the real problem in question...

Code:
org 100h
include 'macro16.inc'
macro test a
{
        pusha
        local ..b, .go
        xor si, si

        jmp @f
        ..b dd a
        @@:
        ;push [..b] ;works for label
        ;push ..b   ;works for constant

        if ~ defined a   ;what conditions here?
           push [..b] ;for label
        else
           push ..b ;for constant
        end if

        pop si
        mov ax, word[si]
        mov bx, word[si+2]
        prtr bx, -n
        prtr ax, -n
        popa
}
test mydata
line
test 500d ;1F4h

pquit
mydata dd 500d ;1F4H    


See the problem there is getting the correct conditions for that IF so that it can take the correct course. Without the proper conditional setup, I have to alternate between the two commented lines previously for displaying each (a.k.a two different macros) correctly. I have also updated the macro file so that you can test the code yourself.

Code:
;Part of macro16.inc
;fl = -n. Do not print the reg's name
macro prtr [a,fl]
{
        local .go, .done, ..hextab, .prttext
        pusha
        ;..hextab db '0123456789ABCDEF'
        mov cx, a
        xor si, si
        xchg ch, cl

        if fl eq -n
           jmp .go
        end if

        .prttext:
        if a eq ax
           prts "AX:"
        else if a eq bx
           prts "BX:"
        else if a eq cx
           prts "CX:"
        else if a eq dx
           prts "DX:"
        else if a eq si
           prts "SI:"
        else if a eq di
           prts "DI:"
        else if a eq sp
           prts "SP:"
        else if a eq bp
           prts "BP:"
        else if a eq cs
           prts "CS:"
        else if a eq ds
           prts "DS:"
        else if a eq ss
           prts "SS:"
        else if a eq es
           prts "ES:"
        end if

        .go:
        mov bx, ..hextab
        ;Get the nibbles
        mov dl, cl
        mov dh, ch
        and cl, 0Fh
        and dl, 0F0h
        shr dl, 4
        ;Digit Translations
        mov al, dl
        xlat [bx]
        prtc al
        mov al, cl
        xlat [bx]
        prtc al
        inc si
        xor bx, bx
        cmp si, 2
        je .done
        xor bx, bx
        mov cl, dh ;get the other half
        jmp .go
        ..hextab db '0123456789ABCDEF'
        .done:
        ;prtc 'H'
        popa
        ;..hextab db '0123456789ABCDEF'
}
macro line
{
        push ax
        mov ah, 0eh
        mov al, 0dh
        int 10h
        mov al, 0ah
        int 10h
        pop ax
}
macro pquit
{
        mov ah,0h
        int 16h
        int 20h
        ;mov ah, 4ch
        ;int 21h
}    


Thank you in advance for your kind replies.

EDIT: Sorry, I forgot to include the prts and prtc macros ... Here they are;

Code:
;Prints both type of string
macro prts a
{
        if a eqtype ''
           prtCStr a
        else
           prtStr a
        end if
}
;Prints constant string
macro prtCStr [a]
{
    pusha
    local .go, ..b, .ok

    xor si,si
    mov si,..b
    .go:
        cmp byte[si],0
        je .ok
        prtc byte[si]
        inc si
    jmp .go
    ..b db a, 0
    .ok:
    popa
}
;[var]. Data type db
;0-ended
macro prtStr a
{
     push ax
     mov ah,0eh
     mov si,a
     local .loop, .done, .b

     .loop:
     cmp byte[si],0
     je .done
     mov al,[si]
     int 10h
     add si,1
     jmp .loop

     .done:
     pop ax
}
macro prtc a
{
     push ax
     mov ah, 0eh
     if ~ a eq al ;prevent perfect
        mov al, a ;nop for mov al, al
     end if
     int 10h
     pop ax
}    


Last edited by fasmnewbie on 10 Aug 2013, 17:33; edited 3 times in total
Post 10 Aug 2013, 12:59
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 555
fasmnewbie 10 Aug 2013, 13:07
l_inc wrote:
fasmnewbie
Your problem is still not clear. Imagine, you're a macro. And I give you an argument 0x800 . Is it a constant or a variable address?
The answer is: it can be both. Thus you in fact need either different macros or a way to tell your single macro, how to handle the passed value.

Here's an example of a C-like syntax:
Code:
macro prthex a
{
        define address +
        define address -
        match *val,a \{
                restore address
                display \`val\#' is an address',13,10
        \}
        match -,address \{
                restore address
                display \`a\#' is a constant',13,10
        \}
        restore address
}
prthex 0x800
prthex *0x800    


Hi I_inc

That macro works but the answer is persistent for one particular value (label) only. I can't display two different values for the same run. And the macro is way too advance for my "almost-flat" learning curve Twisted Evil

Thank you for such a nice code.
Post 10 Aug 2013, 13:07
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 555
fasmnewbie 10 Aug 2013, 13:08
dogman wrote:
There are a couple ways this is usually done but I have no idea if fasm or any Intel assembler supports this. First you could use keywords and invoke the macro with different keywords depending on whether it's a constant or address. prthex addr=something or prthex constant. The other thing is if the macro language can see the symbol table then it can offer some way of querying the type of operand without a keyword in many cases and you create conditional code based on that. fasm's macro language is intergrated with the assembler, correct? Theoretically it could support this then if it can see the symbol table.


Thank you for your input.
Post 10 Aug 2013, 13:08
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 555
fasmnewbie 10 Aug 2013, 13:13
shutdownall wrote:
By the way - it does work this way.
Here is an example:

Code:
                                        macro prthex a
                                        {
                                          virtual
                                          @@: dw 0
                                          end virtual
                                          if a eqtype @b
                                            db 0
                                          else
                                            db 1
                                          end if
                                        }
                                        
0000: [0000] 00 00                      lab1   dw 0
0002: [0002] 00 00 00 00                lab2   dd 0
                                        
0006: [0006] 01                                 prthex [lab1]
0007: [0007] 01                                 prthex [lab2]
0008: [0008] 00                                 prthex 0
    


I did put the listing as it shows more detailed what happen.
First you define a (anonymous) label in your macro (@@).
Then you make a eqtype between the variable a and the anonymous label (referenced with @b).
This will put either a databyte 0 if a is any label and databyte 1 if a is any constant.

This isn't necessary for your code anymore as a holds the contents of the labels already but this could be helpful maybe for some other issues when distingushing between label and constant.


And by the way, why do you always clear register before loading it ? This is not neccessary and has no effect.
Wink

Code:
xor ax,ax
mov ax,si
    


I am still struggling to learn that virtual stuff. But thank you for that effort. I learned a thing or two from that listing.

For that xor ax, ax part, well... I am a newbie.. with lots of insecurity in mind. Just wanted to make sure that my entire porn collections don't pop up suddenly in the other half of the register Twisted Evil
Post 10 Aug 2013, 13:13
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 555
fasmnewbie 10 Aug 2013, 13:17
BAiC wrote:
you have dereferencing a pointer/address mixed up with reading its address. when you use the macro you need to dereference the address with brackets like this:
Code:
prthex 100h   ; a const literal
prthex [myHEX] ; a var     

the macro code will then use eqtype to distinguish between the types.
Code:
macro testing inp
{
    if (inp eqtype [0]) | (inp eqtype eax)
        ;code for variable
        display 'variable'
    end if

    if inp eqtype 0
        ;code for constant
        display 'constant'
    endif
}

testing [0]
testing eax
testing 123
    


Thanks for the input.
Post 10 Aug 2013, 13:17
View user's profile Send private message Visit poster's website Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 881
l_inc 10 Aug 2013, 17:28
fasmnewbie
Quote:
I can't display two different values for the same run.

First of all, why not? Look:
Code:
macro test a
{
        pusha
        local ..b, .go
        xor si, si

        ;push dword [..b] ;works for label
        ;push dword ..b   ;works for constant

        define address +
        define address -
        match *val,a \{
            restore address
            jmp @f
                ..b dd val
            @@:
            push dword [..b]
        \}
        match -,address \{
            restore address
            jmp @f
                ..b dd a
            @@:
            push dword ..b
        \}
        restore address

        pop si
        .go:
        xor ax, ax
        mov ax, word[si]
        xor bx, bx
        mov bx, word[si+2]
        prtr bx, -n
        prtr ax, -n
        popa
}

test 500d ;1F4h 
line 
test *mydata 

pquit 
mydata dd 500d ;1F4H    

That's what you could do.

But your approach is from the beginning is veeery wrong. Firstly, you should start using functions/procedures instead of (or at least together with) macros. Otherwise your code will be bloated with replicated code parts. That's not what macros are intended for. Secondly, your code is full of meaningless and wrong things. Why do you push dword and pop a word (with pop si)? Why do you put the a value into memory at all, if you just need to put it into the ax and bx registers? Why do you sometimes use a single dot prefix and sometimes double dot (your differentiation of those is wrong)? And many more.

_________________
Faith is a superposition of knowledge and fallacy
Post 10 Aug 2013, 17:28
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page 1, 2  Next

< 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-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.