flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > Linux 64 bit call macro

Author
Thread Post new topic Reply to topic
ProphetOfDoom



Joined: 08 Aug 2008
Posts: 120
Location: UK
ProphetOfDoom 08 Apr 2012, 19:42
EDIT: Fixed bug where code wouldn't assemble for functions with no arguments

Hi,

I searched using the forum search, and Google search, but I couldn't find any macro to wrap Linux's 64-bit calling convention (except a Nasm macro that the author says shouldn't be used lol). So I wrote one. It's my first ever (large) macro and it's a little messy and probably could have been a lot smaller but it seems to do the job.

There are a few things to note:

1) The macro uses RAX internally. You can still use RAX as an argument, as many times as you want, but bear in mind there will be a slight performance hit as data is shunted around.
2) A lot of the pushing and popping in the macro is to accommodate the fact that the user might push the arguments in the opposite order to that required by the calling convention. You'll get slightly faster code if you pass say "RDI, RSI" instead of "RSI, RDI".
3) If a string is made up of multiple strings/bytes separated by commas, you should enclose the whole thing in GT/LT symbols <>.
4) The macro tries to prevent crashes due to misalignment of the stack but it's your responsibility to ensure the stack is aligned.
5) There are prolly bugs, use at your own risk, etc.

This is the macro file (name it "unix64call.inc")

[See post below...]

Here's a little example program to demonstrate its various uses (unix64call.asm):

Code:
format ELF64

include "unix64call.inc"

public main

extrn exit: qword
extrn printf: qword

section '.data' writable

pi dq 3.141592, 6.283185
three dq 3
hello db "Hello world.",10,0
align 8
nine_floats db "Nine floats, last one on stack: %f, %f, %f, %f, %f, %f, %f, %f, %f",10,0
align 8
int_float_mix db "Ints and floats mixed: %d, %f, %d, %f",10,0
align 8
int_float_mix_rev db "Ints and floats mixed, register arguments in wrong order: %d, %f, %d, %f",10,0
align 8
seven_ints db "Seven ints: %d, %d, %d, %d, %d, %d, %d",10,0

section '.text' executable

main:

sub rsp, 8

unix64call printf, hello
unix64call printf, <"pi = %f, 2pi = %f",10,0>, float [pi], float [pi + 8]
unix64call printf, nine_floats, float [pi], 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, float [pi + 8]
unix64call printf, int_float_mix, 1, float [pi], 2, float [pi + 8]

mov r9, 1
movq xmm1, [pi]
mov rdi, 2
movq xmm0, [pi + 8]
unix64call printf, int_float_mix_rev, r9, xmm1, rdi, xmm0

unix64call string_test, "Eight strings, six in registers, two on stack: Hullo ", "World ", "How ", "Are " , "You ", "This ", "Fine ", <"Day ",10>
unix64call printf, <"Int, float, string...","%d, %f",10,"%s">,17,3.0,<"erk :S",10>

mov r9, 1
mov r8, 2
mov rdi, 4
mov rsi, 5
unix64call printf, seven_ints, r9, r8, [three], rdi, rsi, 6, 7

mov rdi, 0
call exit

string_test:

sub rsp, 8

mov rbx, rsi
mov rbp, rdx
mov r12, rcx
mov r13, r8
mov r14, r9

mov rax, 0
call printf

mov rax, 0
mov rdi, rbx
call printf

mov rax, 0
mov rdi, rbp
call printf

mov rax, 0
mov rdi, r12
call printf

mov rax, 0
mov rdi, r13
call printf

mov rax, 0
mov rdi, r14
call printf

mov rax, 0
mov rdi, [rsp + 16]
call printf

mov rax, 0
mov rdi, [rsp + 24]
call printf

add rsp, 8

ret
    


You can build the example with:

Code:
fasm unix64call.asm
gcc unix64call.o -o unix64call
    


Fond regards,
Me


Last edited by ProphetOfDoom on 12 Apr 2012, 06:50; edited 1 time in total
Post 08 Apr 2012, 19:42
View user's profile Send private message Reply with quote
ProphetOfDoom



Joined: 08 Aug 2008
Posts: 120
Location: UK
ProphetOfDoom 12 Apr 2012, 06:48
Fixed several catastrophic bugs related to functions with > 6 arguments. Also optimised away some useless stack prodding. Pls re-copy/paste if there's anybody out there, lol...

