rust-lang / rust-lang/rust

`-Zregparm` doesn't put 64-bit arguments in registers

Open
#145,694 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

-Zregparm A-ABI A-rust-for-linux C-bug O-x86_32 T-compiler
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

The -Zregparm option on 32-bit x86 should pass arguments in registers where possible, but for 64-bit arguments, it will push them onto the stack, whereas C compilers (both gcc and clang) will put them in a pair of registers.

For example, the following rust code:

unsafe extern "C" {
    pub fn test(s: i64) -> i64;
}

#[unsafe(no_mangle)]
pub fn f1() {
    unsafe {
        let r = test(42);
    }
}

compiles to (with -Zregparm=3):

f1:
        sub     esp, 20
        push    0
        push    42
        call    test
        add     esp, 28
        ret

Note the 64-bit value is put on the stack.

However, the equivalent C code:

extern long long test(long long s);

void f1(void)
{
    long long r = test(42);
}

compiles to (gcc 15.2 with -mregparm=3, but clang produces something similar):

f1():
        push    ebp
        mov     ebp, esp
        sub     esp, 24
        mov     eax, 42
        mov     edx, 0
        call    test(long long)
        mov     DWORD PTR [ebp-16], eax
        mov     DWORD PTR [ebp-12], edx
        nop
        leave
        ret

Note that the 64-bit value is put in edx:eax.

This can cause crashes/incorrect results due to an ABI mismatch, particularly in Rust-for-Linux on 32-bit x86.

Note that 64-bit return values seem to be functioning correctly, and are placed in edx:eax.

Compiler explorer link with the above examples: https://godbolt.org/z/feb7addG7

Rust-for-Linux tracking issue for 32-bit x86: https://github.com/Rust-for-Linux/linux/issues/78
Tracking issue for -Zregparm: https://github.com/rust-lang/rust/issues/131749

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 -Zregparm behavior and compare the Rust output in the linked Compiler Explorer example with the gcc and clang outputs. Use the -Zregparm tracking issue and Rust-for-Linux issue for context; done means 64-bit arguments on 32-bit x86 follow the expected register ABI without breaking the existing return-value behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, rust
Domain
compilers
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.