However, since C is the low-level implementation language for almost every dominant operating system, a given platform's Operating System ABI is almost always locally synonymous with the C ABI on that platform, and people tend to speak of "being compatible with the C ABI" when what they really mean is that they're compatible with the OS's ABI.
But if you move to, say, a Mainframe OS, the OS ABI is dramatically different than the "C ABI" you're imagining from Wintel.
The design of C is predicated on an approach to portability that involves shipping source code, not binaries, around, with the destination machine having a compiler for its own architecture. (Given this, it's kind of shocking that things like Docker work at all. Goes to show how large a server-side monopoly those Intel ISAs currently hold.)
---
But wouldn't it be interesting if the "C compiler" were made into a low-level part of the operating system—basically taking the form of a JIT with a persistent cache—and then an executable format were specified, which really was just an archive of C source that was JIT-compiled by the OS when you first execv(3)ed it? Then you would have portable C binaries, because you'd be using the "correct" C ABI: C source-code.
Well, if you tack on a bit of pre-chewing to annotate the C source a bit (and maybe do some arch-neutral optimizations), and you have Apple's current LLVM-IR-based "Bitcode" approach to binaries.
Also it's Gott im Himmel ;-) (unless it's a reference I didn't get)
It's sort of like saying that there's no such thing as "rules of the road", because the road makers don't specify how you're supposed to drive on them, and the rules differ by jurisdiction and sometimes you're in a wilderness with no roads. The term is commonly understood to mean "rules for using roads, in the road-containing jurisdiction which you're in". I think the same thing is true of the phrase "C ABI", although if people are coming away thinking there's a cross-platform C ABI, then yes, we should be more precise.
Every platform has an ABI, obviously, and yes it's generally formed in view of C.
This doesn't change the fact that the phrase "The C ABI" is, in a vacuum, meaningless and that "The C ABI on Platform X" is just a convoluted, cart-before-the-horse way of saying "Platform X's ABI"
Put another way, I'm arguing that "C" is a more useful descriptor than "platform X's", because the sentence "Rust is compatible with the C ABI" is short for "forall X, Rust on platform X is compatible with the C ABI on platform X", and means something different from "Rust is compatible with the SysV ABI" (which implies that it follows the SysV ABI on Windows and OS X, too). And since the typical way of doing that is by interfacing with a C compiler or the C library (... and you could make this exact argument about the phrase "C library", I think), it's worth mentioning C. For instance, Vala and Nim, which both compile to C, are always compatible with the C ABI. If you port them to a mainframe they remain compatible with the C ABI, but not with the native ABI.
http://opengrok.libreoffice.org/xref/core/include/sal/types....
For example, I don't think there is a portable way to let your compiler use Pascal calling conventions, or to pass information in specific registers or in processor flags.
As an extreme example, in classic Mac OS, you could register a function to be called for line breaking in text input boxes that had the ABI "Parameters are passed to the routine in registers A3, A4, and D0, and output is returned in the Z flag of the Status Register." (https://developer.apple.com/legacy/library/documentation/mac..., page 2-31 gives several other special-cased ABI's in Mac OS)
Browsing that, I also encountered "The routine follows the C calling conventions employed by the THINK C software development environment. Arguments are passed on the stack from right to left, and a result is returned in register D0."
(Aside: that compiler must have treated vararg functions differently)
So, apparently, one cannot even count on C compilers to push arguments from left to right. So, if your ABI says "push X first, then y", I don't think you can portably call that function from C.
Right-to-left is pretty much the most sensible way to implement variadic functions with a stack-based calling convention - the argument that the function uses to interpret the rest of them must be found at a known location relative to the stack "top", and due to how stacks work, that implies the varying portion has to be pushed first, thus right-to-left.
Maybe if C decided to design things a little differently:
int printf(..., const char *format);
...
printf(5, "There are %d lights.\n");
we would instead have right-to-left being the dominant C calling convention.its a subtle difference some devs will pull out when they want to boost their egos by talking about things that sound smart, but they don't realise it requires that special kind of "smart-yet-dumb naivete" to consider worth caring or talking about.
C calling conventions (cdecl, stdcall) and memory layout is pretty well standardized. So I'm not sure what else you could be referring to here.