News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

x64 calling convention solution

Started by gallo, January 03, 2008, 07:01:34 PM

Previous topic - Next topic

gallo

hi everyone, merry Christmas and happy new year!
first of all, I don't know what happened to my account because I used to be a member until somebody (without my permission) used my id and password to post I don't know what and then the account disappeared... but it doesn't matter, I just reopened it...
Well, I've just started to program with masm64 and I noticed, as you have, that some instructions like invoke, proc and proto (among others) aren't very usefull so I started the make a macro to replace them. The first thing I tried, was to make some prologue and epilogue macros, but then I discovered that when you declare certain number of parameters and local variables, one of each will have the same offset, so I could not use that method; then I just made by my self the whole macro replacement. Using the macros, the code would look like thisinclude x64calling.inc

includelib kernel32.lib
includelib user32.lib

funcproto external,MessageBoxA,qword,qword,qword,dword
funcproto external,lstrcpyA,qword,qword

funcproto local,proc1,qword,real8,byte,word,dword,qword,real4

cstr macro text:vararg
local var
.data
var byte text,0
.code
exitm <offset var>
endm

.data
appname byte "application",0

.code
function main
begin_alloc 5
alloc_var v1{20}:byte
alloc_var v2:dword
alloc_var v3:qword
alloc_var v4:real4
alloc_var v5:real8
end_alloc

mov rcx,19
@@:
mov v1[rcx],-1

dec rcx
jns @B

mov v2,-1
mov v3,-1

invoke proc1,addr v1,v5,-1,-1,v2,v3,v4
endf
ret

function proc1,lpArray:qword,p1:real8,p2:byte,p3:word,p4:dword,p5:qword,p6:real4
begin_alloc 4
alloc_var text{20}:byte
end_alloc rax,rdi

movsd xmm0,p1
movss xmm0,p6
mov al,p2
mov ax,p3
mov eax,p4
mov rax,p5

mov rdi,lpArray

invoke lstrcpyA,addr text,cstr("x64 calling convetion!!")
invoke MessageBoxA,0,addr text,offset appname,0
endf
ret
end
as you can see, you can have parameters and locals with names, and address them with their corresponding names so you don't have to worry about the offsets, but when you're using a debugging tool like I do (I use Microsoft Visual Stdio 2008) you won't be able to access the variables or parameters by name, because the macro doesn't produce any debugging information; you can also have two or more functions with the same variables or parameters names and the macro will know which corresponds to which offset, you can save registers and, the more important, you can specify the greater number of parameters passed to another function by the current function, so the stack can be organized (as you should know, in the x64 calling convention, the stack must hold enough space for the parameters insted of pushing them), you can declare arrays, you can pass and get single and double precision parameters and variables, you just have to declare them as real4 and real8; you can pass constants and the macro will pass them as the needed size, i.e. if you pass -1 for a byte, it will pass ffh, but if you pass -1 for word, it will pass ffffffh and so long... the stack is always aligned to dqword, and a little stack frame is created to address the local variables and parameters from rbp. A little problem is that you can't use things like MessageBox equ <MessageBoxA> because the funcproto macro doesn't resolve the equ, and the only error handling at the moment, is when you pass a wrong number of parameters to the invoke. Obviously you get an error if you pass an address (oh, the addr is also supported) to a byte, of if you try to move a qword ptr to ax, and things like that, but when you make a endf outside a function directive or things like those you won't get an error, and that should happend, but I wanted you to take a look at it before doing those changes. So here are the macros, I hope you like them and find them as useful as I do, thanks for your attention... and sorry it is a little bad commented, but I had it in Spanish and I've just translated themĀ  :green, something more, a little of sintax: invoke is the same as it was... funcproto, you have to first, pass external or local, whether is an external or a local label, then the function name, and then the parameters type without the ":"; in the function macro, is almost the same of the proc, but you just can write the parameters, no the registers used and things like that... in the begin_alloc, leave it alone if you're not calling any function, if you are, type the number of parameters passed, even if it's zero; alloc_var is almost the same as local, but for declaring an array use {} insted of []; in the end_alloc, you can write the list of the registers to be saved, and in the endf macro, just type it before the ret, and that's it.