Code:
macro unix64call proc,[arg]
{
     common
              local G_ARG_INDEX
           local F_ARG_INDEX
           
            local ARG_IS_FLOAT
          local ARG_IS_STRING
         
            local G_ARG0_STORED
         local G_ARG1_STORED
         local G_ARG2_STORED
         local G_ARG3_STORED
         local G_ARG4_STORED
         
            local F_ARG0_STORED
         local F_ARG1_STORED
         local F_ARG2_STORED
         local F_ARG3_STORED
         local F_ARG4_STORED
         local F_ARG5_STORED
         local F_ARG6_STORED
         
            local NUM_XMM_ARGS
          local NUM_FLOAT_ARGS
                local NUM_GENERAL_ARGS
              local NUM_STACK_ARGS
                
            local NUM_ARGS_PUSHED
               
            G_ARG_INDEX = 0
             F_ARG_INDEX = 0
             
            ARG_IS_FLOAT = 0
            ARG_IS_STRING = 0
           
            G_ARG0_STORED = 0
           G_ARG1_STORED = 0
           G_ARG2_STORED = 0
           G_ARG3_STORED = 0
           G_ARG4_STORED = 0

               F_ARG0_STORED = 0
           F_ARG1_STORED = 0
           F_ARG2_STORED = 0
           F_ARG3_STORED = 0
           F_ARG4_STORED = 0
           F_ARG5_STORED = 0
           F_ARG6_STORED = 0
           
            NUM_XMM_ARGS = 0
            NUM_FLOAT_ARGS = 0
          NUM_GENERAL_ARGS = 0
                NUM_STACK_ARGS = 0
          
            NUM_ARGS_PUSHED = 0
 
    forward
             
            if G_ARG_INDEX > 5 | F_ARG_INDEX > 7
                  NUM_STACK_ARGS = NUM_STACK_ARGS + 1
         end if
      
            match =float mem_float, arg
         \{
                    ARG_IS_FLOAT = 1
            \}
    
            if arg eqtype 1.0 | arg in <xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7> | ARG_IS_FLOAT
                   F_ARG_INDEX = F_ARG_INDEX + 1
                       NUM_FLOAT_ARGS = NUM_FLOAT_ARGS + 1
         else if ~(arg eq )
                  G_ARG_INDEX = G_ARG_INDEX + 1
                       NUM_GENERAL_ARGS = NUM_GENERAL_ARGS + 1
             end if
      
            ARG_IS_FLOAT = 0

        common
              
            if NUM_GENERAL_ARGS + NUM_FLOAT_ARGS
                
                    if ~((NUM_STACK_ARGS = 0) | ((NUM_STACK_ARGS mod 2) = 0))
                           sub rsp, 8
                  else
                                sub rsp, 16
                 end if
              
                    mov [rsp], rax
              
                    G_ARG_INDEX = 0
                     F_ARG_INDEX = 0
             
            end if

  common
              
            F_ARG_INDEX = NUM_FLOAT_ARGS
                G_ARG_INDEX = NUM_GENERAL_ARGS
              
    reverse
             
            if NUM_GENERAL_ARGS + NUM_FLOAT_ARGS
                
                    match =float mem_float, arg
                 \{
                            ARG_IS_FLOAT = 1
                    \}
            
                    contains_strings ARG_IS_STRING, arg
         
                    if arg eqtype 1.0 | arg in <xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7> | ARG_IS_FLOAT
                           F_ARG_INDEX = F_ARG_INDEX - 1
                       else
                                G_ARG_INDEX = G_ARG_INDEX - 1
                       end if
              
                    if arg in <xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7>

                               if F_ARG_INDEX > 7
                                       sub rsp, 8
                                  movq [rsp], arg
                                     NUM_ARGS_PUSHED = NUM_ARGS_PUSHED + 1
                               end if
                      
                    else if arg eqtype 1.0

                          if F_ARG_INDEX > 7
                                       mov rax, arg
                                        push rax
                                    NUM_ARGS_PUSHED = NUM_ARGS_PUSHED + 1
                               end if

                  else if ARG_IS_FLOAT
                
                            if F_ARG_INDEX > 7
                                       match =float mem_float, arg
                                 \{
                                            push mem_float
                                              NUM_ARGS_PUSHED = NUM_ARGS_PUSHED + 1
                                       \}
                            end if
                      
                    else if ARG_IS_STRING
                       
                            if G_ARG_INDEX > 5
                       
                                    call @f
                                     db arg, 0
                                   @@:
                             
                                    NUM_ARGS_PUSHED = NUM_ARGS_PUSHED + 1
                               
                            end if

                  else if G_ARG_INDEX > 5
                          if arg eq rax
                                       push qword [rsp + 8 * NUM_ARGS_PUSHED]                          
                            else
                                        push arg
                            end if
                              NUM_ARGS_PUSHED = NUM_ARGS_PUSHED + 1
                       end if
              
                    ARG_IS_FLOAT = 0
                    ARG_IS_STRING = 0
           
            end if

  common
              
            F_ARG_INDEX = 0
             G_ARG_INDEX = 0

 forward
     
            if NUM_GENERAL_ARGS + NUM_FLOAT_ARGS
                
                    if G_ARG_INDEX < 6 & arg eq rax
                              push rax
                    else if G_ARG_INDEX = 0 & arg in <rsi,rdx,rcx,r8,r9>
                              push arg
                            G_ARG0_STORED = 1       
                    else if G_ARG_INDEX = 1 & arg in <rdx,rcx,r8,r9>
                          push arg
                            G_ARG1_STORED = 1
                   else if G_ARG_INDEX = 2 & arg in <rcx,r8,r9>
                              push arg
                            G_ARG2_STORED = 1
                   else if G_ARG_INDEX = 3 & arg in <r8,r9>
                          push arg
                            G_ARG3_STORED = 1
                   else if G_ARG_INDEX = 4 & arg in <r9>
                             push arg
                            G_ARG4_STORED = 1                       
                    else if F_ARG_INDEX = 0 & arg in <xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7>
                             movq rax, arg
                               push rax
                            F_ARG0_STORED = 1
                   else if F_ARG_INDEX = 1 & arg in <xmm2,xmm3,xmm4,xmm5,xmm6,xmm7>
                          movq rax, arg
                               push rax
                            F_ARG1_STORED = 1
                   else if F_ARG_INDEX = 2 & arg in <xmm3,xmm4,xmm5,xmm6,xmm7>
                               movq rax, arg
                               push rax
                            F_ARG2_STORED = 1
                   else if F_ARG_INDEX = 3 & arg in <xmm4,xmm5,xmm6,xmm7>
                            movq rax, arg
                               push rax
                            F_ARG3_STORED = 1
                   else if F_ARG_INDEX = 4 & arg in <xmm5,xmm6,xmm7>
                         movq rax, arg
                               push rax
                            F_ARG4_STORED = 1
                   else if F_ARG_INDEX = 5 & arg in <xmm6,xmm7>
                              movq rax, arg
                               push rax
                            F_ARG5_STORED = 1
                   else if F_ARG_INDEX = 6 & arg in <xmm7>
                           movq rax, arg
                               push rax
                            F_ARG6_STORED = 1
                   end if
              
                    match =float mem_float, arg
                 \{
                            ARG_IS_FLOAT = 1
                    \}
            
                    if arg eqtype 1.0 | arg in <xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7> | ARG_IS_FLOAT
                           F_ARG_INDEX = F_ARG_INDEX + 1
                       else
                                G_ARG_INDEX = G_ARG_INDEX + 1
                       end if
              
                    ARG_IS_FLOAT = 0
            
            end if
      
    common
              
            F_ARG_INDEX = NUM_FLOAT_ARGS
                G_ARG_INDEX = NUM_GENERAL_ARGS
      
    reverse
             
            if NUM_GENERAL_ARGS + NUM_FLOAT_ARGS
                
                    match =float mem_float, arg
                 \{
                            ARG_IS_FLOAT = 1
                    \}
            
                    contains_strings ARG_IS_STRING, arg
         
                    if arg eqtype 1.0 | arg in <xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7> | ARG_IS_FLOAT
                           if NUM_XMM_ARGS < 8
                                      NUM_XMM_ARGS = NUM_XMM_ARGS + 1
                             end if
                              F_ARG_INDEX = F_ARG_INDEX - 1
                       else
                                G_ARG_INDEX = G_ARG_INDEX - 1
                       end if
              
                    if arg in <xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7>
                           
                            if F_ARG_INDEX = 7 & ~(arg eq xmm7)
                                     movq xmm7, arg
                              else if F_ARG_INDEX = 6 & F_ARG6_STORED
                                 pop rax
                                     movq xmm6, rax
                              else if F_ARG_INDEX = 6 & ~(arg eq xmm6)
                                        movq xmm6, arg
                              else if F_ARG_INDEX = 5 & F_ARG5_STORED
                                 pop rax
                                     movq xmm5, rax
                              else if F_ARG_INDEX = 5 & ~(arg eq xmm5)
                                        movq xmm5, arg
                              else if F_ARG_INDEX = 4 & F_ARG4_STORED
                                 pop rax
                                     movq xmm4, rax
                              else if F_ARG_INDEX = 4 & ~(arg eq xmm4)
                                        movq xmm4, arg
                              else if F_ARG_INDEX = 3 & F_ARG3_STORED
                                 pop rax
                                     movq xmm3, rax
                              else if F_ARG_INDEX = 3 & ~(arg eq xmm3)
                                        movq xmm3, arg
                              else if F_ARG_INDEX = 2 & F_ARG2_STORED
                                 pop rax
                                     movq xmm2, rax
                              else if F_ARG_INDEX = 2 & ~(arg eq xmm2)
                                        movq xmm2, arg
                              else if F_ARG_INDEX = 1 & F_ARG1_STORED
                                 pop rax
                                     movq xmm1, rax
                              else if F_ARG_INDEX = 1 & ~(arg eq xmm1)
                                        movq xmm1, arg
                              else if F_ARG_INDEX = 0 & F_ARG0_STORED
                                 pop rax
                                     movq xmm0, rax
                              else if F_ARG_INDEX = 0 & ~(arg eq xmm0)
                                        movq xmm0, arg
                              end if
                      
                    else if arg eqtype 1.0

                          if F_ARG_INDEX = 7
                                  mov rax, arg
                                        movq xmm7, rax
                              else if F_ARG_INDEX = 6
                                     mov rax, arg
                                        movq xmm6, rax
                              else if F_ARG_INDEX = 5
                                     mov rax, arg
                                        movq xmm5, rax
                              else if F_ARG_INDEX = 4
                                     mov rax, arg
                                        movq xmm4, rax
                              else if F_ARG_INDEX = 3
                                     mov rax, arg
                                        movq xmm3, rax
                              else if F_ARG_INDEX = 2
                                     mov rax, arg
                                        movq xmm2, rax
                              else if F_ARG_INDEX = 1
                                     mov rax, arg
                                        movq xmm1, rax
                              else if F_ARG_INDEX = 0
                                     mov rax, arg
                                        movq xmm0, rax
                              end if
              
                    else if ARG_IS_FLOAT
                
                            match =float mem_float, arg
                         \{
                                    if F_ARG_INDEX = 7
                                          movq xmm7, mem_float
                                        else if F_ARG_INDEX = 6
                                             movq xmm6, mem_float
                                        else if F_ARG_INDEX = 5
                                             movq xmm5, mem_float
                                        else if F_ARG_INDEX = 4
                                             movq xmm4, mem_float
                                        else if F_ARG_INDEX = 3
                                             movq xmm3, mem_float
                                        else if F_ARG_INDEX = 2
                                             movq xmm2, mem_float
                                        else if F_ARG_INDEX = 1
                                             movq xmm1, mem_float
                                        else if F_ARG_INDEX = 0
                                             movq xmm0, mem_float
                                        end if
                              \}
            
                    else if ARG_IS_STRING
               
                            if G_ARG_INDEX < 6
                       
                                    call @f
                                     db arg, 0
                                   @@:
             
                                    if G_ARG_INDEX = 5
                                          pop r9
                                      else if G_ARG_INDEX = 4
                                             pop r8
                                      else if G_ARG_INDEX = 3
                                             pop rcx
                                     else if G_ARG_INDEX = 2
                                             pop rdx
                                     else if G_ARG_INDEX = 1
                                             pop rsi
                                     else if G_ARG_INDEX = 0
                                             pop rdi
                                     end if  
                    
                            end if  
            
                    else

                            if G_ARG_INDEX = 5 & arg eq rax
                                 pop r9          
                            else if G_ARG_INDEX = 5 & ~(arg eq r9)
                                  mov r9, arg
                         else if G_ARG_INDEX = 4 & (G_ARG4_STORED | arg eq rax)
                                  pop r8
                              else if G_ARG_INDEX = 4 & ~(arg eq r8)
                                  mov r8, arg
                         else if G_ARG_INDEX = 3 & (G_ARG3_STORED | arg eq rax)
                                  pop rcx
                             else if G_ARG_INDEX = 3 & ~(arg eq rcx)
                                 mov rcx, arg
                                else if G_ARG_INDEX = 2 & (G_ARG2_STORED | arg eq rax)
                                  pop rdx
                             else if G_ARG_INDEX = 2 & ~(arg eq rdx)
                                 mov rdx, arg
                                else if G_ARG_INDEX = 1 & (G_ARG1_STORED | arg eq rax)
                                  pop rsi
                             else if G_ARG_INDEX = 1 & ~(arg eq rsi)
                                 mov rsi, arg
                                else if G_ARG_INDEX = 0 & (G_ARG0_STORED | arg eq rax)
                                  pop rdi
                             else if G_ARG_INDEX = 0 & ~(arg eq rdi)
                                 mov rdi, arg
                                end if
                      end if
              
                    ARG_IS_FLOAT = 0
                    ARG_IS_STRING = 0
           
            end if

  common
      
            mov rax, NUM_XMM_ARGS
               call proc
           
            if NUM_GENERAL_ARGS + NUM_FLOAT_ARGS
                
                    if ~((NUM_STACK_ARGS = 0) | ((NUM_STACK_ARGS mod 2) = 0))
                           add rsp, 8 * (NUM_STACK_ARGS + 1)
                   else
                                add rsp, 8 * (NUM_STACK_ARGS + 2)
                   end if
              
            end if

}

macro contains_strings result, [arg]
{
  result = 0
  forward
             if arg eqtype "fasm"
                      result = 1
          end if
}
    
Post 12 Apr 2012, 06:48
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.