Skip to content

-Zregparm doesn't put 64-bit arguments in registers #145694

@sulix

Description

@sulix

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: Rust-for-Linux/linux#78
Tracking issue for -Zregparm: #131749

Metadata

Metadata

Assignees

No one assigned

    Labels

    -ZregparmUnstable option: -ZregparmA-ABIArea: Concerning the application binary interface (ABI)A-rust-for-linuxRelevant for the Rust-for-Linux projectC-bugCategory: This is a bug.O-x86_32Target: x86 processors, 32 bit (like i686-*) (also known as IA-32, i386, i586, i686)T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions