Function calling conventions

I’ve been working on a project that needs to use callconv(.c) as I need to interop with C. I’ve also read from the language that the “export” keyword makes that function use the C calling convention Documentation - The Zig Programming Language

Apart from the statement “different languages use different function calling conventions” I don’t understand anything about calling conventions and how they differ. What is a function’s prologue and epilogue that is removed when using “callingconv(.naked)”.

Following the adage of “always understand one level deeper”, can’t find the exact article I got this from but here’s similar ones: https://cacm.acm.org/research/always-measure-one-level-deeper/, Try to Fix It One Level Deeper (keep referencing matklad :laughing:). Here are some of my questions.

How many calling conventions does Zig have? What is function’s prologue and epilogue? Why does wasm not want either? Do different calling conventions affect a program’s behaviour or is it just for FFI?

Articles and other deeper reading topics would be highly appreciated!

They’re described in std.builtin.CallingConvention.

A function’s prologue and epilogue are bits of assembly that do things like move arguments to/from registers (or tell you where on the stack they are), set up and/or move the instruction pointer, the return address, and so on.

Since, for example “inline” is also a calling convention, they do affect your program’s behavior, but the differences in effects are usually not (and probably should not be) on the level of changing your program’s semantics. The reason they’re relevant for FFI is that Zig and the other programming language have to agree with how to call a function in order for the handshake in and out of your code to work.

You might like reading this blog post, even if a bunch of it is just flavor at the moment :slight_smile: The Fil-C Optimized Calling Convention

3 Likes

So a calling convention is both OS specific (.winapi (?)), architecture specific and programming language specific?

Does the Zig compiler takes care of the architecture specific part?

yes, in that undecorated functions are interpreted as .auto and the compiler decides what that means.

1 Like

Now for a last question. Why does Zig have it’s own calling convention over using C’s?

Since it already uses C’s calling convention for exported functions, what’s the benefit in using a different calling convention for exported and non-exported functions?

For optimisation, the compiler can create multiple conventions for different functions and callers that are most optimal for their use case.
This ofc means that the convention is unstable, and could change from distantly related code changes.

Using C’s calling convention would also require defining slices, tagged unions, optionals, errors, etc to be compatible with C.
Which, aside from being a lot of work, also prevents the language and compiler from having types and optimisations that are incompatible with C.

6 Likes