flat assembler
Message board for the users of flat assembler.
![]() |
Author |
|
revolution 28 Jun 2017, 01:54
It looks like you are writing Windows 64-bit code and using the C library functions. So what you need to know about is the calling conventions used. They tell you which registers need to be preserved and how the parameters are passed.
For Windows 64-bit the calling convention is fastcall |
|||
![]() |
|
Furs 28 Jun 2017, 10:39
fastcall is a 32-bit calling convention, even the wiki article you linked says it, why do people insist on calling the 64-bit one this way is beyond me. Just to confuse newbies I guess since they're totally different calling conventions. If MS64 ABI call convention is fastcall then what's the name for Linux's? "fastercall"?
BTW you don't have to save rbx, rbx is a saved register in the function (i.e. printf saves it). That's what "preserved" or "callee saved" register means. So you can guarantee their value between function calls won't change. "Volatile" registers as Microsoft calls them, are those which will get trashed/clobbered by the function call with such calling convention. This means you cannot rely on their values, unless they are returned by the function (typically rax/eax). |
|||
![]() |
|
Inagawa 28 Jun 2017, 19:53
Ok, could I please ask any of you to write a simple function that just passes its first parameter to printf and returns. How do you call this function?
I was hoping I could do: Code: main: sub rsp, 8 invoke myOwnPrintf, "Some text" invoke ExitProcess, 0 myOwnPrintf: push rbp mov rbp, rsp sub rsp, 8 cinvoke printf, "%s", rcx pop rbp ret But I cannot use invoke on it. Is the stack frame correct? I had a hard time getting a straight answer. The windows calling convention says that there's at least 32bytes reserved on the stack on every call before the return address, so it's the callers responsibility. That's where I though the invoke macro or something similar is used. Can someone help me with specific answers? I'm just having a hard time finding the right path right now. Last edited by Inagawa on 29 Jun 2017, 09:12; edited 1 time in total |
|||
![]() |
|
revolution 28 Jun 2017, 23:54
If you define "myOwnPrintf" with proc and endp then the stack is setup correctly. The way you have it there is not correct. You shouldn't have the extra 'sub rsp, 8' because the 'push rbp' already does this for you. Alternatively you don't need a stack frame so you can leave out all the instructions using rbp and only use the 'sub rsp, 8'.
|
|||
![]() |
|
Inagawa 29 Jun 2017, 00:39
But I don't want to use the proc macros exactly because they obfuscate something that I obviously don't undestand.
Thanks for the 'sub rsp, 8' mention, I totally missed that I was actually misaligning the stack. How would you call the above function? Can you show me how exactly such a function is invoked in the same convenient fashion that Windows functions have? I.e. 'invoke myFunction, "something"' instead of having to manually put the parameters in the registers. Is there such a macro? |
|||
![]() |
|
revolution 29 Jun 2017, 01:31
For the Win64 macros the call is the same. fastcall and invoke are the same macro. What you have there already should work fine.
The problem you have when you call printf there is that fasm uses left-to-right argument order for the register elements. So rcx is overwritten first and then the next parameter uses the new value of rcx, so your input value of rcx is lost. You can fix this: Code: mov rdx,rcx cinvoke printf, "%s", rdx |
|||
![]() |
|
Inagawa 29 Jun 2017, 08:54
Well "invoke" doesn't work on these simple 'label' procedures, only call. But call doesn't pass parameters. So what macro do you use to call procedures that you defined?
Because the above in my post doesn't compile. |
|||
![]() |
|
revolution 29 Jun 2017, 09:40
Inagawa wrote: Well "invoke" doesn't work on these simple 'label' procedures ... |
|||
![]() |
|
Inagawa 29 Jun 2017, 10:03
Thank you!
|
|||
![]() |
|
Tomasz Grysztar 29 Jun 2017, 14:23
Furs wrote: fastcall is a 32-bit calling convention, even the wiki article you linked says it, why do people insist on calling the 64-bit one this way is beyond me. Just to confuse newbies I guess since they're totally different calling conventions. If MS64 ABI call convention is fastcall then what's the name for Linux's? "fastercall"? |
|||
![]() |
|
Furs 29 Jun 2017, 15:31
But that's wrong, did you even click the link on Microsoft's site linked?
Links to: https://docs.microsoft.com/en-us/cpp/cpp/fastcall ^ describes the 32-bit fastcall, in particular that the called function cleans the stack, which is not the case for x64 calling convention, even if we ignore that they forgot to mention the x64 registers... |
|||
![]() |
|
Tomasz Grysztar 29 Jun 2017, 15:44
Furs wrote: But that's wrong, did you even click the link on Microsoft's site linked? What was relevant in my link was the passage that shows that even Microsoft has been using this name (even if inconsistently) with respect to 64-bit world: Microsoft wrote: Given the expanded register set, x64 uses the __fastcall calling convention and a RISC-based exception-handling model. The __fastcall convention uses registers for the first four arguments and the stack frame to pass additional arguments. |
|||
![]() |
|
Furs 29 Jun 2017, 19:54
I still think it's confusing as heck, especially since even MS state that it is ignored on x64 (the keyword), so it seems someone got it wrong there for sure when it was "prevalent".
FWIW, GCC's sources never refer to it as fastcall, there's only one fastcall there and it's the 32-bit one only (well I've patched it to add custom calling convention support via a plugin, so I had to dig deep). |
|||
![]() |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2023, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.