Does C have a standard ABI?
Asked Answered
C

9

50

From a discussion somewhere else:

C++ has no standard ABI (Application Binary Interface)

But neither does C, right?

On any given platform it pretty much does. It wouldn't be useful as the lingua franca for inter-language communication if it lacked one.

What's your take on this?

Cory answered 20/12, 2010 at 11:3 Comment(2)
I think "on any given platform" is a bit weasel-wordy, presumably by accident. You could almost define "platform" to mean, "using the same C ABI throughout". Specifically, any defined format for dynamically-loaded code must define an ABI for calls across executable boundaries. That ABI certainly needs to support C to be of any practical use (assuming people are going to write executables in C or C++), and might also support C++, if you're lucky. If it supports C but not C++, you write C++ with extern "C" on everything you publish, and/or use the same compiler for linked executables.Applesauce
Also see that different, but close question: What could C/C++ “lose” if they defined a standard ABI?Malines
E
58

C defines no ABI. In fact, it bends over backwards to avoid defining an ABI. Those people, who like me, who have spent most of their programming lives programming in C on 16/32/64 bit architectures with 8 bit bytes, 2's complement arithmetic and flat address spaces, will usually be quite surprised on reading the convoluted language of the current C standard.

For example, read the stuff about pointers. The standard doesn't say anything so simple as "a pointer is an address" for that would be making an assumption about the ABI. In particular, it allows for pointers being in different address spaces and having varying width.

An ABI is a mapping from the execution model of the language to a particular machine/operating system/compiler combination. It makes no sense to define one in the language specification because that runs the risk of excluding C implementations on some architectures.

Exequies answered 20/12, 2010 at 14:21 Comment(9)
“[…] will usually be quite surprised on reading the convoluted language of the current C standard.”: since which version of the standard? About the pointers, I've never checked if this was allowed by ISO C or not, but I know there was the so called small, hug and medium memory models (medium was somewhat mixed one) which were famous at the time of 16 bits DOS (many time running on a 32 bits machine); pointers was already not warranted to be the same size all the time.Malines
@Malines at the time I wrote the answer, the current C standard was C99. I doubt if much has changed in C11. The small, huge and medium memory models were not part of C but part of most implementations of C on the 8086 architecture.Exequies
@curiousguy Well, it could be an index into an array or it could be a handle that redirects through a table of addresses or it could be a segment and an offset or it could br a tagged descriptor. The C standard nowhere says it has to be an address.Exequies
@Exequies A segment+offset determines an address; the diff w/ a pure address is that there are potentially multiple ways to point to one address, but it still encodes an address. A table of addresses doesn't seem compatible w/ ptr arithmetic.Fassett
@Fassett If you are going to say that anything that can be decoded into an address is an address, then everything is an address except a literal. You render the word practically meaningless.Exequies
@Exequies Segment+offset is the way addresses are represented w/ some memory addressing modes; it's the closest to a numeric address that you could even use, when you don't even have a register that can hold a complete numeric address. OTOH an index to a table of addresses can only represented limited addresses and isn't the closest to an address on the machine. So the former is an address, and the later is not.Fassett
@Fassett Not necessarily. The segment need not be the base address of a segment. It could be an index into a table of segments. For example, on an 8086, it might be a number between 0 and 3 representing CS, DS, ES or SS. However, addresses on an 8086 are 20 bit binary numbers.Exequies
@Exequies Even if the segment register is an index and not a base address, the offset is a number that is truly a relative address. So you can do ptr arithmetic, which isn't possible if ptr are represented as indexes in an array of numerical addresses.Fassett
@Fassett Why not?Exequies
S
27

C has no standard ABI in principle, but in practice, this rarely matters: You do what your OS-vendor does.

Take the calling conventions on x86 Windows, for example: The Windows API uses the so-called 'standard' calling convention (stdcall). Thus, any compiler which wants to interface with the OS needs to implement it. However, stdcall doesn't support all C90 language features (eg calling functions without prototypes, variadic functions). As Microsoft provided a C compiler, a second calling convention was necessary, called the 'C' calling convention (cdecl). Most C compilers on Windows use this as their default calling convention, and thus are interoperable.

In principle, the same could have happened with C++, but as the C++ ABI (including the calling convention) is necessarily far more elaborate, compiler vendors did not agree on a single ABI, but could still interoperate by falling back to extern "C".

Significancy answered 20/12, 2010 at 13:37 Comment(1)
This is correct but not clear enough. It is not so much about vendors not agreeing between themselves on a common ABI (that could be solved by a standardization committee). Its more about the same vendor not agreeing with himself at different times due to not always predicting future developments.Danialdaniala
C
17

The ABI for C is platform specific - it covers issues such as register allocation and calling conventions, which are obviously specific to a particular processor. Here are some examples:

