Skip to content

Commit cafc482

Browse files
committed
blog post for v0 mangling on nightly
1 parent 423d051 commit cafc482

File tree

1 file changed

+171
-0
lines changed

1 file changed

+171
-0
lines changed
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
+++
2+
path = "2025/10/28/switching-to-v0-mangling-on-nightly"
3+
title = "Switching to Rust's own mangling scheme on nightly"
4+
authors = ["David Wood"]
5+
6+
[extra]
7+
team = "the compiler team"
8+
team_url = "https://www.rust-lang.org/governance/teams/compiler"
9+
+++
10+
11+
**TL;DR:** rustc will use its own "v0" mangling scheme by default on nightly
12+
versions
13+
14+
#### Context
15+
16+
When Rust is compiled into object files and binaries, each item (functions,
17+
statics, etc) must have a globally unique "symbol" identifying it.
18+
19+
In C, the symbol name of a function is just the name that the function was
20+
defined with, such as `strcmp`. This is straightforward and easy to
21+
understand, but requires that each item have a globally unique name
22+
that don't overlap with any symbols from shared libraries that might be linked
23+
against. If two items had the same symbol then when the linker tried to resolve
24+
a symbol to an address in memory (of a function, say), then it wouldn't know
25+
which symbol is the correct one.
26+
27+
Languages like Rust and C++ define "symbol mangling schemes", leveraging information
28+
from the type system to give each item a unique symbol name. Otherwise every
29+
instantiation of a generic or templated function (or an overload in C++), which has
30+
the same name in the surface language would end up with clashing symbols.
31+
32+
Rust originally used a symbol mangling scheme based on the
33+
[Itanium ABI's name mangling scheme][itanium-mangling] used by C++ (sometimes). Over
34+
the years, it was extended in an inconsistent and ad-hoc way to support Rust
35+
features that the mangling scheme wasn't originally designed for. Rust's current legacy
36+
mangling scheme has a number of drawbacks:
37+
38+
- Information about generic parameter instantiations is lost during mangling
39+
- It is internally inconsistent - some paths use an Itanium ABI-style encoding
40+
but some don't
41+
- Symbol names can contain `.` characters which aren't supported on all platforms
42+
- Symbol names depend on compiler internals and can't be easily replicated by
43+
other compilers or tools
44+
45+
If you've ever tried to use Rust with a debugger or a profiler and found it hard
46+
to work with because you couldn't work out which functions were which, it's probably
47+
because information was being lost in the mangling scheme.
48+
49+
Rust's compiler team started working on our own mangling scheme back in 2018
50+
with [RFC 2603][rfcs#2603] (see the ["v0 Symbol Format"][v0-mangling] chapter in
51+
rustc book for our current documentation on the format). Our "v0" mangling scheme has
52+
multiple advantageous properties:
53+
54+
- An unambigious encoding for everything that can end up in a binary's symbol table
55+
- Information about generic parameters are encoded in a reversible way
56+
- Mangled symbols are decodable such that it should be possible to identify concrete
57+
instances of generic functions
58+
- It doesn't rely on compiler internals
59+
- Symbols are restricted to only `A-Z`, `a-z`, `0-9` and `_`, helping ensure
60+
compatibility with tools on varied platforms
61+
- It tries to stay efficient and avoid unnecessarily long names and
62+
computationally-expensive decoding
63+
64+
However, rustc is not the only tool that interacts with Rust symbol names: the
65+
aforementioned debuggers, profilers and other tools all need to be updated to
66+
understand Rust's v0 symbol mangling scheme so that Rust's users can continue
67+
to work with Rust binaries using all the tools they're used to. Furthermore, all
68+
of those tools need to have new releases cut and then those releases need to be
69+
picked up by distros. This takes time!
70+
71+
Fortunately, the compiler team now believe that support for our v0 mangling
72+
scheme is now sufficiently widespread that it can start to be used by default by
73+
rustc.
74+
75+
#### Benefits
76+
77+
Reading Rust backtraces, or using Rust with debuggers, profilers and other
78+
tools that operate on compiled Rust code, will be able to output much more
79+
useful and readable names. This will especially help with async code,
80+
closures and generic functions.
81+
82+
It's easy to see the new mangling scheme in action, consider the following
83+
example:
84+
85+
```rust
86+
fn foo<T>() {
87+
panic!()
88+
}
89+
90+
fn main() {
91+
foo::<Vec<(String, &[u8; 123])>>();
92+
}
93+
```
94+
95+
With the legacy mangling scheme, all of the useful information about the generic
96+
instantiation of `foo` is lost in the symbol `f:foo`..
97+
98+
```
99+
thread 'main' panicked at f.rs:2:5:
100+
explicit panic
101+
stack backtrace:
102+
0: std::panicking::begin_panic
103+
at /rustc/d6c...582/library/std/src/panicking.rs:769:5
104+
1: f::foo
105+
2: f::main
106+
3: core::ops::function::FnOnce::call_once
107+
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
108+
```
109+
110+
..but with the v0 mangling scheme, the useful details of the generic instantiation
111+
are preserved with `f::foo::<alloc::vec::Vec<(alloc::string::String, &[u8; 123])>>`:
112+
113+
```
114+
thread 'main' panicked at f.rs:2:5:
115+
explicit panic
116+
stack backtrace:
117+
0: std::panicking::begin_panic
118+
at /rustc/d6c...582/library/std/src/panicking.rs:769:5
119+
1: f::foo::<alloc::vec::Vec<(alloc::string::String, &[u8; 123])>>
120+
2: f::main
121+
3: <fn() as core::ops::function::FnOnce<()>>::call_once
122+
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
123+
```
124+
125+
#### Possible drawbacks
126+
127+
Symbols using the v0 mangling scheme can be larger than symbols with the
128+
legacy mangling scheme, which can result in a slight increase in linking
129+
times. Fortunately this impact should be minor, especially with modern
130+
linkers like lld, which Rust [will now default to on some targets][switch-to-lld].
131+
132+
Some old versions of tools/distros or niche tools that the compiler team are
133+
unaware of may not have had support for the v0 mangling scheme added.
134+
135+
In any case, using the new mangling scheme can be disabled if any problem
136+
occurs: use the `-Csymbol-mangling-version=legacy -Zunstable-options` flag
137+
to revert to using the legacy mangling scheme.
138+
139+
#### Summary
140+
141+
rustc will use our "v0" mangling scheme on nightly for all targets
142+
starting in tomorrow's rustup nightly (`nightly-2025-XX-XX`).
143+
144+
Let us know if you encounter problems, by [opening an
145+
issue](https://github.com/rust-lang/rust/issues/new/choose) on GitHub.
146+
147+
If that happens, you can use the legacy mangling scheme with
148+
the `-Csymbol-mangling-version=legacy -Zunstable-options` flag. Either by
149+
adding it to the usual `RUSTFLAGS` environment variable, or to a
150+
project's [`.cargo/config.toml`] configuration file, like so:
151+
152+
```toml
153+
[build]
154+
rustflags = ["-Csymbol-mangling-version=legacy", "-Zunstable-options"]
155+
```
156+
157+
If you like the sound of the new symbol mangling version and would
158+
like to start using it on stable or beta channels of Rust, then you can
159+
similarly use the `-Csymbol-mangling-version=v0` flag today via
160+
`RUSTFLAGS` or [`.cargo/config.toml`]:
161+
162+
```toml
163+
[build]
164+
rustflags = ["-Csymbol-mangling-version=v0"]
165+
```
166+
167+
[`.cargo/config.toml`]: (https://doc.rust-lang.org/cargo/reference/config.html)
168+
[rfcs#2603]: https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html
169+
[itanium-mangling]: https://refspecs.linuxbase.org/cxxabi-1.86.html#mangling
170+
[v0-mangling]: https://doc.rust-lang.org/nightly/rustc/symbol-mangling/v0.html
171+
[switch-to-lld]: https://blog.rust-lang.org/2025/09/01/rust-lld-on-1.90.0-stable/

0 commit comments

Comments
 (0)