Skip to content

Invalid inline assembly is silently discarded #22892

Closed
@devyn

Description

@devyn

Minimal testcase:

#![feature(asm)]

fn main() {
    let byte = 0;
    let port = 0x80;

    unsafe { asm!("out %al, %dx" :: "a" (byte), "d" (port) :: "volatile"); }
}

rustc --version:

rustc 1.0.0-nightly (4db0b3246 2015-02-25) (built 2015-02-26)

rustc output:

$ rustc mintest.rs
$

(i.e., nothing)

Resulting objdump on x86_64-unknown-linux-gnu:

0000000000005070 <_ZN4main20h953519ae653eac04eaaE>:
    5070:       64 48 3b 24 25 70 00    cmp    %fs:0x70,%rsp
    5077:       00 00 
    5079:       77 1a                   ja     5095 <_ZN4main20h953519ae653eac04eaaE+0x25>
    507b:       49 ba 10 00 00 00 00    movabs $0x10,%r10
    5082:       00 00 00 
    5085:       49 bb 00 00 00 00 00    movabs $0x0,%r11
    508c:       00 00 00 
    508f:       e8 80 00 00 00          callq  5114 <__morestack>
    5094:       c3                      retq   
    5095:       48 83 ec 10             sub    $0x10,%rsp
    5099:       c7 44 24 0c 00 00 00    movl   $0x0,0xc(%rsp)
    50a0:       00 
    50a1:       c7 44 24 08 80 00 00    movl   $0x80,0x8(%rsp)
    50a8:       00 
    50a9:       8b 44 24 0c             mov    0xc(%rsp),%eax
    50ad:       8b 4c 24 08             mov    0x8(%rsp),%ecx
    50b1:       89 44 24 04             mov    %eax,0x4(%rsp)
    50b5:       89 0c 24                mov    %ecx,(%rsp)
    50b8:       48 83 c4 10             add    $0x10,%rsp
    50bc:       c3                      retq   
    50bd:       0f 1f 00                nopl   (%rax)

Unless I'm missing something, I should either get an error, or I should see "out %al, %dx" somewhere in there, but instead, absolutely nothing happens.

Activity

devyn

devyn commented on Mar 1, 2015

@devyn
Author

LLVM IR appears to include the inline asm, so I'm guessing this is an LLVM bug:

; ModuleID = 'mintest.0.rs'
target datalayout = "e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

@const10 = internal unnamed_addr constant i32 0
@const14 = internal unnamed_addr constant i32 128

; Function Attrs: uwtable
define internal void @_ZN4main20h4fb6a247161ac946eaaE() unnamed_addr #0 {
entry-block:
  %byte = alloca i32
  %port = alloca i32
  store i32 0, i32* %byte
  store i32 128, i32* %port
  %0 = load i32* %byte
  %1 = load i32* %port
  call void asm sideeffect "out %al, %dx", "a,d,~{dirflag},~{fpsr},~{flags}"(i32 %0, i32 %1), !srcloc !0
  ret void
}

define i64 @main(i64, i8**) unnamed_addr #1 {
top:
  %2 = call i64 @_ZN2rt10lang_start20hb1b8686306685c6ftRLE(i8* bitcast (void ()* @_ZN4main20h4fb6a247161ac946eaaE to i8*), i64 %0, i8** %1)
  ret i64 %2
}

declare i64 @_ZN2rt10lang_start20hb1b8686306685c6ftRLE(i8*, i64, i8**) unnamed_addr #1

attributes #0 = { uwtable "split-stack" }
attributes #1 = { "split-stack" }

!0 = !{i32 1}

I'll check to see what clang does.

devyn

devyn commented on Mar 1, 2015

@devyn
Author

C source:

int main(int argc, char **argv)
{
    unsigned char  byte = 0;
    unsigned short port = 0x80;

    asm volatile("out %%al, %%dx" :: "a" (byte), "d" (port));
}

clang LLVM IR (clang -emit-llvm -S mintest.c):

; ModuleID = 'mintest.c'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