x86 has had many calling conventions, which extensions under Windows to declare which one is used. Platform ABIs for embedded Linux have also changed over time, leading to incompatible user space. See some history of the ARM Linux port here, which shows the problems in the transition to a newer ABI.

Crystlecs answered 20/12, 2010 at 11:15 Comment(1)
I went ahead and removed the broken link.Benelux
A
7

Although several attempts have been made at defining a single ABI for a given architecture across multiple operating systems (Particularly for i386 on Unix Systems), the efforts have not met with such success. Instead, operating systems tend to define their own ABIs ...

Quoting ... Linux System Programming page 4.

Armington answered 20/12, 2010 at 11:14 Comment(0)
A
6

An ABI, even for C, has parts which are quite platform independent, parts which depend on the processor (which registers should be saved, which are used for passing parameters,...) and parts which depend on the OS (more or less the same factors as for the processor as some choices are not imposed by the architecture but are the result of trade-offs, plus some OS's have a language independent notion of exception and so a compiler for any language has to generate the right thing to handle those, handling of threads may also impose things on the ABI -- if a register points to TLS, you can't use it for what you want).

In theory, every compiler may have its own ABI. But usually, for a couple processor/OS, the ABI is fixed by the OS vendor which often also provide a C compiler and common libraries which use that ABI and competitors prefer to be compatible. (I'd not be surprised if there are exceptions for some OS for which C isn't a major programming language).

But the OS vendor may switch ABI for one reason or the other (new versions of processors may have features that you want to use in the ABI for one - for instance some have asked for a 32bit ABI for x86_64 allowing to use all the registers). During the migration phase - which may be for a very long time - you may have to handle two ABI.

Alliaceous answered 20/12, 2010 at 14:24 Comment(0)
G
5

neither does C, right?
Right

On any given platform it pretty much does. It wouldn't be useful as the lingua franca for inter-language communication if it lacked one.
Pretty much might refer to architecture-specific defaults chosen by C compiler vendors being adapted within other languages. So if Keil's ARM C compiler will use left to right little endian parameter ordering and stack to pass arguments and some predetermined register for return value, then extern "C" from other compilers will assume compatibility with such scheme.

While such agreement maybe considered part of ABI, unlike managed execution context such as JVM browser sandbox, this is far from being complete standard ABI by itself.

Gehenna answered 10/4, 2013 at 8:30 Comment(0)
M
3

C does not have a standard ABI. This is easily illustrated by all the calling conventions (cdecl, fastcall and stdcall) that are used out there. Each is a different ABI.

EDIT: Although the C standard does not define an ABI, all platforms that I know have a standard predictable ABI or set of ABIs that the platform adheres to. These are often well documented.

Montalvo answered 20/12, 2010 at 11:11 Comment(0)
L
3

Prior to the C89 Standard, C compilers for many platforms used essentially the same ABI, save for variations in data sizes. For machines whose stack grows downward, code which calls a function would push the arguments on the stack in order from right to left and then call the function (pushing the return address in the process). A called function would leave its arguments on the stack, and the caller would at its leisure adjust the stack pointer to remove them [or, on some architectures, might adjust the stacked values in place]. While <stdarg.h> made it unnecessary for most programs to rely upon that convention, it remained in use for many years because it was simple and worked pretty well. While there was no "official" document establishing that as a cross-platform "standard", most compilers targeting machines with downward-growing stacks worked that way, leading to a greater level of consistency than exists today.

Lek answered 9/1, 2017 at 23:35 Comment(3)
So, just like an ABI, only with enough changes throughout that it doesn't make sense to call it an ABI? ;)Anuradhapura
@hmijail: Almost everyone who wrote C compilers for such machines would have known what other compilers did, and followed their lead in the absence of a reason to do anything else. A lot of "standards" aren't created by a standards body, but simply by the process of one person doing something and others doing likewise.Lek
Most CPUs can access registers faster than stack so it really doesn't make sense to standardize calling convetion that requires passing all arguments on the stack. And any method that prefers passing arguments using registers is obviously highly hardware dependant and cannot be a standard cross-platform.Diaspora
D
3

There's no standard ABI because C has always been about maximum runtime performance and the ABI with the highest performance depends on the underlying hardware. As a result, the ABI may use only stack or prefer registers for passing function call arguments and return values as needed for any given hardware.

For example, even amd64 (a.k.a x86-64) has two calling conventions: Microsoft x64 and System V AMD64 ABI. The former puts 4 first arguments to registers and the rest into the stack. The latter puts 6 first arguments to registers and the rest into the stack. I have no idea why Microsoft created non-compatible calling convention for amd64 hardware. For all I know, the Microsoft variant has a slightly worse performance and was created later.

For more information, see https://en.wikipedia.org/wiki/X86_calling_conventions

Diaspora answered 21/7, 2021 at 17:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.