flat assembler
Message board for the users of flat assembler.

Index > Main > invoke and fastcall macro (x64)

Author
Thread Post new topic Reply to topic
Hotwire



Joined: 17 Sep 2015
Posts: 14
Hotwire
Hello there!

I want to understand properly all the macroses involved in coding process with fasm.
Macroses like invoke and fastcall are pretty long and hard to understand after reading fasm manual. I would be very thankful if someone could add comments to those macroses.

Many thanks in advance
Post 20 Dec 2021, 19:24
View user's profile Send private message Visit poster's website Reply with quote
ProMiNick



Joined: 24 Mar 2012
Posts: 656
Location: Russian Federation, Sochi
ProMiNick
let I explain on another variant
Code:
macro invoke proc,[arg]
 { common fastcall [proc],arg }

macro detect@argsize arg {
    define type@param
    define definition@param arg
    match =float value,definition@param
    \{ define definition@param value
       define type@param float \}
    match =addr value,definition@param
    \{ define definition@param value
       define type@param addr \}
    match param,definition@param
    \{ local opcode,origin
       size@param = 0
       if param eqtype 0 | param eqtype 0f | type@param eq addr
        size@param = 8
       else if param eqtype byte 0 | param eqtype byte 0f
        match prefix value,definition@param
         \\{ if prefix eq qword
              size@param = 8
             else if prefix eq dword
              size@param = 4
             else if prefix eq word
              size@param = 2
             else if prefix eq byte
              size@param = 1
             end if \\}
       else if ~ param in <xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7,xmm8,xmm9,xmm10,xmm11,xmm12,xmm13,xmm14,xmm15>
        virtual
         origin = $
         inc param
         load opcode byte from origin
         if opcode = 67h | opcode = 41h
          load opcode byte from origin+1
         end if
         if opcode and 0F8h = 48h
          size@param = 8
         else if opcode = 66h
          size@param = 2
         else if opcode = 0FFh
          size@param = 4
         else
          size@param = 1
         end if
        end virtual
       end if \}
}

macro __mov reg,src,regd,regw,regb,regxmm {
        detect@argsize src
        match param,definition@param \{
                if type@param eq float
                        if ~ param eq regxmm
                                if size@param = 4
                                        if param eqtype byte 0 | param eqtype byte 0f
                                                mov eax,param
                                                movd regxmm,eax
                                        else
                                                movd regxmm,param
                                        end if
                                else
                                        if param eqtype 0 | param eqtype 0f | param eqtype byte 0 | param eqtype byte 0f
                                                mov rax,param
                                                movq regxmm,rax
                                        else
                                                movq regxmm,param
                                        end if
                                end if
                        end if
                        if vararg@fastcall & ~ param eq reg
                                movq reg,regxmm
                        end if
                else if type@param eq addr
                        if ~ param eq reg
                                lea reg,[param]
                        end if
                else if size@param = 8
                        if ~ param eq reg
                                mov reg,param
                        end if
                else if size@param = 4
                        if ~ param eq regd
                                mov regd,param
                        end if
                else if size@param = 2
                        if ~ param eq regw
                                mov regw,param
                        end if
                else if size@param = 1
                        if ~ param eq regb
                                mov regb,param
                        end if
                end if \} }

macro __push arg {
        detect@argsize arg
        match param,definition@param \{
                if type@param eq addr
                        lea     rax,[param]
                        push    rax
                else if param eqtype [0] | param eqtype byte [0]
                        if size@param = 8
                                mov     rax,param
                                push    rax
                        else if size@param = 4
                                mov     eax,param
                                push    rax
                        else if size@param = 2
                                mov     ax,param
                                push    rax
                        else
                                mov     al,param
                                push    rax
                        end if
                else if size@param = 8
                        virtual
                                origin = $
                                mov     rax,param
                                load opcode byte from origin+1
                        end virtual
                        if opcode = 0B8h
                                mov     rax,param
                                push    rax
                        else
                                push    param
                        end if
                else if param in <xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7,xmm8,xmm9,xmm10,xmm11,xmm12,xmm13,xmm14,xmm15>
                        movq    rax,param
                        push    rax
                else
                        mov     eax,param
                        push    rax
                end if \} }

