Issue 162043
Summary Inline assembly syntax rejected only in a `module asm` block by LLVM on a Windows host while being accepted on a Linux host
Labels new issue
Assignees
Reporter Fulgen301
    This is rust-lang/rust#147267

Rust lowers naked functions to a `module asm` block - the following Rust code

```rs
#[unsafe(no_mangle)]
extern "C" fn foo() {
    unsafe {
 core::arch::asm!("mov rax, QWORD PTR gs:[60h]");
 }
}

#[unsafe(naked)]
#[unsafe(no_mangle)]
extern "C" fn foo2() {
 core::arch::naked_asm!("mov rax, QWORD PTR gs:[60h]")
}
```

ends up as 

<details><summary>LLVM IR</summary>
<p>

```
; ModuleID = 'test.881695139e95559a-cgu.0'
source_filename = "test.881695139e95559a-cgu.0"
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"

module asm ".intel_syntax"
module asm ".pushsection .text.foo2,\22xr\22"
module asm ".balign 4"
module asm ".globl foo2"
module asm ".def foo2"
module asm ".scl 2"
module asm ".type 32"
module asm ".endef"
module asm "foo2:"
module asm "mov rax, QWORD PTR gs:[60h]"
module asm ".popsection"
module asm ""
module asm ".att_syntax"

@vtable.0 = private unnamed_addr constant <{ [24 x i8], ptr, ptr, ptr }> <{ [24 x i8] c"\00\00\00\00\00\00\00\00\08\00\00\00\00\00\00\00\08\00\00\00\00\00\00\00", ptr @"_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17hd1c75b492168a55dE", ptr @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h4262cf38e2e29668E", ptr @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h4262cf38e2e29668E" }>, align 8

; std::rt::lang_start
; Function Attrs: uwtable
define hidden i64 @_ZN3std2rt10lang_start17h433cd31365191fd0E(ptr %main, i64 %argc, ptr %argv, i8 %sigpipe) unnamed_addr #0 {
start:
  %_7 = alloca [8 x i8], align 8
  store ptr %main, ptr %_7, align 8
; call std::rt::lang_start_internal
  %_0 = call i64 @_ZN3std2rt19lang_start_internal17h4a182455c3ab4a29E(ptr align 1 %_7, ptr align 8 @vtable.0, i64 %argc, ptr %argv, i8 %sigpipe)
  ret i64 %_0
}

; std::rt::lang_start::{{closure}}
; Function Attrs: inlinehint uwtable
define internal i32 @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h4262cf38e2e29668E"(ptr align 8 %_1) unnamed_addr #1 {
start:
  %_4 = load ptr, ptr %_1, align 8
; call std::sys::backtrace::__rust_begin_short_backtrace
  call void @_ZN3std3sys9backtrace28__rust_begin_short_backtrace17hc9806c74f494fc26E(ptr %_4)
; call <() as std::process::Termination>::report
  %self = call i32 @"_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h264280877e7cdf26E"()
 ret i32 %self
}

; std::sys::backtrace::__rust_begin_short_backtrace
; Function Attrs: noinline uwtable
define internal void @_ZN3std3sys9backtrace28__rust_begin_short_backtrace17hc9806c74f494fc26E(ptr %f) unnamed_addr #2 {
start:
; call core::ops::function::FnOnce::call_once
  call void @_ZN4core3ops8function6FnOnce9call_once17h2ca7e55b5cd60158E(ptr %f)
  call void asm sideeffect "", "~{memory}"(), !srcloc !3
  ret void
}

; core::ops::function::FnOnce::call_once{{vtable.shim}}
; Function Attrs: inlinehint uwtable
define internal i32 @"_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17hd1c75b492168a55dE"(ptr %_1) unnamed_addr #1 {
start:
  %_2 = alloca [0 x i8], align 1
  %0 = load ptr, ptr %_1, align 8
; call core::ops::function::FnOnce::call_once
  %_0 = call i32 @_ZN4core3ops8function6FnOnce9call_once17h3de95b96d12b004dE(ptr %0)
  ret i32 %_0
}

; core::ops::function::FnOnce::call_once
; Function Attrs: inlinehint uwtable
define internal void @_ZN4core3ops8function6FnOnce9call_once17h2ca7e55b5cd60158E(ptr %_1) unnamed_addr #1 {
start:
  %_2 = alloca [0 x i8], align 1
  call void %_1()
  ret void
}

; core::ops::function::FnOnce::call_once
; Function Attrs: inlinehint uwtable
define internal i32 @_ZN4core3ops8function6FnOnce9call_once17h3de95b96d12b004dE(ptr %0) unnamed_addr #1 personality ptr @__CxxFrameHandler3 {
start:
  %_2 = alloca [0 x i8], align 1
  %_1 = alloca [8 x i8], align 8
  store ptr %0, ptr %_1, align 8
; invoke std::rt::lang_start::{{closure}}
  %_0 = invoke i32 @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h4262cf38e2e29668E"(ptr align 8 %_1)
          to label %bb1 unwind label %funclet_bb3

bb3: ; preds = %funclet_bb3
  cleanupret from %cleanuppad unwind to caller

funclet_bb3: ; preds = %start
  %cleanuppad = cleanuppad within none []
  br label %bb3

bb1:                                              ; preds = %start
  ret i32 %_0
}

; <() as std::process::Termination>::report
; Function Attrs: inlinehint uwtable
define internal i32 @"_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h264280877e7cdf26E"() unnamed_addr #1 {
start:
  ret i32 0
}

; Function Attrs: nounwind uwtable
define dso_local void @foo() unnamed_addr #3 {
start:
  call void asm sideeffect alignstack inteldialect "mov rax, QWORD PTR gs:[60h]", "~{dirflag},~{fpsr},~{flags},~{memory}"(), !srcloc !4
  ret void
}

; test::main
; Function Attrs: uwtable
define hidden void @_ZN4test4main17h31abd93402dadb48E() unnamed_addr #0 {
start:
  ret void
}

; std::rt::lang_start_internal
; Function Attrs: uwtable
declare i64 @_ZN3std2rt19lang_start_internal17h4a182455c3ab4a29E(ptr align 1, ptr align 8, i64, ptr, i8) unnamed_addr #0

declare i32 @__CxxFrameHandler3(...) unnamed_addr #4

; Function Attrs: noinline nounwind uwtable
declare void @foo2() unnamed_addr #5

define i32 @main(i32 %0, ptr %1) unnamed_addr #4 {
top:
  %2 = sext i32 %0 to i64
; call std::rt::lang_start
  %3 = call i64 @_ZN3std2rt10lang_start17h433cd31365191fd0E(ptr @_ZN4test4main17h31abd93402dadb48E, i64 %2, ptr %1, i8 0)
  %4 = trunc i64 %3 to i32
  ret i32 %4
}

attributes #0 = { uwtable "target-cpu"="x86-64" "target-features"="+cx16,+sse3,+sahf" }
attributes #1 = { inlinehint uwtable "target-cpu"="x86-64" "target-features"="+cx16,+sse3,+sahf" }
attributes #2 = { noinline uwtable "target-cpu"="x86-64" "target-features"="+cx16,+sse3,+sahf" }
attributes #3 = { nounwind uwtable "target-cpu"="x86-64" "target-features"="+cx16,+sse3,+sahf" }
attributes #4 = { "target-cpu"="x86-64" }
attributes #5 = { noinline nounwind uwtable "target-cpu"="x86-64" "target-features"="+cx16,+sse3,+sahf" }

!llvm.module.flags = !{!0, !1}
!llvm.ident = !{!2}

!0 = !{i32 8, !"PIC Level", i32 2}
!1 = !{i32 7, !"PIE Level", i32 2}
!2 = !{!"rustc version 1.90.0 (1159e78c4 2025-09-14)"}
!3 = !{i64 2898316946459614}
!4 = !{i64 433791696970
```

