Skip to content

Rust "forgets" intel attribute on assembly code sometimes #70337

Closed
@dbartussek

Description

@dbartussek

I tried this code:

#![no_std]
#![no_main]
#![feature(asm)]
#![feature(lang_items)]

///! A small reproduction case
///!
///! Build with `cargo build`
///!
///! Notes:
///! - setting opt-level to 0 or 1 compiles
///! - opt-level 2, 3, "s", "z" cause the error
///! - a release build works just fine, just a debug build with optimization has the issue

use core::mem::{ManuallyDrop, MaybeUninit};
use core::panic::PanicInfo;

pub unsafe fn call_with_stack<T>(
    arg: &mut T,
    function: extern "sysv64" fn(&mut T) -> (),
    stack: *mut u8,
) {
    asm!(r#"
    mov rbp, rsp
    mov rsp, $2

    call $1

    mov rsp, rbp
    "#
    : // Return values
    : "{rdi}"(arg), "r"(function), "r"(stack) // Arguments
    : "rbp", "cc", "memory" // Clobbers
    : "volatile", "intel" // Options
    );
}

/// Calls a closure and returns the result
///
/// This function is unsafe because it changes the stack pointer to stack.
/// stack must be suitable to be used as a stack pointer on the target system.
pub unsafe fn call_closure_with_stack<F, R>(closure: F, stack: *mut u8) -> R
where
    F: FnOnce() -> R,
{
    extern "sysv64" fn inner<F, R>(data: &mut (ManuallyDrop<F>, MaybeUninit<R>))
    where
        F: FnOnce() -> R,
    {
        let result = {
            // Read the closure from context, taking ownership of it
            let function = unsafe { ManuallyDrop::take(&mut data.0) };

            // Call the closure.
            // This consumes it and returns the result
            function()
        };

        // Write the result into the context
        data.1 = MaybeUninit::new(result);
    }

    // The context contains the closure and uninitialized memory for the return value
    let mut context = (ManuallyDrop::new(closure), MaybeUninit::uninit());

    call_with_stack(
        &mut context,
        // We create a new, internal function that does not close over anything
        // and takes a context reference as its argument
        inner,
        stack,
    );

    // Read the result from the context
    // No values are in the context anymore afterwards
    context.1.assume_init()
}

#[no_mangle]
pub unsafe fn _start(stack: *mut u8) {
    call_closure_with_stack(|| (), stack);
}

#[no_mangle]
pub unsafe fn efi_main(stack: *mut u8) {
    call_closure_with_stack(|| (), stack);
}

#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}

#[lang = "eh_personality"] extern fn eh_personality() {}

I expected to see this happen:
The inline assembly should be compiled in intel syntax

Instead, this happened:
Under some circumstances, Rust seems to forget about the intel attribute and tries to compile it as AT&T assembly.
I have not found a consistent reason for this, if the code compiles or not changes seemingly at random with different compile options or code reordering.
Removing call_closure_with_stack also made resulted in no error, but I am not sure if it is the cause or just massages the code in such a way that the issue goes silent.

full cargo error message with --verbose

   Compiling asm_test v0.1.0 (C:\Users\Dario\RustProjects\asm_test)
     Running `rustc --crate-name asm_test --edition=2018 'src\main.rs' --error-format=json --json=diagnostic-rendered-ansi --crate-type bin --emit=dep-info,link -C opt-level=s -C debuginfo=2 -C debug-assertions=on -C metadata=ff8ce8b6214d71b9 --out-dir 'C:\Users\Dario\RustProjects\asm_test\target\debug\deps' -C 'incremental=C:\Users\Dario\RustProjects\asm_test\target\debug\incremental' -L 'dependency=C:\Users\Dario\RustProjects\asm_test\target\debug\deps' -Ctarget-feature=+crt-static`
error: <inline asm>:2:5: error: unknown use of instruction mnemonic without a size suffix
    mov rbp, rsp
    ^

  --> src\main.rs:23:5
   |
23 | /     asm!(r#"
24 | |     mov rbp, rsp
25 | |     mov rsp, $2
26 | |
...  |
34 | |     : "volatile", "intel" // Options
35 | |     );
   | |______^

error: <inline asm>:5:5: error: unknown use of instruction mnemonic without a size suffix
    call %rax
    ^

  --> src\main.rs:23:5
   |
23 | /     asm!(r#"
24 | |     mov rbp, rsp
25 | |     mov rsp, $2
26 | |
...  |
34 | |     : "volatile", "intel" // Options
35 | |     );
   | |______^

error: <inline asm>:7:5: error: unknown use of instruction mnemonic without a size suffix
    mov rsp, rbp
    ^

  --> src\main.rs:23:5
   |
23 | /     asm!(r#"
24 | |     mov rbp, rsp
25 | |     mov rsp, $2
26 | |
...  |
34 | |     : "volatile", "intel" // Options
35 | |     );
   | |______^

error: aborting due to 3 previous errors

error: could not compile `asm_test`.

Caused by:
  process didn't exit successfully: `rustc --crate-name asm_test --edition=2018 'src\main.rs' --error-format=json --json=diagnostic-rendered-ansi --crate-type bin --emit=dep-info,link -C opt-level=s -C debuginfo=2 -C debug-assertions=on -C metadata=ff8ce8b6214d71b9 --out-dir 'C:\Users\Dario\RustProjects\asm_test\target\debug\deps' -C 'incremental=C:\Users\Dario\RustProjects\asm_test\target\debug\incremental' -L 'dependency=C:\Users\Dario\RustProjects\asm_test\target\debug\deps' -Ctarget-feature=+crt-static` (exit code: 1)

Meta

rustc --version --verbose:
Windows:

rustc 1.44.0-nightly (f509b26a7 2020-03-18)
binary: rustc
commit-hash: f509b26a7730d721ef87423a72b3fdf8724b4afa
commit-date: 2020-03-18
host: x86_64-pc-windows-msvc
release: 1.44.0-nightly
LLVM version: 9.0

Linux:

rustc 1.44.0-nightly (f509b26a7 2020-03-18)
binary: rustc
commit-hash: f509b26a7730d721ef87423a72b3fdf8724b4afa
commit-date: 2020-03-18
host: x86_64-unknown-linux-gnu
release: 1.44.0-nightly
LLVM version: 9.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-inline-assemblyArea: Inline assembly (`asm!(…)`)C-bugCategory: This is a bug.P-lowLow priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.requires-nightlyThis issue requires a nightly compiler in some way.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions