flat assembler
Message board for the users of flat assembler.

Index > Windows > fastcall how to use for more than 4 parameters

Author
Thread Post new topic Reply to topic
patchariadog



Joined: 24 Mar 2013
Posts: 94
patchariadog 26 May 2014, 15:55
I was trying to build a function for x64. the function happens to use more than 4 parameters. in x86 it works fine but I know in x64 with fastcall you have to spill the parameters into the shadow space in the order of rcx,rdx,r8,r9 I read that for 5 and etc you have to pass them onto the stack, but I don't know how to do this. this is what I tried but it keeps saying invalid operand. I know that the first 4 parameters I am doing right because I have made x64 functions before but it is the last 3 I don't know how to spill
Code:
proc myfunction,inputstring,outputstring,buffer1,buffer2,buffer3,startposition,length
;spill
mov [inputstring],rcx
mov [outputstring],rdx
mov [buffer1],r8
mov [buffer2],r9
mov [buffer3],[rsp+8*4]
mov [startposition],[rsp+8*5]
mov [length],[rsp+8*6]
    

I tried this because someone suggested that this would work on
http://board.flatassembler.net/topic.php?t=15131

I also tried this
Code:
mov [inputstring],rcx
mov [outputstring],rdx
mov [buffer1],r8
mov [buffer2],r9
mov rax,[rsp+8*4]
mov [buffer3],rax
mov rax,[rsp+8*5]
mov [startposition],rax
mov rax,[rsp+8*6]
mov [length],rax
    

it compiles but it leads to an APPCRASH when I use the substr function

can someone please show me how to use fastcall to call a proc that has more than 4 parameters on x64

also do I need to setup more space on the stack because I read somewhere I may need to put add rsp,28h above the spill zone?
I am not sure

thanks
Post 26 May 2014, 15:55
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1708
Location: Toronto, Canada
AsmGuru62 26 May 2014, 17:06
The fastcall convention is for calling Win API functions only.
It means if you call Win API - you have to provide spill and put parameters into exactly named registers.
As I see it - you just using your own function, it means you can use registers as parameters in whatever form or shape you wish.
There are a lot of registers on x64 - you can pass all parameters as registers.

However,
If you provide your function as a library function (called by C++ for example), then yes, you need to follow fastcall.
Post 26 May 2014, 17:06
View user's profile Send private message Send e-mail Reply with quote
patchariadog



Joined: 24 Mar 2013
Posts: 94
patchariadog 26 May 2014, 17:21
I am still confused
I tried removing all the ;spill and using fastcall and this makes it not function properly.
I tried using stdcall and it appcrashes
I tried using fastcall and spilling this
Code:
mov [inputstring],rcx
mov [outputstring],rdx
mov [buffer1],r8
mov [buffer2],r9
mov [buffer3],r10
mov [startposition],r11
mov [length],r12      

and it does not function properly.

I am confused because I know I could never convert my x86 functions to x64 untill I learned about the spill

for example x86
Code:
proc stringlengthx86 uses esi, str
;usage stdcall stringlengthx86,str
;length is stored in eax
;works with rb and dd
mov esi, [str]
or eax,-1
.Loop:
inc eax
cmp byte[esi+eax], 0
jne .Loop
ret
endp
    


only works in x64 when i do this
Code:
proc stringlengthx64 uses rsi, str
;usage fastcall stringlengthx64,str
;works with dd and rb
;length is stored in eax
;spill
mov [str],rcx
mov rsi, [str]
or rax,-1
.Loop:
inc rax
cmp byte[rsi+rax], 0
jne .Loop
ret
endp
    


I just don't know how to spill more than 4 parameters.

thanks
Post 26 May 2014, 17:21
View user's profile Send private message Reply with quote
einar



Joined: 08 Feb 2014
Posts: 4
einar 26 May 2014, 21:14
Hi patchariadog,

I'm not familiar with FASM syntax but I'll try to help you.
If you want to make your proc x64 fastcall you don't have to worry about spilling
more than first four params because someone who called function already did it.
Look at this:
Code:
;masm syntax

        mov     qword ptr [rsp+8*6], 16 ; length
        mov     qword ptr [rsp+8*5], 0  ; startposition
        mov     qword ptr [rsp+8*4], 400000h    ; buffer3
        mov     r9, buffer2
        mov     r8, buffer1
        mov     rdx, outputstring
        mov     rcx, inputstring
        call    myfunction
    
Post 26 May 2014, 21:14
View user's profile Send private message Reply with quote
patchariadog



Joined: 24 Mar 2013
Posts: 94
patchariadog 27 May 2014, 03:16
thanks asmguru 62 and especially einar. after playing around with it for a little bit I found that the only way it seems to work is if I spill the first 4 parameters and then ignore the rest 5-infinity

example
Code:
proc substr,inputstring,outputstring,buffer1,buffer2,buffer3,startposition,length
;spill
mov [inputstring],rcx
mov [outputstring],rdx
mov [buffer1],r8
mov [buffer2],r9

;start the regular code. ignore spilling buffer3,startposition and length
    
Post 27 May 2014, 03:16
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20630
Location: In your JS exploiting you and your system
revolution 27 May 2014, 03:47
Only the first four parameters are left off the stack image of the incoming values. All other parameters are put on the stack in the usual way.

It is kind of a weird calling method IMO as is encourages a lot of "mov [rsp+...],value" instructions (as opposed to "push value") which tends to inflate code size and reduce the efficiency of the code caches. I would hope that whoever designed this fastcall method did some benchmarks to justify the choices. I would hate to think that it was just simply decided without any figures to back it up. Also the 0 mod 16 thing kind of forces the use of RBP as a stack pointer in many cases and certainly leads to many silly bugs when one forgets about the alignment restrictions.
Post 27 May 2014, 03:47
View user's profile Send private message Visit poster's website Reply with quote
einar



Joined: 08 Feb 2014
Posts: 4
einar 27 May 2014, 05:10
Quote:

It is kind of a weird calling method IMO as is encourages a lot of "mov [rsp+...],value" instructions (as opposed to "push value")


Reason why it's made this way is because RSP must be always aligned to 16 byte boundry. Whenever you use PUSH you may break this alignment and this sometimes will cause crash. This forces you to tracing state of RSP in your code. So it's safer to use MOV instead.

Quote:

I would hope that whoever designed this fastcall method did some benchmarks to justify the choices.


I heard that keeping RSP alingned gives significant acceleration of the peformance. But i'm not an expert. So I'll gladly hear what others know about it.
Post 27 May 2014, 05:10
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-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.