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 #1520.
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
\01byte marker, see the language reference. Cranelift should probably implement something similar.For example, the
linkmecrate'sdistributed_sliceuses this to access the specialsection$start$SEGMENT$SECTIONandsection$end$SEGMENT$SECTIONsymbols 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:
That is, add various items to a custom
__DATAsection, and then use the special directives to get the bounds of that section.You can observe the difference with:
The Cranelift-compiled one will have symbol references with
\x01_(the0x01byte is invisible), while the LLVM-compiled one will have symbol references with no prefix.EDIT: Related to #1520.