From 6d912f8ec5c44c12d008171304381624da24a4f9 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 1 Sep 2021 12:04:21 +0200 Subject: [PATCH 1/8] Use custom probestack trampoline as a custom section --- lib/compiler-cranelift/src/compiler.rs | 34 +++++++++++++++++++------- lib/compiler-cranelift/src/sink.rs | 32 +++++++++++++++++++++--- 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/lib/compiler-cranelift/src/compiler.rs b/lib/compiler-cranelift/src/compiler.rs index 95374975b39..549d5f09971 100644 --- a/lib/compiler-cranelift/src/compiler.rs +++ b/lib/compiler-cranelift/src/compiler.rs @@ -25,12 +25,13 @@ use wasmer_compiler::CompileError; use wasmer_compiler::{CallingConvention, ModuleTranslationState, Target}; use wasmer_compiler::{ Compilation, CompileModuleInfo, CompiledFunction, CompiledFunctionFrameInfo, - CompiledFunctionUnwindInfo, Compiler, Dwarf, FunctionBinaryReader, FunctionBody, - FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware, ModuleMiddlewareChain, - SectionIndex, + CompiledFunctionUnwindInfo, Compiler, CustomSection, CustomSectionProtection, Dwarf, + FunctionBinaryReader, FunctionBody, FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware, + ModuleMiddlewareChain, Relocation, RelocationKind, RelocationTarget, SectionBody, SectionIndex, }; use wasmer_types::entity::{EntityRef, PrimaryMap}; use wasmer_types::{FunctionIndex, LocalFunctionIndex, SignatureIndex}; +use wasmer_vm::libcalls::LibCall; /// A compiler that compiles a WebAssembly module with Cranelift, translating the Wasm to Cranelift IR, /// optimizing it and then translating to assembly. @@ -102,6 +103,21 @@ impl Compiler for CraneliftCompiler { } }; + let mut custom_sections = PrimaryMap::new(); + + let probestack_trampoline = CustomSection { + protection: CustomSectionProtection::ReadExecute, + bytes: SectionBody::new_with_vec(vec![0xff, 0x25, 0x00, 0x00, 0x00, 0x00]), + relocations: vec![Relocation { + kind: RelocationKind::Abs8, + reloc_target: RelocationTarget::LibCall(LibCall::Probestack), + offset: 6, + addend: 0, + }], + }; + custom_sections.push(probestack_trampoline); + let probestack_trampoline_relocation_target = SectionIndex::new(custom_sections.len() - 1); + let functions = function_body_inputs .iter() .collect::)>>() @@ -138,7 +154,8 @@ impl Compiler for CraneliftCompiler { )?; let mut code_buf: Vec = Vec::new(); - let mut reloc_sink = RelocSink::new(&module, func_index); + let mut reloc_sink = + RelocSink::new(&module, func_index, probestack_trampoline_relocation_target); let mut trap_sink = TrapSink::new(); let mut stackmap_sink = binemit::NullStackMapSink {}; context @@ -204,8 +221,7 @@ impl Compiler for CraneliftCompiler { .collect::>(); #[cfg(feature = "unwind")] - let (custom_sections, dwarf) = { - let mut custom_sections = PrimaryMap::new(); + let dwarf = { let dwarf = if let Some((dwarf_frametable, _cie_id)) = dwarf_frametable { let mut eh_frame = EhFrame(WriterRelocate::new(target.triple().endianness().ok())); dwarf_frametable @@ -216,14 +232,14 @@ impl Compiler for CraneliftCompiler { let eh_frame_section = eh_frame.0.into_section(); custom_sections.push(eh_frame_section); - Some(Dwarf::new(SectionIndex::new(0))) + Some(Dwarf::new(SectionIndex::new(custom_sections.len() - 1))) } else { None }; - (custom_sections, dwarf) + dwarf }; #[cfg(not(feature = "unwind"))] - let (custom_sections, dwarf) = (PrimaryMap::new(), None); + let dwarf = None; // function call trampolines (only for local functions, by signature) let function_call_trampolines = module diff --git a/lib/compiler-cranelift/src/sink.rs b/lib/compiler-cranelift/src/sink.rs index dfc803002d0..3b53ba831a3 100644 --- a/lib/compiler-cranelift/src/sink.rs +++ b/lib/compiler-cranelift/src/sink.rs @@ -2,9 +2,11 @@ use crate::translator::{irlibcall_to_libcall, irreloc_to_relocationkind}; use cranelift_codegen::binemit; -use cranelift_codegen::ir::{self, ExternalName}; +use cranelift_codegen::ir::{self, ExternalName, LibCall}; use cranelift_entity::EntityRef as CraneliftEntityRef; -use wasmer_compiler::{JumpTable, Relocation, RelocationTarget, TrapInformation}; +use wasmer_compiler::{ + JumpTable, Relocation, RelocationKind, RelocationTarget, SectionIndex, TrapInformation, +}; use wasmer_types::entity::EntityRef; use wasmer_types::{FunctionIndex, LocalFunctionIndex, ModuleInfo}; use wasmer_vm::TrapCode; @@ -18,6 +20,9 @@ pub(crate) struct RelocSink<'a> { /// Relocations recorded for the function. pub func_relocs: Vec, + + /// The section where the probestack trampoline call is located + pub probestack_trampoline_relocation_target: SectionIndex, } impl<'a> binemit::RelocSink for RelocSink<'a> { @@ -37,7 +42,21 @@ impl<'a> binemit::RelocSink for RelocSink<'a> { .expect("The provided function should be local"), ) } else if let ExternalName::LibCall(libcall) = *name { - RelocationTarget::LibCall(irlibcall_to_libcall(libcall)) + match libcall { + LibCall::Probestack => { + self.func_relocs.push(Relocation { + kind: RelocationKind::X86CallPCRel4, + reloc_target: RelocationTarget::CustomSection( + self.probestack_trampoline_relocation_target, + ), + offset: offset, + addend: addend, + }); + // Skip the default path + return; + } + _ => RelocationTarget::LibCall(irlibcall_to_libcall(libcall)), + } } else { panic!("unrecognized external name") }; @@ -74,7 +93,11 @@ impl<'a> binemit::RelocSink for RelocSink<'a> { impl<'a> RelocSink<'a> { /// Return a new `RelocSink` instance. - pub fn new(module: &'a ModuleInfo, func_index: FunctionIndex) -> Self { + pub fn new( + module: &'a ModuleInfo, + func_index: FunctionIndex, + probestack_trampoline_relocation_target: SectionIndex, + ) -> Self { let local_func_index = module .local_func_index(func_index) .expect("The provided function should be local"); @@ -82,6 +105,7 @@ impl<'a> RelocSink<'a> { module, local_func_index, func_relocs: Vec::new(), + probestack_trampoline_relocation_target, } } } From 6c6df4a213ee27107d0aff96b9e999505d3e0668 Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Wed, 1 Sep 2021 13:34:29 +0200 Subject: [PATCH 2/8] fix(compiler) Only create probstack custom section when building on x86_64 --- lib/compiler-cranelift/src/compiler.rs | 5 +++++ lib/compiler-cranelift/src/sink.rs | 1 + 2 files changed, 6 insertions(+) diff --git a/lib/compiler-cranelift/src/compiler.rs b/lib/compiler-cranelift/src/compiler.rs index 549d5f09971..eb7881a9a24 100644 --- a/lib/compiler-cranelift/src/compiler.rs +++ b/lib/compiler-cranelift/src/compiler.rs @@ -105,6 +105,7 @@ impl Compiler for CraneliftCompiler { let mut custom_sections = PrimaryMap::new(); + #[cfg(target_arch = "x86_64")] let probestack_trampoline = CustomSection { protection: CustomSectionProtection::ReadExecute, bytes: SectionBody::new_with_vec(vec![0xff, 0x25, 0x00, 0x00, 0x00, 0x00]), @@ -115,8 +116,12 @@ impl Compiler for CraneliftCompiler { addend: 0, }], }; + #[cfg(target_arch = "x86_64")] custom_sections.push(probestack_trampoline); + #[cfg(target_arch = "x86_64")] let probestack_trampoline_relocation_target = SectionIndex::new(custom_sections.len() - 1); + #[cfg(not(target_arch = "x86_64"))] + let probestack_trampoline_relocation_target = None; let functions = function_body_inputs .iter() diff --git a/lib/compiler-cranelift/src/sink.rs b/lib/compiler-cranelift/src/sink.rs index 3b53ba831a3..60208a24abd 100644 --- a/lib/compiler-cranelift/src/sink.rs +++ b/lib/compiler-cranelift/src/sink.rs @@ -43,6 +43,7 @@ impl<'a> binemit::RelocSink for RelocSink<'a> { ) } else if let ExternalName::LibCall(libcall) = *name { match libcall { + #[cfg(target_arch = "x86_64")] LibCall::Probestack => { self.func_relocs.push(Relocation { kind: RelocationKind::X86CallPCRel4, From 42cc25b788ea8ddde5d4e0c595ba67aeb60a9629 Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Wed, 1 Sep 2021 13:49:22 +0200 Subject: [PATCH 3/8] fix(compiler) more conditional to limit probestack trampoline to x86_64 build --- lib/compiler-cranelift/src/compiler.rs | 17 ++++++++++++----- lib/compiler-cranelift/src/sink.rs | 11 +++++++++-- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/lib/compiler-cranelift/src/compiler.rs b/lib/compiler-cranelift/src/compiler.rs index eb7881a9a24..2c018489ab9 100644 --- a/lib/compiler-cranelift/src/compiler.rs +++ b/lib/compiler-cranelift/src/compiler.rs @@ -25,12 +25,18 @@ use wasmer_compiler::CompileError; use wasmer_compiler::{CallingConvention, ModuleTranslationState, Target}; use wasmer_compiler::{ Compilation, CompileModuleInfo, CompiledFunction, CompiledFunctionFrameInfo, - CompiledFunctionUnwindInfo, Compiler, CustomSection, CustomSectionProtection, Dwarf, + CompiledFunctionUnwindInfo, Compiler,Dwarf, FunctionBinaryReader, FunctionBody, FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware, - ModuleMiddlewareChain, Relocation, RelocationKind, RelocationTarget, SectionBody, SectionIndex, + ModuleMiddlewareChain, SectionIndex, +}; +#[cfg(target_arch = "x86_64")] +use wasmer_compiler::{ + CustomSection, CustomSectionProtection, + Relocation, RelocationKind, RelocationTarget, SectionBody, }; use wasmer_types::entity::{EntityRef, PrimaryMap}; use wasmer_types::{FunctionIndex, LocalFunctionIndex, SignatureIndex}; +#[cfg(target_arch = "x86_64")] use wasmer_vm::libcalls::LibCall; /// A compiler that compiles a WebAssembly module with Cranelift, translating the Wasm to Cranelift IR, @@ -120,8 +126,6 @@ impl Compiler for CraneliftCompiler { custom_sections.push(probestack_trampoline); #[cfg(target_arch = "x86_64")] let probestack_trampoline_relocation_target = SectionIndex::new(custom_sections.len() - 1); - #[cfg(not(target_arch = "x86_64"))] - let probestack_trampoline_relocation_target = None; let functions = function_body_inputs .iter() @@ -160,7 +164,10 @@ impl Compiler for CraneliftCompiler { let mut code_buf: Vec = Vec::new(); let mut reloc_sink = - RelocSink::new(&module, func_index, probestack_trampoline_relocation_target); + RelocSink::new(&module, func_index, + #[cfg(target_arch = "x86_64")] + probestack_trampoline_relocation_target + ); let mut trap_sink = TrapSink::new(); let mut stackmap_sink = binemit::NullStackMapSink {}; context diff --git a/lib/compiler-cranelift/src/sink.rs b/lib/compiler-cranelift/src/sink.rs index 60208a24abd..0b233e2795e 100644 --- a/lib/compiler-cranelift/src/sink.rs +++ b/lib/compiler-cranelift/src/sink.rs @@ -2,11 +2,15 @@ use crate::translator::{irlibcall_to_libcall, irreloc_to_relocationkind}; use cranelift_codegen::binemit; -use cranelift_codegen::ir::{self, ExternalName, LibCall}; +use cranelift_codegen::ir::{self, ExternalName}; +#[cfg(target_arch = "x86_64")] +use cranelift_codegen::ir::LibCall; use cranelift_entity::EntityRef as CraneliftEntityRef; use wasmer_compiler::{ - JumpTable, Relocation, RelocationKind, RelocationTarget, SectionIndex, TrapInformation, + JumpTable, Relocation, RelocationTarget, TrapInformation, }; +#[cfg(target_arch = "x86_64")] +use wasmer_compiler::{RelocationKind, SectionIndex}; use wasmer_types::entity::EntityRef; use wasmer_types::{FunctionIndex, LocalFunctionIndex, ModuleInfo}; use wasmer_vm::TrapCode; @@ -22,6 +26,7 @@ pub(crate) struct RelocSink<'a> { pub func_relocs: Vec, /// The section where the probestack trampoline call is located + #[cfg(target_arch = "x86_64")] pub probestack_trampoline_relocation_target: SectionIndex, } @@ -97,6 +102,7 @@ impl<'a> RelocSink<'a> { pub fn new( module: &'a ModuleInfo, func_index: FunctionIndex, + #[cfg(target_arch = "x86_64")] probestack_trampoline_relocation_target: SectionIndex, ) -> Self { let local_func_index = module @@ -106,6 +112,7 @@ impl<'a> RelocSink<'a> { module, local_func_index, func_relocs: Vec::new(), + #[cfg(target_arch = "x86_64")] probestack_trampoline_relocation_target, } } From cb61a632c8506950d7b133f434cf56dffe56a97f Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Wed, 1 Sep 2021 14:03:12 +0200 Subject: [PATCH 4/8] fix(compiler) Fix lint --- lib/compiler-cranelift/src/compiler.rs | 21 +++++++++++---------- lib/compiler-cranelift/src/sink.rs | 9 +++------ 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/lib/compiler-cranelift/src/compiler.rs b/lib/compiler-cranelift/src/compiler.rs index 2c018489ab9..dbecf1639e0 100644 --- a/lib/compiler-cranelift/src/compiler.rs +++ b/lib/compiler-cranelift/src/compiler.rs @@ -25,14 +25,14 @@ use wasmer_compiler::CompileError; use wasmer_compiler::{CallingConvention, ModuleTranslationState, Target}; use wasmer_compiler::{ Compilation, CompileModuleInfo, CompiledFunction, CompiledFunctionFrameInfo, - CompiledFunctionUnwindInfo, Compiler,Dwarf, - FunctionBinaryReader, FunctionBody, FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware, - ModuleMiddlewareChain, SectionIndex, + CompiledFunctionUnwindInfo, Compiler, Dwarf, FunctionBinaryReader, FunctionBody, + FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware, ModuleMiddlewareChain, + SectionIndex, }; #[cfg(target_arch = "x86_64")] use wasmer_compiler::{ - CustomSection, CustomSectionProtection, - Relocation, RelocationKind, RelocationTarget, SectionBody, + CustomSection, CustomSectionProtection, Relocation, RelocationKind, RelocationTarget, + SectionBody, }; use wasmer_types::entity::{EntityRef, PrimaryMap}; use wasmer_types::{FunctionIndex, LocalFunctionIndex, SignatureIndex}; @@ -163,11 +163,12 @@ impl Compiler for CraneliftCompiler { )?; let mut code_buf: Vec = Vec::new(); - let mut reloc_sink = - RelocSink::new(&module, func_index, - #[cfg(target_arch = "x86_64")] - probestack_trampoline_relocation_target - ); + let mut reloc_sink = RelocSink::new( + &module, + func_index, + #[cfg(target_arch = "x86_64")] + probestack_trampoline_relocation_target, + ); let mut trap_sink = TrapSink::new(); let mut stackmap_sink = binemit::NullStackMapSink {}; context diff --git a/lib/compiler-cranelift/src/sink.rs b/lib/compiler-cranelift/src/sink.rs index 0b233e2795e..903d38385f9 100644 --- a/lib/compiler-cranelift/src/sink.rs +++ b/lib/compiler-cranelift/src/sink.rs @@ -2,13 +2,11 @@ use crate::translator::{irlibcall_to_libcall, irreloc_to_relocationkind}; use cranelift_codegen::binemit; -use cranelift_codegen::ir::{self, ExternalName}; #[cfg(target_arch = "x86_64")] use cranelift_codegen::ir::LibCall; +use cranelift_codegen::ir::{self, ExternalName}; use cranelift_entity::EntityRef as CraneliftEntityRef; -use wasmer_compiler::{ - JumpTable, Relocation, RelocationTarget, TrapInformation, -}; +use wasmer_compiler::{JumpTable, Relocation, RelocationTarget, TrapInformation}; #[cfg(target_arch = "x86_64")] use wasmer_compiler::{RelocationKind, SectionIndex}; use wasmer_types::entity::EntityRef; @@ -102,8 +100,7 @@ impl<'a> RelocSink<'a> { pub fn new( module: &'a ModuleInfo, func_index: FunctionIndex, - #[cfg(target_arch = "x86_64")] - probestack_trampoline_relocation_target: SectionIndex, + #[cfg(target_arch = "x86_64")] probestack_trampoline_relocation_target: SectionIndex, ) -> Self { let local_func_index = module .local_func_index(func_index) From bc8dd5cd50cfabaef20c79d16992eac35f2775cf Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Wed, 1 Sep 2021 14:03:30 +0200 Subject: [PATCH 5/8] fix(compiler) Fix comment --- lib/compiler-cranelift/src/translator/func_translator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compiler-cranelift/src/translator/func_translator.rs b/lib/compiler-cranelift/src/translator/func_translator.rs index ed59bb3ac4f..8e2cb145d22 100644 --- a/lib/compiler-cranelift/src/translator/func_translator.rs +++ b/lib/compiler-cranelift/src/translator/func_translator.rs @@ -178,7 +178,7 @@ fn parse_local_decls( /// Declare `count` local variables of the same type, starting from `next_local`. /// -/// Fail of too many locals are declared in the function, or if the type is not valid for a local. +/// Fail if the type is not valid for a local. fn declare_locals( builder: &mut FunctionBuilder, count: u32, From 978dd957168ad875e963434aa2ae2c7cbb5242ae Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Wed, 1 Sep 2021 15:05:05 +0200 Subject: [PATCH 6/8] fix(compiler) Added special case for StackOverflow intrap_handler, and enabled skip_stack_gard_page tests --- lib/vm/src/trap/traphandlers.rs | 3 ++- tests/ignores.txt | 6 ------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/vm/src/trap/traphandlers.rs b/lib/vm/src/trap/traphandlers.rs index 4a4c7a0f1f3..c39b2f7ad7f 100644 --- a/lib/vm/src/trap/traphandlers.rs +++ b/lib/vm/src/trap/traphandlers.rs @@ -721,7 +721,8 @@ impl<'a> CallThreadState<'a> { } // If this fault wasn't in wasm code, then it's not our problem - if unsafe { !IS_WASM_PC(pc as _) } { + // except if it's a StackOverflow (see below) + if unsafe { !IS_WASM_PC(pc as _) } && signal_trap != Some(TrapCode::StackOverflow) { return ptr::null(); } diff --git a/tests/ignores.txt b/tests/ignores.txt index e02ce8b74c9..4cf43021c6c 100644 --- a/tests/ignores.txt +++ b/tests/ignores.txt @@ -41,12 +41,6 @@ windows+cranelift spec::memory_grow # LLVM/Universal doesn't work in macOS M1. Skip all tests llvm+universal+macos+aarch64 * -# TODO: We need to fix this. The issue is caused by libunwind overflowing -# the stack while creating the stacktrace. -# https://github.com/rust-lang/backtrace-rs/issues/356 -cranelift spec::skip_stack_guard_page -llvm spec::skip_stack_guard_page - # TODO(https://github.com/wasmerio/wasmer/issues/1727): Traps in dylib engine cranelift+dylib spec::linking cranelift+dylib spec::bulk From db7042ea14cadd5d2f1662dfc6b246e0927c5cfc Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Wed, 1 Sep 2021 16:59:22 +0200 Subject: [PATCH 7/8] fix(compiler) Added comment to trampoline x86_64 code --- lib/compiler-cranelift/src/compiler.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/compiler-cranelift/src/compiler.rs b/lib/compiler-cranelift/src/compiler.rs index dbecf1639e0..b49c11c8dd1 100644 --- a/lib/compiler-cranelift/src/compiler.rs +++ b/lib/compiler-cranelift/src/compiler.rs @@ -114,10 +114,15 @@ impl Compiler for CraneliftCompiler { #[cfg(target_arch = "x86_64")] let probestack_trampoline = CustomSection { protection: CustomSectionProtection::ReadExecute, + // We create a jump to an absolute 64bits address + // with an indrect jump immediatly followed but the absolute address + // JMP [IP+0] FF 25 00 00 00 00 + // 64bits ADDR bytes: SectionBody::new_with_vec(vec![0xff, 0x25, 0x00, 0x00, 0x00, 0x00]), relocations: vec![Relocation { kind: RelocationKind::Abs8, reloc_target: RelocationTarget::LibCall(LibCall::Probestack), + // 6 is the size of the jmp instruction. The relocated address must follow offset: 6, addend: 0, }], From bbce5097449aa85f93333d94b787f0f2dc67f6cf Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Wed, 1 Sep 2021 18:13:11 +0200 Subject: [PATCH 8/8] fix(compile) re-disable skip_stack_guard test has they still fails on macOS and windows --- tests/ignores.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/ignores.txt b/tests/ignores.txt index 4cf43021c6c..e02ce8b74c9 100644 --- a/tests/ignores.txt +++ b/tests/ignores.txt @@ -41,6 +41,12 @@ windows+cranelift spec::memory_grow # LLVM/Universal doesn't work in macOS M1. Skip all tests llvm+universal+macos+aarch64 * +# TODO: We need to fix this. The issue is caused by libunwind overflowing +# the stack while creating the stacktrace. +# https://github.com/rust-lang/backtrace-rs/issues/356 +cranelift spec::skip_stack_guard_page +llvm spec::skip_stack_guard_page + # TODO(https://github.com/wasmerio/wasmer/issues/1727): Traps in dylib engine cranelift+dylib spec::linking cranelift+dylib spec::bulk