Skip to content

Invalid inline assembly is silently discarded #22892

Closed

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

  1. 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.

  2. 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?

  3. 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.

  4. 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));
        }
    }
  5. 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.

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

    @devyn
    Author

    Updated.

  8. 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...

  9. 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.

  10. jethrogb commented on Apr 28, 2017

    @jethrogb
    Contributor

    Might be good to add a regression test?

  11. Mark-Simulacrum commented on Apr 28, 2017

    @Mark-Simulacrum
    Member

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

  12. added
    E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.
    on Apr 28, 2017
  13. 3 remaining items

  14. added a commit that references this issue on Feb 26, 2019
  15. added a commit that references this issue on Feb 27, 2019
  16. added a commit that references this issue on Feb 27, 2019
  17. added a commit that references this issue on Mar 1, 2019
  18. added 2 commits that reference this issue on Mar 9, 2019
  19. varkor commented on Mar 9, 2019

    @varkor
    Contributor

    There seem to still be issues with this test case on armhf-gnu: #59046 (comment).

  20. removed
    E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.
    on Mar 9, 2019
  21. added
    requires-nightlyThis issue requires a nightly compiler in some way. When possible, use a F-* label instead.
    on Oct 25, 2019
  22. Amanieu commented on May 22, 2020

    @Amanieu
    Member

    This issue does not apply to the new asm! (RFC 2850) which validates the operand register classes.

    The legacy llvm_asm! is deprecated and is no longer maintained.

  23. added a commit that references this issue on Jul 27, 2026
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. When possible, use a F-* label instead.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions