Author Topic: What's an ideal assembly language calling convention?  (Read 3038 times)

Offline Dr1v3n

  • Jr. Member
  • *
  • Posts: 6
What's an ideal assembly language calling convention?
« on: December 10, 2020, 06:25:50 AM »
Assume I am not trying to make my code work with any other code or the output of any compiler...

What would be some options I should consider for a calling convention internal to my own code?

I've learned cdecl, fastcall, stdcall, etc... But these are all common conventions output by compilers. I want to learn a way I may do this as just an assembly programmer.

First, is there even one convention I should follow? Why or why not? I'm thinking for example, if I write a procedure which is to take 2 strings and a length, I could simply write it to expect the 2 string pointers to be in rsi, rdi, and the length in rcx for example... But maybe if I have a proc that takes 2 numbers in and does some math, then returns a result, that proc could expect the numbers to be in rcx and rdx, and then the return in rax and so on and so forth...

Generally, I think I would prefer registers so as to reduce the amount of memory reads/writes and stack manipulation, since most general purpose registers are assumed to be clobbered anyway...

Does anyone have any guidance on this? Is there a good blog, forum post, article, etc...?

Thanks

Offline vitsoft

  • Jr. Member
  • *
  • Posts: 13
  • Country: cz
    • About me
Re: What's an ideal assembly language calling convention?
« Reply #1 on: December 14, 2020, 08:58:52 AM »
It depends on the programming style: If you are used to hold most of temporary information in GPR between calls of procedures, it is convenient when those procedures do not clobber registers. If you keep temporary information in memory-variables, you don't have to care if the call of registry-convention procedure destroys GPR, but prior to CALL you need to load the input registers from memory anyway, so the gain of performance is lower.

Choice of calling convention is a trade-off between performance and programmer's convenience. It also depends on the complexity of procedures and the number of input arguments. With register-calling convention we may run out of available input registers soon, especially in 32bit mode.
StdCall seems more universal and convenient, see https://euroassembler.eu/easource/#CallingConvention, and it is compatible with 32bit Windows API.

Unlike C-functions we don't have to restrict the procedure output to just one value in assembly language, the result(s) can be returned in many registers and|or flags.

First, is there even one convention I should follow? Why or why not? I'm thinking for example, if I write a procedure which is to take 2 strings and a length, I could simply write it to expect the 2 string pointers to be in rsi, rdi, and the length in rcx for example...
Yes, such procedure could be this simple:

Compare PROC ; Compare strings at RSI, RDI with the length in RCX. Return ZF when equal. Clobbers RSI,RDI,RCX,Rflags.
     REP CMPS
     RET
    ENDPROC

However, you will need to load pointers from memory to RSI,RDI,RCX before each CALL Compare (of course, no sane programmer would create a procedure from just simple REP CMPS).
I prefer standard-calling convention even in 64bit mode, where arguments are pushed on stack before CALL and in the end they are discarded by RET IMM. Inside the procedure they are accessible relative to RSP or RBP, see StdCall Compare as an example.