flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > CALL return result support for HLL macros [fasmg]

Author
Thread Post new topic Reply to topic
Beege



Joined: 24 Nov 2018
Posts: 13
Location: USA Indiana
Beege 25 Nov 2019, 04:33
Heres an easy addon I made for the HLL macros to support some call return functionality. Its got a couple restrictions but works good for cleaning up code if you got a bunch of .elseif statements depending on a call result.

The restrictrictions are that you can only have one call per .if/.while/.repeat and the call needs to be the first condition that is following one of the following patterns regarding the parentheses. The macro just adds the call and replaces the condition with eax then passes on to original jcondexpr macro so any additional conditions specified after the call work as they normally would. All the patterns below that have parentheses also support boolean if wanted and could have additional check conditions added on to them and also support the negation operator as in the examples:
Code:
.if (callconv _add, a,b) = c
.if callconv(_add, a,b) = c
.if (callconv(_add, a,b) = c)

no parentheses needed for boolean only:
.if callconv _add, a,b    

Examples/testing:
Code:
mov ebx, 3
mov esi, 5

.if (stdcall _add,5,5) ; boolean check
.endif
.if (stdcall _add,5,5) = 10; compare check
.endif
.if (stdcall _add,5,5) = 10 & (ebx=5 | esi) & esi=5 ; compare + additional
.endif
.if (stdcall _add,5,5) & (ebx=5 | esi) & esi=5 ; boolean + additional
.endif

.if stdcall(_add,5,5)
.endif
.if stdcall(_add,5,5) = 10
.endif
.if stdcall(_add,5,5) = 10 & (ebx | esi=4) & esi=5
.endif
.if stdcall(_add,5,5) & (ebx | esi=4) & esi=5
.endif

.if (stdcall(_add,5,5))
.endif
.if (stdcall(_add,5,5) = 10)
.endif
.if (stdcall(_add,5,5) = 10) & (ebx | esi=4) & esi=5
.endif
.if (stdcall(_add,5,5)) & (ebx | esi=4) & esi=5
.endif

.if stdcall _add,5,5 ; boolean 
.endif

.if ~(stdcall _add,5,-5)
.endif
.if ~stdcall(_add,5,5) <> 10
.endif
.if ~stdcall(_add,5, stdcall _add, ebx, stdcall _add,esi,stdcall _add,-5,5) <> 13 & (ebx=33|esi=5) & esi=5 
.endif

xor ebx, ebx
.while (stdcall _add,1,ebx) < 10
        inc ebx
.endw

xor ebx, ebx
.repeat
        inc ebx
.until stdcall(_add,1,ebx) > 10

proc _add, i1, i2
   mov eax, dword[i1]
   add eax, dword[i2]
   ret
endp    

Please let me know if you see any issues or some syntax Im not thinking about. Improvements are very much welcome as well. Thanks

Edit: Fixes and added support for negation operator and no parentheses boolean only pattern.


Description:
Download
Filename: ifex.inc
Filesize: 2.42 KB
Downloaded: 549 Time(s)



Last edited by Beege on 08 Dec 2019, 04:37; edited 2 times in total
Post 25 Nov 2019, 04:33
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8351
Location: Kraków, Poland
Tomasz Grysztar 25 Nov 2019, 09:26
Beege wrote:
I dont exactly understand why I had to use "rawmatch" here to detect the calls when it didnt have to be used in proc32.inc.
I understand it even less, because your macro appears to work for me when I replace them all with regular MATCH.

The RAWMATCH is very rarely the right directive to use, because it strips the text of all the context information, and therefore it is applicable only to some specific corner case. When you really need to use RAWMATCH, you should know why.

Apart from context-stripping (which is the main feature of RAWMATCH) it also differs from MATCH in that it does not replace symbolic variables with their values before matching. Perhaps this was the source of the problem?