macro fastcall proc,torcx:rcx,tordx:rdx,tor8:r8,tor9:r9,[arg] {
 common local stackspace,argscount,counter
        counter = 4
        if ~arg eq
                if argscount and 1
                        sub     esp,8
                end if
 reverse
        counter = counter + 1
        __push arg
 common
        end if
        argscount = counter
        stackspace = ((argscount and 1) + argscount)*8
        if stackspace
                sub rsp,4*8;stackspace
        end if

        __mov r9,tor9,r9d,r9w,r9b,xmm3
        __mov r8,tor8,r8d,r8w,r8b,xmm2
        __mov rdx,tordx,edx,dx,dl,xmm1
        __mov rcx,torcx,ecx,cx,cl,xmm0

        call proc
        if stackspace & ~defined current@frame
                add rsp,stackspace
        end if }

macro proc [args]
 { common
    match name params, args>
    \{ define@proc name,<params \} }     

first four params (in linux first six, rsi, rdi added) goes to rcx,rdx,r8,r9, in case of floats via xmm0.xmm1,xmm2,xmm3 respectively.
like in x32 first of all in revers order params goes to stack if they are.(rax may be trashed)
then they (first ones) goes to registers, (again rax may be trashed)
then call happened.
In official macro params not separated on that ones that goes to registers & and ones goes to stack, they are counted instead to move first 4 to registers if they are and others to stack.

for linux (see libcall same as win fastcall):
Code:
macro invoke proc,[arg] { common libccall [proc],arg }
macro libccall proc,tordi:rdi,torsi:rsi,torcx:rcx,tordx:rdx,tor8:r8,tor9:r9,[arg] {
 common local stackspace,counter
        counter = 6*8
        if defined current@frame
                if current@frame<stackspace
                        current@frame = stackspace
                end if
        else
                sub rsp,stackspace
        end if
        if ~ arg eq
 forward
                counter = counter + 8
 common
        end if
        stackspace = counter + counter and 8
        if ~ arg eq
                counter = 8
 reverse
                __push arg,stackspace-counter
                counter = counter + 8
 common
        end if
        __mov r9,tor9,r9d,r9w,r9b,xmm5
        __mov r8,tor8,r8d,r8w,r8b,xmm4
        __mov rdx,tordx,edx,dx,dl,xmm3
        __mov rcx,torcx,ecx,cx,cl,xmm2
        __mov rsi,torsi,esi,si,sil,xmm1
        __mov rdi,tordi,edi,di,dil,xmm0
        call proc
        if stackspace & ~defined current@frame
                add rsp,stackspace
        end if }

macro lcall proc_num,tordi:rdi,torsi:rsi,torcx:rcx,tordx:rdx,tor8:r8,tor9:r9 {
        __mov r9,tor9,r9d,r9w,r9b,xmm5
        __mov r8,tor8,r8d,r8w,r8b,xmm4
        __mov rdx,tordx,edx,dx,dl,xmm3
        __mov rcx,torcx,ecx,cx,cl,xmm2
        __mov rsi,torsi,esi,si,sil,xmm1
        __mov rdi,tordi,edi,di,dil,xmm0
        mov     eax,proc_num
        syscall }

macro proc [args]
 { common
    match name params, args>
    \{ define@proc name,<params \} }    

and __push for linux slightly differ:
Code:
macro __push value,offs{
        define type@param
        define definition@param value
        match =float value,definition@param \{
                define definition@param value
                define type@param float \}
        match =addr value,definition@param \{
                define definition@param value
                define type@param addr \}
        detect@argsize size@param,definition@param
        if type@param eq addr
                lea rax,[definition@param]
                mov [rsp+offs],rax
        else if definition@param eqtype [0] | definition@param eqtype byte [0]
                if size@param = 8
                        mov rax,definition@param
                        mov [rsp+offs],rax
                else if size@param = 4
                        mov eax,definition@param
                        mov [rsp+offs],eax
                else if size@param = 2
                        mov ax,definition@param
                        mov [rsp+offs],ax
                else
                        mov al,definition@param
                        mov [rsp+offs],al
                end if
        else if size@param = 8
                virtual
                        origin = $
                        mov rax,definition@param
                        load opcode byte from origin+1
                end virtual
                if opcode = 0B8h
                        mov rax,definition@param
                        mov [rsp+offs],rax
                else
                        mov qword [rsp+offs],definition@param
                end if
        else if definition@param in <xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7,xmm8,xmm9,xmm10,xmm11,xmm12,xmm13,xmm14,xmm15>
                movq [rsp+offs],definition@param
        else
                mov [rsp+offs],definition@param
        end if

}    
Post 20 Dec 2021, 20:16
View user's profile Send private message Send e-mail Reply with quote
Hotwire



Joined: 17 Sep 2015
Posts: 14
Hotwire
Many thanks!
Post 23 Dec 2021, 20:52
View user's profile Send private message Visit poster's website 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-2020, Tomasz Grysztar. Also on GitHub, YouTube, Twitter.

Website powered by rwasa.