about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorLevente Kurusa <lkurusa@acm.org>2018-09-25 20:35:19 +0200
committerLevente Kurusa <lkurusa@acm.org>2018-09-25 20:38:35 +0200
commitfec86c8352d57fd7764d0fa2c4975010c7de793e (patch)
tree76d7eb0fbda781b8ee5a5c6aca645a99d4946d7f /src
parente5c6575801028f5e089ef2e7720aa1af9d452334 (diff)
downloadrust-fec86c8352d57fd7764d0fa2c4975010c7de793e.tar.gz
rust-fec86c8352d57fd7764d0fa2c4975010c7de793e.zip
codegen_llvm: check inline assembly constraints with LLVM
LLVM provides a way of checking whether the constraints and the actual
inline assembly make sense. This commit introduces a check before
emitting code for the inline assembly. If LLVM rejects the inline
assembly (or its constraints), then the compiler emits an error E0668
("malformed inline assembly").

Signed-off-by: Levente Kurusa <lkurusa@acm.org>
Diffstat (limited to 'src')
-rw-r--r--src/librustc_codegen_llvm/asm.rs8
-rw-r--r--src/librustc_codegen_llvm/builder.rs16
-rw-r--r--src/librustc_codegen_llvm/diagnostics.rs22
-rw-r--r--src/librustc_codegen_llvm/llvm/ffi.rs3
-rw-r--r--src/librustc_codegen_llvm/mir/statement.rs5
-rw-r--r--src/rustllvm/RustWrapper.cpp5
6 files changed, 53 insertions, 6 deletions
diff --git a/src/librustc_codegen_llvm/asm.rs b/src/librustc_codegen_llvm/asm.rs
index 5d27f8eab3e..f1bb41bceba 100644
--- a/src/librustc_codegen_llvm/asm.rs
+++ b/src/librustc_codegen_llvm/asm.rs
@@ -30,7 +30,7 @@ pub fn codegen_inline_asm(
     ia: &hir::InlineAsm,
     outputs: Vec<PlaceRef<'ll, 'tcx>>,
     mut inputs: Vec<&'ll Value>
-) {
+) -> bool {
     let mut ext_constraints = vec![];
     let mut output_types = vec![];
 
@@ -97,6 +97,10 @@ pub fn codegen_inline_asm(
         ia.alignstack,
         dialect
     );
+    if r.is_none() {
+        return false;
+    }
+    let r = r.unwrap();
 
     // Again, based on how many outputs we have
     let outputs = ia.outputs.iter().zip(&outputs).filter(|&(ref o, _)| !o.is_indirect);
@@ -117,6 +121,8 @@ pub fn codegen_inline_asm(
         llvm::LLVMSetMetadata(r, kind,
             llvm::LLVMMDNodeInContext(bx.cx.llcx, &val, 1));
     }
+
+    return true;
 }
 
 pub fn codegen_global_asm<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index e3526a5a2ee..afb87e2723f 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -737,7 +737,7 @@ impl Builder<'a, 'll, 'tcx> {
     pub fn inline_asm_call(&self, asm: *const c_char, cons: *const c_char,
                          inputs: &[&'ll Value], output: &'ll Type,
                          volatile: bool, alignstack: bool,
-                         dia: AsmDialect) -> &'ll Value {
+                         dia: AsmDialect) -> Option<&'ll Value> {
         self.count_insn("inlineasm");
 
         let volatile = if volatile { llvm::True }
@@ -753,9 +753,17 @@ impl Builder<'a, 'll, 'tcx> {
         debug!("Asm Output Type: {:?}", output);
         let fty = Type::func(&argtys[..], output);
         unsafe {
-            let v = llvm::LLVMRustInlineAsm(
-                fty, asm, cons, volatile, alignstack, dia);
-            self.call(v, inputs, None)
+            // Ask LLVM to verify that the constraints are well-formed.
+            let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons);
+            debug!("Constraint verification result: {:?}", constraints_ok);
+            if constraints_ok == 1 {
+                let v = llvm::LLVMRustInlineAsm(
+                    fty, asm, cons, volatile, alignstack, dia);
+                Some(self.call(v, inputs, None))
+            } else {
+                // LLVM has detected an issue with our constaints, bail out
+                None
+            }
         }
     }
 
diff --git a/src/librustc_codegen_llvm/diagnostics.rs b/src/librustc_codegen_llvm/diagnostics.rs
index 94776f17c79..05359f62ac0 100644
--- a/src/librustc_codegen_llvm/diagnostics.rs
+++ b/src/librustc_codegen_llvm/diagnostics.rs
@@ -47,4 +47,26 @@ unsafe { simd_add(i32x2(0, 0), i32x2(1, 2)); } // ok!
 ```
 "##,
 
+E0668: r##"
+Malformed inline assembly rejected by LLVM.
+
+LLVM checks the validity of the constraints and the assembly string passed to
+it. This error implies that LLVM seems something wrong with the inline
+assembly call.
+
+In particular, it can happen if you forgot the closing bracket of a register
+constraint (see issue #51430):
+```
+#![feature(asm)]
+
+fn main() {
+    let rax: u64;
+    unsafe {
+        asm!("" :"={rax"(rax));
+        println!("Accumulator is: {}", rax);
+    }
+}
+```
+"##,
+
 }
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index a5f4137c62b..7975e7ad670 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -1208,6 +1208,9 @@ extern "C" {
                              AlignStack: Bool,
                              Dialect: AsmDialect)
                              -> &Value;
+    pub fn LLVMRustInlineAsmVerify(Ty: &Type,
+                             Constraints: *const c_char)
+                             -> Bool;
 
     pub fn LLVMRustDebugMetadataVersion() -> u32;
     pub fn LLVMRustVersionMajor() -> u32;
diff --git a/src/librustc_codegen_llvm/mir/statement.rs b/src/librustc_codegen_llvm/mir/statement.rs
index b4eb7615f98..eb7eb1dbd46 100644
--- a/src/librustc_codegen_llvm/mir/statement.rs
+++ b/src/librustc_codegen_llvm/mir/statement.rs
@@ -86,7 +86,10 @@ impl FunctionCx<'a, 'll, 'tcx> {
                     self.codegen_operand(&bx, input).immediate()
                 }).collect();
 
-                asm::codegen_inline_asm(&bx, asm, outputs, input_vals);
+                let res = asm::codegen_inline_asm(&bx, asm, outputs, input_vals);
+                if !res {
+                    span_err!(bx.sess(), statement.source_info.span, E0668, "malformed inline assembly");
+                }
                 bx
             }
             mir::StatementKind::FakeRead(..) |
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index 9b9c908ea52..f1ab1d4ddfa 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -426,6 +426,11 @@ extern "C" LLVMValueRef LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString,
                              HasSideEffects, IsAlignStack, fromRust(Dialect)));
 }
 
+extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty,
+                                          char *Constraints) {
+  return InlineAsm::Verify(unwrap<FunctionType>(Ty), Constraints);
+}
+
 extern "C" void LLVMRustAppendModuleInlineAsm(LLVMModuleRef M, const char *Asm) {
   unwrap(M)->appendModuleInlineAsm(StringRef(Asm));
 }