If you need to not replace values before matching, you can do it the same way that was used in fasm 1 - with a proxy variable made with DEFINE (note that it needs to be DEFINE and not EQU, because EQU replaces symbolic values before assignment, so it would gain us nothing):
Code:
local PROXY
define PROXY full_condition
match =( =stdcall? rest, PROXY    
(Another small detail: you do not need to put "=" before "(" in the pattern. "(" is a token character and these are mostly matched literally anyway, so "=" is redundant there.)

Finally, I may recommend a trick that actually utilizes the fact that MATCH replaces symbolic variables with their values. By defining symbolic constants in a special namespace you can easily detect all of the calling convention words with just a single MATCH:
Code:
define __callconv
define __callconv.stdcall? *stdcall
define __callconv.invoke? *invoke
define __callconv.ccall? *ccall
define __callconv.cinvoke? *cinvoke
define __callconv.call? *call

macro _ifex jmplbl, full_condition&
        local callfound,newcond

        callfound = 0
        match *any, __callconv.full_condition
                callfound = 1
        else match (tail, full_condition
                match *any, __callconv.tail
                        callfound = 1
                end match
        end match

        define newcond full_condition

        ; ...    
Note that this trick is described and recommended in the "What are the means of parsing the arguments of an instruction?" section of Introduction to fasmg.
Post 25 Nov 2019, 09:26
View user's profile Send private message Visit poster's website Reply with quote
Beege



Joined: 24 Nov 2018
Posts: 13
Location: USA Indiana
Beege 26 Nov 2019, 06:39
Quote:

I understand it even less, because your macro appears to work for me when I replace them all with regular MATCH.


This drove me nuts when I read it but figured out at least how I got on the rawmatch path and possibly how this still worked for you. The code I have above assumes win32a.inc or a least the macros searched for are included prior in the code. Any of the macros that have a "define" at the top of the include (ex "define stdcall?) get skipped in the match statement I was testing with but show up with the rawmatch so thats how I got myself confused.

So for example:
Code:
define stdcallw?
macro _ifex full_condition&
                match a b c, full_condition
                        display "-match-",13,10,"a=",`a,13,10,"b=",`b,13,10,"c=",`c,13,10,13,10
                end match
                rawmatch a b c, full_condition
                        display "-rawmatch-",13,10,"a=",`a,13,10,"b=",`b,13,10,"c=",`c,13,10
                end rawmatch
end macro
_ifex (stdcallw _testfunc, 1)
    


Gives me an output like so:
Code:
-match-
a=(
b=_testfunc
c=, 1)

-rawmatch-
a=(
b=stdcallw
c=_testfunc, 1)    


Thank you very much for the additional corrections and recommendations. I will definitely be implementing that last trick. Its exactly what I needed here
Post 26 Nov 2019, 06:39
View user's profile Send private message Reply with quote
Beege



Joined: 24 Nov 2018
Posts: 13
Location: USA Indiana
Beege 03 Dec 2019, 04:15
Quote:

I understand it even less, because your macro appears to work for me when I replace them all with regular MATCH.

Tomasz, this issue I ran into where MATCH can not detect keyword "stdcall" (and lead me down the RAWMATCH path) is currently effecting the original stdcall macro defined in proc32.inc in the same way. This can be seen if you try and do a nested call. The other call conventions are fine, its just stdcall
Code:
stdcall _add, 3, stdcall _add,3,3
ccall _add, 3, ccall _add,3,3
    

gives a listing/disassembly of:
Code:
00000005: 6A 03 6A 24 E8 16 00 00 
          00                      stdcall _retme, stdcall _retme, 3

0:  6a 03               push   0x3
2:  6a 24               push   0x24
4:  e8 16 00 00 00      call   0x1f


0000000E: 6A 03 E8 0F 00 00 00 50 
          E8 09 00 00 00 83 C4 08 ccall _retme, ccall _retme, 3

0:  6a 03               push   0x3
2:  e8 0f 00 00 00      call   0x16
7:  50                  push   eax
8:  e8 09 00 00 00      call   0x16
d:  83 c4 08            add    esp,0x8
    

A proxy variable could be used to fix this Very Happy , but my guess is renaming the symbol for push_string macro will end up being fix here. That or Im down a wrong path again and incorrect about all of this.
.
Post 03 Dec 2019, 04:15
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8351
Location: Kraków, Poland
Tomasz Grysztar 03 Dec 2019, 08:22
Beege wrote:
A proxy variable could be used to fix this Very Happy , but my guess is renaming the symbol for push_string macro will end up being fix here.
Both methods would fix it, but I think I'm going to change the definition in proc32.inc because this way you may still be able to define aliases.
Post 03 Dec 2019, 08:22
View user's profile Send private message Visit poster's website Reply with quote
Beege



Joined: 24 Nov 2018
Posts: 13
Location: USA Indiana
Beege 04 Dec 2019, 03:48
Tomasz Grysztar wrote:
Both methods would fix it, but I think I'm going to change the definition in proc32.inc because this way you may still be able to define aliases.

Fixed with one word! Surprised Thats sweet! and way less modifications than what I was thinking had to happen. Thank you for the easy fix

I was looking over all the match statements in proc32.inc searching for stdcall and noticed lines 252 and 255 both are matching a literal c. Are these meant to say =ccall?

EDIT: NOPE! Found in documentation "The name of procedure can be also followed by either the stdcall or c keyword to define the calling convention it uses."
Post 04 Dec 2019, 03:48
View user's profile Send private message Reply with quote
Beege



Joined: 24 Nov 2018
Posts: 13
Location: USA Indiana
Beege 08 Dec 2019, 04:57
First post has been updated with primary macro below with all the recommendations and also added support for negation operator plus one more pattern requiring no parentheses if you only need a boolean check.
Code:
macro _ifex jmplbl, cond&
        local cond_proxy,neg,callfound

        ;check if first token is "~" (negation) operator
        match ~negcond, cond
                define cond_proxy negcond
                neg equ ~
        else
                define cond_proxy cond
                neg equ
        end match

        ;search for call convention usage from __callconv keyword list
        callfound = 0
        match head tail, cond_proxy
                match *any, __callconv.head
                        callfound = 1
                else match (, head
                        match *any, __callconv.tail
                                callfound = 1
                        end match
                end match
        end match

        ;execute call and swap call with eax
        if callfound = 1
                ;cc = call convention
                ;fa = function to call with arguments
                ;ov = condition operator and value to compare and/or additional conditions
                ;rc = remaining conditions
                match (cc(fa)ov)rc, cond_proxy ;                .if (stdcall(_add,5,5) = 10) & (ebx | esi=4) & esi=5
                        cc fa
                        jcondexpr jmplbl,1,(neg eax ov rc) ;
                else match (cc(fa)ov), cond_proxy ;             .if (stdcall(_add,5,5) = 10)
                        cc fa
                        jcondexpr jmplbl,1,(neg eax ov) ;
                else match (cc(fa)), cond_proxy ;               .if (stdcall(_add,5,5))
                        cc fa
                        jcondexpr jmplbl,1,(neg eax) ;
                else match (cc fa)ov, cond_proxy;               .if (stdcall _add,5,5) = 10 & (ebx | esi=4) & esi=5
                        cc fa
                        jcondexpr jmplbl,1,(neg eax ov)
                else match (cc fa), cond_proxy ;                .if (stdcall _add,5,5)
                        cc fa
                        jcondexpr jmplbl,1,(neg eax)
                else match cc(fa)ov, cond_proxy ;               .if stdcall(_add,5,5) = 10 & (ebx | esi=4) & esi=5
                        cc fa
                        jcondexpr jmplbl,1,(neg eax ov)
                else match cc(fa), cond_proxy ;                 .if stdcall(_add,5,5)
                        cc fa
                        jcondexpr jmplbl,1,(neg eax)
                else match cc fa, cond_proxy ;                  .if stdcall _add,5,5 ; boolean only
                        cc fa
                        jcondexpr jmplbl,1,(neg eax)
                end match
        else
                jcondexpr jmplbl,1,cond
        end if

end macro    
Post 08 Dec 2019, 04:57
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-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.