; Function Attrs: nounwind uwtable
define i32 @main(i32 %argc, i8** %argv) #0 {
  %1 = alloca i32, align 4
  %2 = alloca i8**, align 8
  %byte = alloca i8, align 1
  %port = alloca i16, align 2
  store i32 %argc, i32* %1, align 4
  store i8** %argv, i8*** %2, align 8
  store i8 0, i8* %byte, align 1
  store i16 128, i16* %port, align 2
  %3 = load i8* %byte, align 1
  %4 = load i16* %port, align 2
  call void asm sideeffect "out %al, %dx", "{ax},{dx},~{dirflag},~{fpsr},~{flags}"(i8 %3, i16 %4) #1, !srcloc !1
  ret i32 0
}

attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind }

!llvm.ident = !{!0}

!0 = metadata !{metadata !"clang version 3.5.1 (tags/RELEASE_351/final)"}
!1 = metadata !{i32 115}

So it looks like it might be a Rust bug after all; Rust should be generating {ax} and {dx} constraints in the IR?

devyn

devyn commented on Mar 2, 2015

@devyn
Author

Okay, so I looked at this again today:

asm!("out %al, %dx" :: "{ax}" (byte), "{dx}" (port) :: "volatile");

seems to work just fine. The relevant LLVM documentation is for struct llvm::InlineAsm::SubConstraintInfo, field Codes where it specifies that the register name may come in braces, but doesn't really say anything more specific than that.

If Rust isn't receiving an error from LLVM about the invalid constraint, that's an LLVM bug, right? Still, I would like Rust documentation to be a little more specific about what constraints are allowed in asm! and perhaps for rustc to verify them, if LLVM won't.

thepowersgang

thepowersgang commented on Jul 2, 2015

@thepowersgang
Contributor

This issue appears to have returned with the recent LLVM update. If the data type passed to the inline assembly does not match the register size, the assembly is not emitted into assembly.

#![feature(asm)]

fn main() {
    unsafe {
        // - Errors, as expected
        //asm!("lttr %cx" : : "{ecx}" (7*8));
        // No error, no emitted instruction.
        asm!("lttr %cx" : : "{rcx}" (7*8));
    }
}
jethrogb

jethrogb commented on Jan 14, 2016

@jethrogb
Contributor

This is still a problem. Title of this bug should be: Invalid inline assembly is silently discarded.

changed the title [-]Inline assembly fails to generate OUT instruction with the required constraints[/-] [+]Invalid inline assembly is silently discarded[/+] on Jan 14, 2016
devyn

devyn commented on Jan 14, 2016

@devyn
Author

Updated.

Mark-Simulacrum

Mark-Simulacrum commented on Apr 16, 2017

@Mark-Simulacrum
Member

Minimal test case from top comment produces, so presumably this is fixed. However, output files (rust_out.0.o and rust_out.crate.metadata.o) are still produced despite the error, so I'm not sure if this should be closed quite yet. If yes, please do so.

error: couldn't allocate input reg for constraint 'a'
 --> <anon>:7:14
  |
7 |     unsafe { asm!("out %al, %dx" :: "a" (byte), "d" (port) :: "volatile"); }
  |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

Edit: This probably means #26648 is also fixed, but I'm not sure...

Mark-Simulacrum

Mark-Simulacrum commented on Apr 28, 2017

@Mark-Simulacrum
Member

If anyone can reproduce, please reopen. I haven't been able to reproduce since the original source doesn't quite compile--we should open another issue about incomplete compiles leaving files behind.

jethrogb

jethrogb commented on Apr 28, 2017

@jethrogb
Contributor

Might be good to add a regression test?

Mark-Simulacrum

Mark-Simulacrum commented on Apr 28, 2017

@Mark-Simulacrum
Member

Hmm, yeah. I'll reopen and mark as E-needstest.

19 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-inline-assemblyArea: Inline assembly (`asm!(…)`)C-bugCategory: This is a bug.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

        Participants

        @devyn@Amanieu@Centril@thepowersgang@jethrogb

        Issue actions

          Invalid inline assembly is silently discarded · Issue #22892 · rust-lang/rust