</p>
</details> 

However, LLVM with x86_64-pc-windows-msvc as _host_ tools does not accept `mov rax, QWORD PTR gs:[60h]` in module asm:

```
PS> rustc test.rs
error: unknown token in _expression_
   |
note: instantiated into assembly here
  --> <inline asm>:10:27
   |
10 | mov rax, QWORD PTR gs:[60h]
   | ^

error: aborting due to 1 previous error

PS> rustc --emit=llvm-ir test.rs && clang test.ll
warning: overriding the module target triple with x86_64-pc-windows-msvc19.44.35217 [-Woverride-module]
<inline asm>:10:27: error: unknown token in _expression_
mov rax, QWORD PTR gs:[60h]
 ^
error: cannot compile inline asm
1 warning and 1 error generated
```

The error goes away if I pass `-masm=intel` to Clang, or use `[0x96]` instead of `[60h]`. The error also does not appear if the code is compiled with Linux host tools, such as on godbolt. It is also accepted by regular inline assembly (`call void asm`).


Reduced:

```
source_filename = "short.ll"
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"


module asm ".intel_syntax"
module asm ".pushsection .text"
module asm "foo2:"
module asm "mov rax, QWORD PTR gs:[60h]"
module asm ".popsection"
module asm ""
module asm ".att_syntax"
```


_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to