Pre-RFC: defining globals in global_asm!

Rust's asm story currently has some big limitations related to defining globals from asm blocks. Specifically, there are two limitations:

  • You have to pick the symbol name yourself. You cannot ask the compiler to pick a name using e.g. name mangling.
  • Symbols have to be marked global because otherwise they cannot cross CGU boundaries.

The second problem is quite problematic. Let's say you tried to define a symbol like this:

extern "C" {
    static MY_GLOBAL_U64: u64;
}

global_asm!(
    "MY_GLOBAL_U64:",
    ".quad 17"
);

fn get_seventeen() -> u64 {
    MY_GLOBAL_U64
}

Then if you compile with more than one CGU (code generation unit), then there's a chance that the global asm block and the get_seventeen() function end up in different CGUs. Since the symbol is only locally defined, this will lead to a linker error because get_seventeen() cannot find the MY_GLOBAL_U64 symbol.


Because of the above two issues, I propose adding the ability to place a defines {} block when using assembly in Rust.

global_asm!(
    "{MY_GLOBAL_U64}:",
    ".quad 17",
    defines {
        static MY_GLOBAL_U64: u64;
    }
);

fn get_seventeen() -> u64 {
    MY_GLOBAL_U64
}

The behavior of the above code is like so:

  1. Because the defines block mentions a MY_GLOBAL_U64 of type u64, we can now write MY_GLOBAL_U64 to access said symbol.
  2. Since the static is not marked #[no_mangle], the name is chosen using the usual name mangling rules. Exactly the same as if you had declared a normal static in the same location as the asm block.
  3. Inside the asm block, you may use {MY_GLOBAL_U64} to get the actual symbol name chosen for the static.
  4. Since Rust knows that MY_GLOBAL_U64 is defined by that global_asm! block, Rust can insert the appropriate exports from the CGUs to ensure that even if get_seventeen() ends up in a different CGU, it will still work correctly.

A few other notes:

  • You can place both statics and functions inside of defines {} to allow defining either kind of symbol.
  • I also think it makes sense to allow defines {} for inline asm blocks as well. In this case, we need to keep in mind that such blocks are duplicated by monomorphization and inlining, which means that such statics are not unique, and symbol mangling must choose unique names for each duplicate static.
5 Likes

I'm not sure if we can actually ensure unique names for LLVM inlining. I know LLVM has a way to get unique names inside an inline asm block, but I don't think you can access that unique name outside the inline asm.

1 Like