rust-lang / rust-lang/rustc_codegen_cranelift

Add support for suppressing name mangling with `\01` prefix

Open
#1,689 16 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

O-macos
Dominant language
Rust
Stars
2.1k
Forks
157
Avg merge
1d 19h
Merged PRs (30d)
3

Description

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_slice uses 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:

use std::{mem, slice};

unsafe extern "Rust" {
    #[link_name = "\x01section$start$__DATA$__MY_SECTION"]
    static MY_SECTION_START: [fn(); 0];
    #[link_name = "\x01section$end$__DATA$__MY_SECTION"]
    static MY_SECTION_STOP: [fn(); 0];
}

#[used]
#[unsafe(link_section = "__DATA,__MY_SECTION,regular,no_dead_strip")]
static ITEM1: fn() = || println!("1");

#[used]
#[unsafe(link_section = "__DATA,__MY_SECTION,regular,no_dead_strip")]
static ITEM2: fn() = || println!("2");

fn main() {
    let start = (&raw const MY_SECTION_START).cast::<fn()>();
    let stop = (&raw const MY_SECTION_STOP).cast::<fn()>();

    let byte_offset = stop as usize - start as usize;
    let len = byte_offset / mem::size_of::<fn()>();
    let items = unsafe { slice::from_raw_parts(start, len) };

    for fnptr in items {
        fnptr();
    }
}

That is, add various items to a custom __DATA section, and then use the special directives to get the bounds of that section.

You can observe the difference with:

$ rustc foo.rs --emit obj -o llvm.o
$ objdump -t llvm.o | rg section
0000000000000000         *UND* section$end$__DATA$__MY_SECTION
0000000000000000         *UND* section$start$__DATA$__MY_SECTION

$ $cg_clif_dir/dist/rustc-clif foo.rs --emit obj -o clif.o
$ objdump -t clif.o | rg section
0000000000000000         *UND* _section$end$__DATA$__MY_SECTION
0000000000000000         *UND* _section$start$__DATA$__MY_SECTION

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.

EDIT: Related to https://github.com/rust-lang/rustc_codegen_cranelift/issues/1520.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the mismatch with foo.rs using rustc --emit obj and rustc-clif, then inspect the symbol emission and name-mangling entry point in rustc_codegen_cranelift. Compare objdump -t output for the section$start and section$end symbols; done when the Cranelift object preserves the \x01 opt-out and matches LLVM without the extra underscore.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.