[attachment deleted by admin]


MazeGen

I'm interested in macros supporting x64 conventions in general. I also work on my own solution.

What I really miss in your macros is support for x64 "compile-time" exception handling (MASM FRAME option). Without this, your macros are quite incomplete.

gallo

hi,
yes, when I was reading about the convention, I read about the exception handling, but I didn't make it part of the macros because I have never used that in x86 assembler and I'm pretty sure that a very few library calls need to be inside some try/except/catch structure, unless that's what I've read. So, anyway, if that's important I'll make it part of the macros... but I still don't know if the other macros are working fine.

gallo

hello,
I've noticed that the macros have a little problem: when you try to refer to a local variable which is an struct, for examplefunc function1
begin_alloc
alloc_var rt:RECT
end_alloc

mov rt.RECT.top,0
that won't work, because it'd be translated by the macro to something likemov xmmword ptr [rbp-(16+8)],0 and that is not even near to what we want... well the offset is, but the xmmword part isn't; this happends because when you declare a local variable, the macro relates the name of the variable to a pointer based in rbp and with a data type; so, as RECT has a size of dqword, the only data type supported with that size is a xmmword... so I deleted the part in which the declaration relates the variable or parameter name with its data type, so you can use a struct as you used to, well more or less like the code above, but now when you're referring to a local variable which is not a struct, you have to add something like thisfunc function1
begin_alloc
alloc_var x:qword
end_alloc

mov qword ptr x,1

thanks for your attention

[attachment deleted by admin]

gallo

hi,
I don't know if someone is actually interested in this macros...
Well, I've noticed that one of the most hard part of programming in x64 is to remember to set the greater number of parameters in the function declaration, and as the invoke macro is part of those macros, I added a little very useful feature; when you invoke the function whose parameters count is the greater inside a function, and that parameter count is different of the number you wrote in the function declaration, the macros will raise an error telling you that the allocated number of parameters is wrong...

[attachment deleted by admin]

gallo

hello,
there was a little problem when you tried to pass to invoke a parameter which was real4 or real8, you had to pass it as followinvoke funtion,mmword x
invoke funtion,dword x
but now you can pass it and the macro will decide to use mmword/dword based on the prototype, and you can pass xmm registers as well without...
I'd like to know what do you guys think about it so long
thanks

[attachment deleted by admin]

GUAN DE DIO

Hi gallo,

     I'm interesting in your macros.

     I donwloaded the las zip put it in this thread and  when I compliled my code I had the next issue:

        "variable invokedparams is not declared"

     This varialbe is in invoke macro.

       could you tell me how fix this issue?

Thanks,
GUAN

ecube

I got the same error, but the minor changes below seems to fix it


;; passes the parameters and calls the function
invoke macro function:req,paramslist:vararg
local typeslist,index,invokedparams,paramvalue,paramtype

typeslist textequ @CatStr(<_proto_>,function)

invokedparams=0
index=@countargs(paramslist)
if index eq @countargs(typeslist)
if index ge invokedparams
invokedparams=index
endif
repeat index
paramvalue textequ @argn(index,paramslist)
paramtype textequ @argn(index,typeslist)

pos=@InStr(1,%paramvalue,<addr >)
if pos ;; is an address
pushparam index,paramtype,-1,@SubStr(%paramvalue,pos+5)
else
pushparam index,paramtype,0,paramvalue
endif

index=index-1
endm
call function
else
.err <&function doesn't take this number of parameters>
endif
endm


also to gallo i'd just like to say fantastic job!!!, i'm working on a MASM64 SDK package to match the masm32 as closely as possible as we speak which i'll have uploaded tonight or tommorow. i'm writing a tool now that converts old masm32 .inc proto defs to your funcproto syntax(which I renamed to proto64). you get full credit throughout, your example code above however I couldn't get to work, it errors on

mov v1[rcx],-1

and a couple other places,so perhaps you can take another look at it.