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: NLevente Kurusa <lkurusa@acm.org>
上级 e5c65758
......@@ -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>,
......
......@@ -737,7 +737,7 @@ pub fn phi(&self, ty: &'ll Type, vals: &[&'ll Value], bbs: &[&'ll BasicBlock]) -
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 @@ pub fn inline_asm_call(&self, asm: *const c_char, cons: *const c_char,
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
}
}
}
......
......@@ -47,4 +47,26 @@ fn main() {
```
"##,
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);
}
}
```
"##,
}
......@@ -1208,6 +1208,9 @@ pub fn LLVMRustInlineAsm(Ty: &Type,
AlignStack: Bool,
Dialect: AsmDialect)
-> &Value;
pub fn LLVMRustInlineAsmVerify(Ty: &Type,
Constraints: *const c_char)
-> Bool;
pub fn LLVMRustDebugMetadataVersion() -> u32;
pub fn LLVMRustVersionMajor() -> u32;
......
......@@ -86,7 +86,10 @@ pub fn codegen_statement(&mut self,
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(..) |
......
......@@ -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));
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册