3 ms·
This sentence from the Reference is important: > The exact assembly code syntax is target-specific and opaque to the compiler > except for the way operands
by jmillikin 2y ago
This sentence from the Reference is important:
> The exact assembly code syntax is target-specific and opaque to the compiler
> except for the way operands are substituted into the template string to form
> the code passed to the assembler.
You can verify that rustc doesn't validate the contents of asm!() by telling it to emit the raw LLVM IR:
% cat bogus.rs
#![no_std]
pub unsafe fn bogus_fn() {
core::arch::asm!(".bogus");
core::arch::asm!("bogus");
}
% rustc --crate-type=lib -C panic=abort --emit=llvm-ir -o bogus.ll bogus.rs
% cat bogus.ll
[...]
; bogus::bogus_fn
; Function Attrs: nounwind
define void @_ZN5bogus8bogus_fn17h0e38c0ae539c227fE() unnamed_addr #0 {
start:
call void asm sideeffect alignstack ".bogus", "~{cc},~{memory}"(), !srcloc !2
call void asm sideeffect alignstack "bogus", "~{cc},~{memory}"(), !srcloc !3
ret void
}
That IR is going to get passed to llvm-as and possibly onward to an external assembler, which is where the actual validation of instruction mnemonics and assembler directives happens.
---
The difference between llvm_asm!() and asm!() is in the syntax of the stuff outside of the instructions/directives -- LLVM's "~{cc},~{memory}" is what llvm_asm!() accepts more-or-less directly, and asm!() generates from backend-independent syntax.
I have an example on my blog of calling Linux syscalls via inline assembly in C, LLVM IR, and Rust. Reading it might help clarify the boundary: https://john-millikin.com/unix-syscalls#inline-assembly https://john-millikin.com/unix-syscalls#inline-assembly