You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Add support for suppressing name mangling with \01 prefix #1689
Normal Mach-O symbols are prefixed with _, non-prefixed symbols are reserved for special use. EDIT: Other platforms have similar name mangling rules.
LLVM allows you to opt out of symbol mangling by prefixing your symbol with the \01 byte marker, see the language reference. Cranelift should probably implement something similar.
For example, the linkme crate's distributed_sliceuses this to access the special section$start$SEGMENT$SECTION and section$end$SEGMENT$SECTION symbols that the linker will replace with the address to respectively the start and end of the specified symbol.
The basic pattern they use is something like this:
The Cranelift-compiled one will have symbol references with \x01_ (the 0x01 byte is invisible), while the LLVM-compiled one will have symbol references with no prefix.
This is now also important for the ctor crate, as it uses a similar pattern internally since mmastrac/linktime#368 (released in ctor v0.9.0), CC @mmastrac. See also #1588 (which will be fixed soon by #1648).
\x01 is an LLVM invention and doesn't have anything to do with Mach-O. It is a no-op on ELF and has effect on Windows too. We never officially blessed this as supported by Rust the language. The LLVM backend just accidentally supported it due to not supporting it needing an extra check. I would prefer not to support this in cg_clif unless it is officially blessed as being part of Rust and required to be supported by all backends. I don't know if cg_gcc can implement it at all for example.
changed the title [-]Add support for Mach-O unprefixed symbol `\x01` convention[/-][+]Add support for suppressing name mangling with `\01` prefix[/+]on Aug 10, 2026
changed the title [-]Add support for suppressing name mangling with `\01` prefix[/-][+]Add support for suppressing Mach-O name mangling with `\01` prefix[/+]on Aug 10, 2026
changed the title [-]Add support for suppressing Mach-O name mangling with `\01` prefix[/-][+]Add support for suppressing name mangling with `\01` prefix[/+]on Aug 10, 2026
mangling = "none" would be great, and ideally for both sections and symbols. FWIW we also need that escape hatch for WASM where some section names were baked into WASM custom sections (and for supporting other section types like .fini_array).
The ctor MSRV is 1.60 which might allow me to move over to a global_asm approach (I can test that out), but this is an escape hatch the language badly needs in any case.
I need to think a bit more about this to make sure it doesn't break in strange ways, but scattered-collect's tests pass fully which exercise all the demons in link-time manipulation, including those that test if a section is empty.
But the instructions to emit here depends on rust-lang/rust#114929 and the architecture, which would be kinda undesirable for linkme/ctor.
Does macOS have multiple relocation models in practice at all? I would expect outside of perhaps the dynamic linker itself and some core system utils, everything would be have to be dynamically linked. And -Crelocation-model=static and -Crelocation-model=pic seem to result in the exact same assembly on aarch64-apple-darwin, using a GOT relocation for statics in both cases.
Does macOS have multiple relocation models in practice at all?
I couldn't find a way to get the compiler to generate something else either, but I'm not that experienced in how relocation models work, so I put it as a sort of disclaimer (and because making this work with inline asm for non-Mach-O targets would possibly need it?). Might also be a different story on older x86 macOS / ARM iOS?
Regardless, I like the global_asm! alias solution that mmastrac proposes better than inline asm.
If a caller does want explicit duplicates like the \x01 prefix previously allowed, they would need to disambiguate using a name built from the cargo crate-name env var, module path, file, etc. link-section doesn't need that.
The alternative is a naked function and just always emit the GOT-related load. I'm not super-familiar with relocation types on macOS, but it appears that the linker folds unnecessary GOT-relative instructions as needed so this is probably safe as an alternative.
Ok, so results of a research spike over in linktime:
.private_extern + .set works for ld64
in rust-lld, .set does not support section$start$__DATA$foo because those are unknown symbols at the time of linking and the lld driver doesn't know how to make them work as aliases (arguably an lld bug).
caveat to above: a local alias does work because it collapses into a standard extern reference before lld touches it
a .quad symbol works and a naked function works, but neither of those support const context which may be a breaking change for some crates
\x01 is the portable solution today and unfortunately I have not found a replacement that is cross-linker compatible and const-friendly.
global_asm! and asm! blocks get promoted to their own files in cranelift which may be a big surprise downstream
What would help:
#[unsafe(link_section = "...", mangled = "...")], but only if we get a cfg(cranelift) so we can use it there, because that would be a pretty rough MSRV hit
\x01 support in cranelift (sucks to enshrine it, but maybe it can be deprecated in a few years)
Fixing lld (a less painful MSRV hit)
Special-casing some basic forms of asm-blocks to codegen in the same file (ick)
Maybe we could support \x01 but only for \x01section$start$ and \x01section$end$ on Mach-O platforms and on nothing else? And with a comment that the exception might get removed if we get something like #[unsafe(link_name(symbol = "...", modifiers = "+verbatim"))] (or whatever syntax ends up getting implemented).
That would be perfect. I don't believe any of the linker shenanigan crates rely on any other use of it. I'd be happy to spitball a proposal with someone to start the process for a revision on link_name.
Activity
madsmtm commentedon Aug 10, 2026
This is now also important for the
ctorcrate, as it uses a similar pattern internally since mmastrac/linktime#368 (released inctor v0.9.0), CC @mmastrac. See also #1588 (which will be fixed soon by #1648).bjorn3 commentedon Aug 10, 2026
\x01is an LLVM invention and doesn't have anything to do with Mach-O. It is a no-op on ELF and has effect on Windows too. We never officially blessed this as supported by Rust the language. The LLVM backend just accidentally supported it due to not supporting it needing an extra check. I would prefer not to support this in cg_clif unless it is officially blessed as being part of Rust and required to be supported by all backends. I don't know if cg_gcc can implement it at all for example.[-]Add support for Mach-O unprefixed symbol `\x01` convention[/-][+]Add support for suppressing name mangling with `\01` prefix[/+][-]Add support for suppressing name mangling with `\01` prefix[/-][+]Add support for suppressing Mach-O name mangling with `\01` prefix[/+]madsmtm commentedon Aug 10, 2026
Do you know of a good alternative that
linkmeetc. could use instead? Inline assembly?[-]Add support for suppressing Mach-O name mangling with `\01` prefix[/-][+]Add support for suppressing name mangling with `\01` prefix[/+]madsmtm commentedon Aug 10, 2026
I guess we could formally add something like this to the language:
#[unsafe(link_section(name = "section$start$__DATA$__MY_SECTION", mangling = "none"))]But that has MSRV concerns so would probably take a while to get adopted :/
madsmtm commentedon Aug 10, 2026
For the record, something similar is possible in both Clang and GCC with:
Though this uses
__asm__, which is definitely lower-level (__attribute__((section(...)))disallows\01likerustcperhaps should've done too).mmastrac commentedon Aug 10, 2026
mangling = "none"would be great, and ideally for both sections and symbols. FWIW we also need that escape hatch for WASM where some section names were baked into WASM custom sections (and for supporting other section types like .fini_array).The
ctorMSRV is 1.60 which might allow me to move over to aglobal_asmapproach (I can test that out), but this is an escape hatch the language badly needs in any case.madsmtm commentedon Aug 10, 2026
Getting the symbols with inline assembly on Aarch64 macOS PIC is definitely possible:
But the instructions to emit here depends on the relocation model and the architecture, which would be kinda undesirable for
linkme/ctor.mmastrac commentedon Aug 10, 2026
This might work as well, but I need to make sure it doesn't interact badly with other functionality:
mmastrac commentedon Aug 10, 2026
Confirming this works:
mmastrac/linktime#518
I need to think a bit more about this to make sure it doesn't break in strange ways, but
scattered-collect's tests pass fully which exercise all the demons in link-time manipulation, including those that test if a section is empty.bjorn3 commentedon Aug 10, 2026
Does macOS have multiple relocation models in practice at all? I would expect outside of perhaps the dynamic linker itself and some core system utils, everything would be have to be dynamically linked. And
-Crelocation-model=staticand-Crelocation-model=picseem to result in the exact same assembly on aarch64-apple-darwin, using a GOT relocation for statics in both cases.madsmtm commentedon Aug 10, 2026
I couldn't find a way to get the compiler to generate something else either, but I'm not that experienced in how relocation models work, so I put it as a sort of disclaimer (and because making this work with inline asm for non-Mach-O targets would possibly need it?). Might also be a different story on older x86 macOS / ARM iOS?
Regardless, I like the
global_asm!alias solution that mmastrac proposes better than inline asm.mmastrac commentedon Aug 10, 2026
Slightly better approach which avoids exporting the renamed symbol but still allows Rust to link it:
If a caller does want explicit duplicates like the
\x01prefix previously allowed, they would need to disambiguate using a name built from the cargo crate-name env var, module path, file, etc.link-sectiondoesn't need that.The alternative is a
nakedfunction and just always emit the GOT-related load. I'm not super-familiar with relocation types on macOS, but it appears that the linker folds unnecessary GOT-relative instructions as needed so this is probably safe as an alternative.mmastrac commentedon Aug 10, 2026
Ok, so results of a research spike over in
linktime:.private_extern+.setworks for ld64rust-lld,.setdoes not supportsection$start$__DATA$foobecause those are unknown symbols at the time of linking and the lld driver doesn't know how to make them work as aliases (arguably an lld bug)..quadsymbol works and a naked function works, but neither of those supportconstcontext which may be a breaking change for some crates\x01is the portable solution today and unfortunately I have not found a replacement that is cross-linker compatible and const-friendly.global_asm!andasm!blocks get promoted to their own files in cranelift which may be a big surprise downstreamWhat would help:
#[unsafe(link_section = "...", mangled = "...")], but only if we get acfg(cranelift)so we can use it there, because that would be a pretty rough MSRV hit\x01support in cranelift (sucks to enshrine it, but maybe it can be deprecated in a few years)bjorn3 commentedon Aug 11, 2026
Maybe we could support
\x01but only for\x01section$start$and\x01section$end$on Mach-O platforms and on nothing else? And with a comment that the exception might get removed if we get something like#[unsafe(link_name(symbol = "...", modifiers = "+verbatim"))](or whatever syntax ends up getting implemented).madsmtm commentedon Aug 11, 2026
I'd be fine with that
mmastrac commentedon Aug 11, 2026
That would be perfect. I don't believe any of the linker shenanigan crates rely on any other use of it. I'd be happy to spitball a proposal with someone to start the process for a revision on link_name.