"Linker shenanigans." I'm not the best person to explain it, @dtolnay would be the one who understands how the linkme implementation works the best.
But the short version, as I understand it, is:
With linker shenanigans:
- In creating a distributed slice "registry" called NAME, we set up three linker sections, the exact name and method of which are platform dependent, but we'll call
__linkme_NAME
,__linkme_start_NAME
, and__linkme_end_NAME
. - We ask the linker to lay these sections out such that
__linkme_start_NAME
is directly followed by__linkme_NAME
which is then directly followed by__linkme_end_NAME
. - Each item put in the distributed slice is (of known, verified type and) placed as a
static
in the__linkme_NAME
section. - Again through platform/linker-specific tricks, we define
static
s that reside in the__linkme_start_NAME
and__linkme_end_NAME
sections. - We at runtime use those two
static
s to create our slice; we effectively have a "first before the start" and "first past the end" pointer from which to derive our linker-assembled slice.
This is almost certainly actually UB in a strict sense, as the Rust Abstract Machine doesn't have a concept of what we're doing here. In practice, this is closer to platform-defined behavior.
With compiler support, it would work much the same way, except that because the compiler itself knows about it, it wouldn't require platform linker support, just rustc linker support. At a high level,
- The registry crate defines a distributed slice as a
static
. - Any
static
which is placed in the distributed slice is marked specially in the rlib as being part of the distributed slice. - When rustc is invoked to link together the rlibs into an executable, it first finds all of the statics marked as part of the distributed slice, and orchestrates the platform-specific operations to put them in a continuous statically allocated slice. This may be linker directives on some platforms (e.g. the ones linkme already supports), or it may be in directly reässembling the individual static sections into one static section (and references from the children back to the parent) before handing it off to the platform linker.
- Notably, the Abstract Machine is now dealing with an actual slice of linktime determined size, rather than seeing you accessing outside of these
static
s you've defined, so it's no longer strictly speaking UB, and there's no danger of future optimizations breaking the behavior.
All of this of course only works with static linking.