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>
This commit is contained in:
parent
e5c6575801
commit
fec86c8352
@ -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 {
|
||||
// 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);
|
||||
self.call(v, inputs, None)
|
||||
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));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user