rust-lang / rust-lang/rust

Dollar sign is handled incorrectly for section names in inline-assembly on Windows platform

Open
#128,177 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-inline-assembly C-bug T-compiler
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

I tried this code:

fn main() {
    unsafe {
        core::arch::asm!(
            r#"
        .pushsection .foo$a
        .long 0x1234
        .popsection
        "#
        );
    }
}

I expected to see this happen: Generated executable contains a section named ".foo".

Instead, this happened: Generated executable contains a section named ".fooa".

Further explanation:

On Windows platform, section names are divided by "$". The former part is used as section name in final binary, and the latter part is used to sort and merge sections with names with same former part, and the latter part will be erased in final binary. For example, if I declare a section ".foo$a" in source code, it will be generated to section ".foo" in final executable.

This is a extremely useful feature to achieve a symbol pointing to the start and end of certain sections (See this and this, and this is what the famous linkme crate does). If we use link_section attribute on statics in Rust, things go right:

#[link_section = ".foo$a"]
#[used]
static mut MY_VAR: xxxx = xxxx;

The MY_VAR will be generated into ".foo" section.

However, in some situations, we can only use inline assembly instead of statics to declare some datas (more concretely, I'm re-implementing Linux kernel's static-keys mechanism into Rust userland, see static-keys). And the inline-assembly generates the wrong section name, which prevents us from getting the right section-start and section-end symbols.

Moreover, I use RUSTFLAGS="--emit asm" to check, it turns out that, inside generated assembly file, the section name has already become ".fooa" instead of ".foo$a", so it is not a linker bug.

I don't if this bug is Rust-related or LLVM-related (since it is hard to use LLVM tools to write a C inline-asm to test on a Windows platform), and hope someone could help. :) BTW, by searching ".split('$').second" in LLVM source code, it seems that there is nothing wrong?

Meta

rustc --version --verbose:

rustc 1.79.0 (129f3b996 2024-06-10)
binary: rustc
commit-hash: 129f3b9964af4d4a709d1383930ade12dfe7c081
commit-date: 2024-06-10
host: x86_64-pc-windows-msvc
release: 1.79.0
LLVM version: 18.1.7

rustc +nightly --version --verbose:

rustc 1.82.0-nightly (c1a6199e9 2024-07-24)
binary: rustc
commit-hash: c1a6199e9d92bb785c17a6d7ffd8b8b552f79c10
commit-date: 2024-07-24
host: x86_64-pc-windows-msvc
release: 1.82.0-nightly
LLVM version: 18.1.7

Contributor guide

Open the contributing guide

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

Start with the inline-assembly reproducer on x86_64-pc-windows-msvc and inspect the generated assembly produced by RUSTFLAGS="--emit asm". Trace where .foo$a becomes .fooa, compare it with the working link_section behavior, and add a regression test showing that the dollar-suffixed section is emitted and linked as .foo.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers, operating-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.