Modular ABI for Rust

Disclaimer: I hope I didn't miss anything important, I beg forgiveness if some questions are already answered.

ABI != Memory Layout

I've seen a lot of emphasis on memory layout in this thread. The memory layout of types is part of ABI, indeed, but there seems to be quite a few things missing:

  • I have not seen any mention of the memory layout of v-tables.
  • I have not seen any mention of the memory layout of fat-pointers.
  • I have not seen any mention of calling conventions.
  • I have not seen any mention of exception handling.

For reference, here is a complete ABI for C++: The Itanium ABI.

Better is the enemy of Good

I found that the thread started in a reasonable fashion: allowing ABI evolution, whilst offering ABI guarantees. It then took a turn for the unexpected by jumping from the ability to Select an ABI to the ability to Define an ABI.

Now, the ability to completely define an ABI in completely arbitrary ways is kinda awesome. At the same time, it also seems vastly more complex, and this is reflected in the discussion: we've gone from "how to get a stable ABI" to "how to get a stable API for the ABI-defining crate".

I really think that we should take a step back here.

Let's postpone the ABI-defining crate -- it's not a bad idea, it's just a long-term one -- and instead focus on ABI-selection.

Selecting an ABI for fun and profit.

I would propose to start simple: ABI selection.

At the moment, the ABI is defined within the compiler. Let's keep it as is. Or rather, let's keep them as is.

Let us define 2 ABI flags to start with:

  • --abi=latest (default).
  • --abi=2020 or --abi=1.43.1 or whatever version you want.

At the moment? They're both the same, it's just that a slightly different symbol hash is generated (different flag).

This insta-stabilize the current ABI as --abi=2020 (or whatever), and promises that this one will never change. If any change is introduced, then --abi=latest automatically picks it up, while --abi=2020 doesn't change.

Simple, Complicated

The scheme I propose seems like the simple scheme to obtain a stable ABI, and therefore the quickest way to get one.

In practice, though, it's a bit more complicated than that.

Technically, the work to be done is relatively simple. I think implementation-wise the simplest solution is to abstract all ABI decisions behind a trait, and then have two implementations -- which happen to be identical right now -- and create a test-suite to prevent regression of the stable ABI.

Socially, however, you need the compiler developers to buy into this: they'll be the ones tasked with maintenance, after all. Some policy will have to be decided as well: How many ABIs are kept around? How often is a new ABI cut? Are new features retrofitted in previous (stable) ABIs? How?

You don't have to have the answers now, but the answers will be needed before this proposal is accepted.

In parting

I think the ability to select/define an ABI would really help Rust adoption, thanks for working on this.

3 Likes