From 187b7508c951f9d854c4ea3d85a165f20def6425 Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Wed, 2 Mar 2022 12:21:55 +0100 Subject: [PATCH 01/14] Added some infrastructure to generate EH_Frame in singlepass compiler --- Cargo.lock | 1 + lib/compiler-singlepass/Cargo.toml | 4 +- lib/compiler-singlepass/src/codegen.rs | 31 ++++--- lib/compiler-singlepass/src/compiler.rs | 69 ++++++++++++-- lib/compiler-singlepass/src/dwarf.rs | 102 +++++++++++++++++++++ lib/compiler-singlepass/src/lib.rs | 3 + lib/compiler-singlepass/src/machine_x64.rs | 13 +++ lib/compiler-singlepass/src/unwind.rs | 32 +++++++ lib/compiler-singlepass/src/x64_decl.rs | 54 ++++++++++- tests/ignores.txt | 12 +-- 10 files changed, 290 insertions(+), 31 deletions(-) create mode 100644 lib/compiler-singlepass/src/dwarf.rs create mode 100644 lib/compiler-singlepass/src/unwind.rs diff --git a/Cargo.lock b/Cargo.lock index a50d6c84d02..9c835cd4843 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2989,6 +2989,7 @@ dependencies = [ "byteorder", "dynasm", "dynasmrt", + "gimli 0.25.0", "hashbrown 0.11.2", "lazy_static", "loupe", diff --git a/lib/compiler-singlepass/Cargo.toml b/lib/compiler-singlepass/Cargo.toml index db689b77932..42662d94f9d 100644 --- a/lib/compiler-singlepass/Cargo.toml +++ b/lib/compiler-singlepass/Cargo.toml @@ -17,6 +17,7 @@ wasmer-vm = { path = "../vm", version = "=2.2.0" } wasmer-types = { path = "../types", version = "=2.2.0", default-features = false, features = ["std"] } rayon = { version = "1.5", optional = true } hashbrown = { version = "0.11", optional = true } +gimli = { version = "0.25", optional = true } more-asserts = "0.2" dynasm = "1.2.1" dynasmrt = "1.2.1" @@ -32,8 +33,9 @@ target-lexicon = { version = "0.12.2", default-features = false } maintenance = { status = "actively-developed" } [features] -default = ["std", "rayon", "avx"] +default = ["std", "rayon", "unwind", "avx"] std = ["wasmer-compiler/std", "wasmer-types/std"] core = ["hashbrown", "wasmer-types/core"] +unwind = ["gimli"] sse = [] avx = [] diff --git a/lib/compiler-singlepass/src/codegen.rs b/lib/compiler-singlepass/src/codegen.rs index 2e68a8fc0d9..bfd3edc782f 100644 --- a/lib/compiler-singlepass/src/codegen.rs +++ b/lib/compiler-singlepass/src/codegen.rs @@ -2,6 +2,7 @@ use crate::address_map::get_function_address_map; use crate::location::{Location, Reg}; use crate::machine::{CodegenError, Label, Machine, MachineStackOffset, NATIVE_PAGE_SIZE}; use crate::{common_decl::*, config::Singlepass}; +use gimli::write::FrameDescriptionEntry; use smallvec::{smallvec, SmallVec}; use std::cmp; use std::iter; @@ -5850,7 +5851,10 @@ impl<'a, M: Machine> FuncGen<'a, M> { Ok(()) } - pub fn finalize(mut self, data: &FunctionBodyData) -> CompiledFunction { + pub fn finalize( + mut self, + data: &FunctionBodyData, + ) -> (CompiledFunction, Option) { // Generate actual code for special labels. self.machine .emit_label(self.special_labels.integer_division_by_zero); @@ -5895,18 +5899,21 @@ impl<'a, M: Machine> FuncGen<'a, M> { let traps = self.machine.collect_trap_information(); let body = self.machine.assembler_finalize(); - CompiledFunction { - body: FunctionBody { - body: body, - unwind_info: None, - }, - relocations: self.relocations.clone(), - jt_offsets: SecondaryMap::new(), - frame_info: CompiledFunctionFrameInfo { - traps: traps, - address_map, + ( + CompiledFunction { + body: FunctionBody { + body: body, + unwind_info: None, + }, + relocations: self.relocations.clone(), + jt_offsets: SecondaryMap::new(), + frame_info: CompiledFunctionFrameInfo { + traps: traps, + address_map, + }, }, - } + None, + ) } // FIXME: This implementation seems to be not enough to resolve all kinds of register dependencies // at call place. diff --git a/lib/compiler-singlepass/src/compiler.rs b/lib/compiler-singlepass/src/compiler.rs index 0c04789b561..03dcc996fa4 100644 --- a/lib/compiler-singlepass/src/compiler.rs +++ b/lib/compiler-singlepass/src/compiler.rs @@ -4,21 +4,28 @@ use crate::codegen::FuncGen; use crate::config::Singlepass; +#[cfg(feature = "unwind")] +use crate::dwarf::WriterRelocate; use crate::machine::Machine; use crate::machine::{ gen_import_call_trampoline, gen_std_dynamic_import_trampoline, gen_std_trampoline, CodegenError, }; use crate::machine_arm64::MachineARM64; use crate::machine_x64::MachineX86_64; +#[cfg(feature = "unwind")] +use crate::unwind::create_systemv_cie; +#[cfg(feature = "unwind")] +use gimli::write::{EhFrame, FrameTable}; use loupe::MemoryUsage; #[cfg(feature = "rayon")] use rayon::prelude::{IntoParallelIterator, ParallelIterator}; use std::sync::Arc; use wasmer_compiler::{ Architecture, CallingConvention, Compilation, CompileError, CompileModuleInfo, - CompiledFunction, Compiler, CompilerConfig, CpuFeature, FunctionBinaryReader, FunctionBody, - FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware, ModuleMiddlewareChain, - ModuleTranslationState, OperatingSystem, SectionIndex, Target, TrapInformation, + CompiledFunction, Compiler, CompilerConfig, CpuFeature, Dwarf, FunctionBinaryReader, + FunctionBody, FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware, + ModuleMiddlewareChain, ModuleTranslationState, OperatingSystem, SectionIndex, Target, + TrapInformation, }; use wasmer_types::entity::{EntityRef, PrimaryMap}; use wasmer_types::{ @@ -94,11 +101,34 @@ impl Compiler for SinglepassCompiler { _ => panic!("Unsupported Calling convention for Singlepass compiler"), }; + // Generate the frametable + #[cfg(feature = "unwind")] + let dwarf_frametable = if function_body_inputs.is_empty() { + // If we have no function body inputs, we don't need to + // construct the `FrameTable`. Constructing it, with empty + // FDEs will cause some issues in Linux. + None + } else { + match target.triple().default_calling_convention() { + Ok(CallingConvention::SystemV) => { + match create_systemv_cie(target.triple().architecture) { + Some(cie) => { + let mut dwarf_frametable = FrameTable::default(); + let cie_id = dwarf_frametable.add_cie(cie); + Some((dwarf_frametable, cie_id)) + } + None => None, + } + } + _ => None, + } + }; + let memory_styles = &compile_info.memory_styles; let table_styles = &compile_info.table_styles; let vmoffsets = VMOffsets::new(8, &compile_info.module); let module = &compile_info.module; - let import_trampolines: PrimaryMap = (0..module.num_imported_functions) + let mut custom_sections: PrimaryMap = (0..module.num_imported_functions) .map(FunctionIndex::new) .collect::>() .into_par_iter_if_rayon() @@ -114,7 +144,7 @@ impl Compiler for SinglepassCompiler { .collect::>() .into_iter() .collect(); - let functions = function_body_inputs + let (functions, fdes): (Vec, Vec<_>) = function_body_inputs .iter() .collect::)>>() .into_par_iter_if_rayon() @@ -185,9 +215,9 @@ impl Compiler for SinglepassCompiler { _ => unimplemented!(), } }) - .collect::, CompileError>>()? + .collect::, CompileError>>()? .into_iter() - .collect::>(); + .unzip(); let function_call_trampolines = module .signatures @@ -215,12 +245,31 @@ impl Compiler for SinglepassCompiler { .into_iter() .collect::>(); + #[cfg(feature = "unwind")] + let dwarf = if let Some((mut dwarf_frametable, cie_id)) = dwarf_frametable { + for fde in fdes { + if let Some(fde) = fde { + dwarf_frametable.add_fde(cie_id, fde); + } + } + let mut eh_frame = EhFrame(WriterRelocate::new(target.triple().endianness().ok())); + dwarf_frametable.write_eh_frame(&mut eh_frame).unwrap(); + + let eh_frame_section = eh_frame.0.into_section(); + custom_sections.push(eh_frame_section); + Some(Dwarf::new(SectionIndex::new(custom_sections.len() - 1))) + } else { + None + }; + #[cfg(not(feature = "unwind"))] + let dwarf = None; + Ok(Compilation::new( - functions, - import_trampolines, + functions.into_iter().collect(), + custom_sections, function_call_trampolines, dynamic_function_trampolines, - None, + dwarf, )) } } diff --git a/lib/compiler-singlepass/src/dwarf.rs b/lib/compiler-singlepass/src/dwarf.rs new file mode 100644 index 00000000000..8a472f310c0 --- /dev/null +++ b/lib/compiler-singlepass/src/dwarf.rs @@ -0,0 +1,102 @@ +use gimli::write::{Address, EndianVec, Result, Writer}; +use gimli::{RunTimeEndian, SectionId}; +use wasmer_compiler::{CustomSection, CustomSectionProtection, SectionBody}; +use wasmer_compiler::{Endianness, Relocation, RelocationKind, RelocationTarget}; +use wasmer_types::entity::EntityRef; +use wasmer_types::LocalFunctionIndex; + +#[derive(Clone, Debug)] +pub struct WriterRelocate { + pub relocs: Vec, + writer: EndianVec, +} + +impl WriterRelocate { + pub const FUNCTION_SYMBOL: usize = 0; + pub fn new(endianness: Option) -> Self { + let endianness = match endianness { + Some(Endianness::Little) => RunTimeEndian::Little, + Some(Endianness::Big) => RunTimeEndian::Big, + // We autodetect it, based on the host + None => RunTimeEndian::default(), + }; + WriterRelocate { + relocs: Vec::new(), + writer: EndianVec::new(endianness), + } + } + + pub fn into_section(mut self) -> CustomSection { + // GCC expects a terminating "empty" length, so write a 0 length at the end of the table. + self.writer.write_u32(0).unwrap(); + let data = self.writer.into_vec(); + CustomSection { + protection: CustomSectionProtection::Read, + bytes: SectionBody::new_with_vec(data), + relocations: self.relocs, + } + } +} + +impl Writer for WriterRelocate { + type Endian = RunTimeEndian; + + fn endian(&self) -> Self::Endian { + self.writer.endian() + } + + fn len(&self) -> usize { + self.writer.len() + } + + fn write(&mut self, bytes: &[u8]) -> Result<()> { + self.writer.write(bytes) + } + + fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> { + self.writer.write_at(offset, bytes) + } + + fn write_address(&mut self, address: Address, size: u8) -> Result<()> { + match address { + Address::Constant(val) => self.write_udata(val, size), + Address::Symbol { symbol, addend } => { + // Is a function relocation + if symbol == Self::FUNCTION_SYMBOL { + // We use the addend to detect the function index + let function_index = LocalFunctionIndex::new(addend as _); + let reloc_target = RelocationTarget::LocalFunc(function_index); + let offset = self.len() as u32; + let kind = match size { + 8 => RelocationKind::Abs8, + _ => unimplemented!("dwarf relocation size not yet supported: {}", size), + }; + let addend = 0; + self.relocs.push(Relocation { + kind, + reloc_target, + offset, + addend, + }); + self.write_udata(addend as u64, size) + } else { + unreachable!("Symbol {} in DWARF not recognized", symbol); + } + } + } + } + + fn write_offset(&mut self, _val: usize, _section: SectionId, _size: u8) -> Result<()> { + unimplemented!("write_offset not yet implemented"); + } + + fn write_offset_at( + &mut self, + _offset: usize, + _val: usize, + _section: SectionId, + _size: u8, + ) -> Result<()> { + unimplemented!("write_offset_at not yet implemented"); + } +} diff --git a/lib/compiler-singlepass/src/lib.rs b/lib/compiler-singlepass/src/lib.rs index 48329748abf..ef2ca8d0599 100644 --- a/lib/compiler-singlepass/src/lib.rs +++ b/lib/compiler-singlepass/src/lib.rs @@ -14,12 +14,15 @@ mod codegen; mod common_decl; mod compiler; mod config; +#[cfg(feature = "unwind")] +mod dwarf; mod emitter_arm64; mod emitter_x64; mod location; mod machine; mod machine_arm64; mod machine_x64; +mod unwind; mod x64_decl; pub use crate::compiler::SinglepassCompiler; diff --git a/lib/compiler-singlepass/src/machine_x64.rs b/lib/compiler-singlepass/src/machine_x64.rs index a463a010f32..1f31f175011 100644 --- a/lib/compiler-singlepass/src/machine_x64.rs +++ b/lib/compiler-singlepass/src/machine_x64.rs @@ -3,6 +3,7 @@ use crate::emitter_x64::*; use crate::location::Location as AbstractLocation; use crate::location::Reg; use crate::machine::*; +use crate::unwind::UnwindOps; use crate::x64_decl::new_machine_state; use crate::x64_decl::{ArgumentRegisterAllocator, X64Register, GPR, XMM}; use dynasmrt::{x64::X64Relocation, DynasmError, VecAssembler}; @@ -66,6 +67,8 @@ pub struct MachineX86_64 { instructions_address_map: Vec, /// The source location for the current operator. src_loc: u32, + /// Vector of unwind operations with offset + unwind_ops: Vec<(usize, UnwindOps)>, } impl MachineX86_64 { @@ -77,6 +80,7 @@ impl MachineX86_64 { trap_table: TrapTable::default(), instructions_address_map: vec![], src_loc: 0, + unwind_ops: vec![], } } pub fn emit_relaxed_binop( @@ -2180,7 +2184,16 @@ impl Machine for MachineX86_64 { fn emit_function_prolog(&mut self) { self.emit_push(Size::S64, Location::GPR(GPR::RBP)); + self.unwind_ops + .push((self.get_offset().0, UnwindOps::PushFP { up_to_sp: 16 })); self.move_location(Size::S64, Location::GPR(GPR::RSP), Location::GPR(GPR::RBP)); + self.unwind_ops.push(( + self.get_offset().0, + UnwindOps::DefineNewFrame { + up_to_sp: 0, + down_to_clobber: 0, + }, + )); } fn emit_function_epilog(&mut self) { diff --git a/lib/compiler-singlepass/src/unwind.rs b/lib/compiler-singlepass/src/unwind.rs new file mode 100644 index 00000000000..dae1ce8ec34 --- /dev/null +++ b/lib/compiler-singlepass/src/unwind.rs @@ -0,0 +1,32 @@ +use gimli::{write::CallFrameInstruction, write::CommonInformationEntry, Encoding, Format, X86_64}; +use std::fmt::Debug; +use wasmer_compiler::Architecture; + +#[derive(Clone, Debug)] +pub enum UnwindOps { + PushFP { up_to_sp: u32 }, + DefineNewFrame { up_to_sp: u32, down_to_clobber: u32 }, +} + +/// generate a default systemv cie +pub fn create_systemv_cie(arch: Architecture) -> Option { + match arch { + Architecture::X86_64 => { + let mut entry = CommonInformationEntry::new( + Encoding { + address_size: 8, + format: Format::Dwarf32, + version: 1, + }, + 1, + -8, + X86_64::RA, + ); + entry.add_instruction(CallFrameInstruction::Cfa(X86_64::RSP, 8)); + entry.add_instruction(CallFrameInstruction::Offset(X86_64::RA, -8)); + Some(entry) + } + Architecture::Aarch64(_) => None, + _ => None, + } +} diff --git a/lib/compiler-singlepass/src/x64_decl.rs b/lib/compiler-singlepass/src/x64_decl.rs index b9626f947bd..e6756e7b742 100644 --- a/lib/compiler-singlepass/src/x64_decl.rs +++ b/lib/compiler-singlepass/src/x64_decl.rs @@ -164,11 +164,61 @@ impl CombinedRegister for X64Register { fn from_simd(x: u16) -> Self { X64Register::XMM(XMM::from_index(x as usize).unwrap()) } - + /* x86_64-abi-0.99.pdf + * Register Name | Number | Abbreviation + * General Purpose Register RAX | 0 | %rax + * General Purpose Register RDX | 1 | %rdx + * General Purpose Register RCX | 2 | %rcx + * General Purpose Register RBX | 3 | %rbx + * General Purpose Register RSI | 4 | %rsi + * General Purpose Register RDI | 5 | %rdi + * Frame Pointer Register RBP | 6 | %rbp + * Stack Pointer Register RSP | 7 | %rsp + * Extended Integer Registers 8-15 | 8-15 | %r8-%r15 + * Return Address RA | 16 | + * Vector Registers 0-7 | 17-24 | %xmm0-%xmm7 + * Extended Vector Registers 8-15 | 25-32 | %xmm8-%xmm15 + * Floating Point Registers 0-7 | 33-40 | %st0-%st7 + * MMX Registers 0-7 | 41-48 | %mm0-%mm7 + * Flag Register | 49 | %rFLAGS + * Segment Register ES | 50 | %es + * Segment Register CS | 51 | %cs + * Segment Register SS | 52 | %ss + * Segment Register DS | 53 | %ds + * Segment Register FS | 54 | %fs + * Segment Register GS | 55 | %gs + * Reserved | 56-57 | + * FS Base address | 58 | %fs.base + * GS Base address | 59 | %gs.base + * Reserved | 60-61 | + * Task Register | 62 | %tr + * LDT Register | 63 | %ldtr + * 128-bit Media Control and Status | 64 | %mxcsr + * x87 Control Word | 65 | %fcw + * x87 Status Word | 66 | %fsw + */ /// Converts a DWARF regnum to X64Register. fn _from_dwarf_regnum(x: u16) -> Option { + static DWARF_REGS: [GPR; 16] = [ + GPR::RAX, + GPR::RDX, + GPR::RCX, + GPR::RBX, + GPR::RSI, + GPR::RDI, + GPR::RBP, + GPR::RSP, + GPR::R8, + GPR::R9, + GPR::R10, + GPR::R11, + GPR::R12, + GPR::R13, + GPR::R14, + GPR::R15, + ]; Some(match x { - 0..=15 => X64Register::GPR(GPR::from_index(x as usize).unwrap()), + 0..=15 => X64Register::GPR(DWARF_REGS[x as usize]), 17..=24 => X64Register::XMM(XMM::from_index(x as usize - 17).unwrap()), _ => return None, }) diff --git a/tests/ignores.txt b/tests/ignores.txt index a2efd9dbb3a..88eec35ada6 100644 --- a/tests/ignores.txt +++ b/tests/ignores.txt @@ -10,25 +10,25 @@ musl+dylib * # Dynamic loading not supported in Musl ## Traps. Tracing doesn't work properly in Singlepass ## Unwinding is not properly implemented in Singlepass # Needs investigation -singlepass traps::test_trap_trace +#singlepass traps::test_trap_trace dylib traps::test_trap_trace aarch64 traps::test_trap_trace -singlepass traps::test_trap_stack_overflow # Need to investigate +#singlepass traps::test_trap_stack_overflow # Need to investigate dylib traps::test_trap_stack_overflow # Need to investigate aarch64 traps::test_trap_stack_overflow # Need to investigate -singlepass traps::trap_display_pretty +#singlepass traps::trap_display_pretty llvm traps::trap_display_pretty dylib traps::trap_display_pretty aarch64 traps::trap_display_pretty -singlepass traps::trap_display_multi_module +#singlepass traps::trap_display_multi_module llvm traps::trap_display_multi_module dylib traps::trap_display_multi_module aarch64 traps::trap_display_multi_module -singlepass traps::call_signature_mismatch +#singlepass traps::call_signature_mismatch llvm traps::call_signature_mismatch dylib traps::call_signature_mismatch macos+aarch64 traps::call_signature_mismatch -singlepass traps::start_trap_pretty +#singlepass traps::start_trap_pretty llvm traps::start_trap_pretty dylib traps::start_trap_pretty aarch64 traps::start_trap_pretty From 205611b58fdd52e4ad1c6df3ccf82ed6e0131e4b Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Wed, 2 Mar 2022 13:09:04 +0100 Subject: [PATCH 02/14] Put back the ignored test about trap/singlepass for now --- tests/ignores.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/ignores.txt b/tests/ignores.txt index 88eec35ada6..a2efd9dbb3a 100644 --- a/tests/ignores.txt +++ b/tests/ignores.txt @@ -10,25 +10,25 @@ musl+dylib * # Dynamic loading not supported in Musl ## Traps. Tracing doesn't work properly in Singlepass ## Unwinding is not properly implemented in Singlepass # Needs investigation -#singlepass traps::test_trap_trace +singlepass traps::test_trap_trace dylib traps::test_trap_trace aarch64 traps::test_trap_trace -#singlepass traps::test_trap_stack_overflow # Need to investigate +singlepass traps::test_trap_stack_overflow # Need to investigate dylib traps::test_trap_stack_overflow # Need to investigate aarch64 traps::test_trap_stack_overflow # Need to investigate -#singlepass traps::trap_display_pretty +singlepass traps::trap_display_pretty llvm traps::trap_display_pretty dylib traps::trap_display_pretty aarch64 traps::trap_display_pretty -#singlepass traps::trap_display_multi_module +singlepass traps::trap_display_multi_module llvm traps::trap_display_multi_module dylib traps::trap_display_multi_module aarch64 traps::trap_display_multi_module -#singlepass traps::call_signature_mismatch +singlepass traps::call_signature_mismatch llvm traps::call_signature_mismatch dylib traps::call_signature_mismatch macos+aarch64 traps::call_signature_mismatch -#singlepass traps::start_trap_pretty +singlepass traps::start_trap_pretty llvm traps::start_trap_pretty dylib traps::start_trap_pretty aarch64 traps::start_trap_pretty From 064657849d268b26f153d7bb13c7fab1ff23d065 Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Wed, 2 Mar 2022 14:02:19 +0100 Subject: [PATCH 03/14] Try to fix no-unwind build --- lib/compiler-singlepass/src/codegen.rs | 4 ++++ lib/compiler-singlepass/src/unwind.rs | 2 ++ 2 files changed, 6 insertions(+) diff --git a/lib/compiler-singlepass/src/codegen.rs b/lib/compiler-singlepass/src/codegen.rs index bfd3edc782f..5887bec9a5a 100644 --- a/lib/compiler-singlepass/src/codegen.rs +++ b/lib/compiler-singlepass/src/codegen.rs @@ -2,6 +2,7 @@ use crate::address_map::get_function_address_map; use crate::location::{Location, Reg}; use crate::machine::{CodegenError, Label, Machine, MachineStackOffset, NATIVE_PAGE_SIZE}; use crate::{common_decl::*, config::Singlepass}; +#[cfg(feature = "unwind")] use gimli::write::FrameDescriptionEntry; use smallvec::{smallvec, SmallVec}; use std::cmp; @@ -21,6 +22,9 @@ use wasmer_types::{ }; use wasmer_vm::{MemoryStyle, TableStyle, TrapCode, VMBuiltinFunctionIndex, VMOffsets}; +#[cfg(not(feature = "unwind"))] +pub type FrameDescriptionEntry = u32; + /// The singlepass per-function code generator. pub struct FuncGen<'a, M: Machine> { // Immutable properties assigned at creation time. diff --git a/lib/compiler-singlepass/src/unwind.rs b/lib/compiler-singlepass/src/unwind.rs index dae1ce8ec34..1c7653ac234 100644 --- a/lib/compiler-singlepass/src/unwind.rs +++ b/lib/compiler-singlepass/src/unwind.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "unwind")] use gimli::{write::CallFrameInstruction, write::CommonInformationEntry, Encoding, Format, X86_64}; use std::fmt::Debug; use wasmer_compiler::Architecture; @@ -9,6 +10,7 @@ pub enum UnwindOps { } /// generate a default systemv cie +#[cfg(feature = "unwind")] pub fn create_systemv_cie(arch: Architecture) -> Option { match arch { Architecture::X86_64 => { From 16d2b7877696732f942e9d63975569bd10581c09 Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Thu, 3 Mar 2022 14:41:28 +0100 Subject: [PATCH 04/14] Filling some FDE information on x86_64 now --- lib/compiler-singlepass/src/arm64_decl.rs | 6 + lib/compiler-singlepass/src/codegen.rs | 28 ++- lib/compiler-singlepass/src/dwarf.rs | 204 +++++++++---------- lib/compiler-singlepass/src/location.rs | 1 + lib/compiler-singlepass/src/machine.rs | 3 + lib/compiler-singlepass/src/machine_arm64.rs | 4 + lib/compiler-singlepass/src/machine_x64.rs | 116 ++++++++++- lib/compiler-singlepass/src/unwind.rs | 27 ++- lib/compiler-singlepass/src/x64_decl.rs | 23 +++ tests/ignores.txt | 7 +- 10 files changed, 298 insertions(+), 121 deletions(-) diff --git a/lib/compiler-singlepass/src/arm64_decl.rs b/lib/compiler-singlepass/src/arm64_decl.rs index 6aab5dbc13e..ea91cbdc1f4 100644 --- a/lib/compiler-singlepass/src/arm64_decl.rs +++ b/lib/compiler-singlepass/src/arm64_decl.rs @@ -141,6 +141,9 @@ impl AbstractReg for GPR { ]; GPRS.iter() } + fn to_dwarf(self) -> u16 { + self.into_index() as u16 + } } impl AbstractReg for NEON { @@ -196,6 +199,9 @@ impl AbstractReg for NEON { ]; NEONS.iter() } + fn to_dwarf(self) -> u16 { + self.into_index() as u16 + 64 + } } /// A machine register under the x86-64 architecture. diff --git a/lib/compiler-singlepass/src/codegen.rs b/lib/compiler-singlepass/src/codegen.rs index 5887bec9a5a..1c8b7f21245 100644 --- a/lib/compiler-singlepass/src/codegen.rs +++ b/lib/compiler-singlepass/src/codegen.rs @@ -1,13 +1,17 @@ use crate::address_map::get_function_address_map; +#[cfg(feature = "unwind")] +use crate::dwarf::WriterRelocate; use crate::location::{Location, Reg}; use crate::machine::{CodegenError, Label, Machine, MachineStackOffset, NATIVE_PAGE_SIZE}; use crate::{common_decl::*, config::Singlepass}; #[cfg(feature = "unwind")] -use gimli::write::FrameDescriptionEntry; +use gimli::write::{Address, FrameDescriptionEntry}; use smallvec::{smallvec, SmallVec}; use std::cmp; use std::iter; use wasmer_compiler::wasmparser::{Operator, Type as WpType, TypeOrFuncType as WpTypeOrFuncType}; +#[cfg(feature = "unwind")] +use wasmer_compiler::CompiledFunctionUnwindInfo; use wasmer_compiler::{ CallingConvention, CompiledFunction, CompiledFunctionFrameInfo, FunctionBody, FunctionBodyData, Relocation, RelocationTarget, SectionIndex, @@ -5898,6 +5902,24 @@ impl<'a, M: Machine> FuncGen<'a, M> { self.machine.finalize_function(); let body_len = self.machine.assembler_get_offset().0; + + #[cfg(feature = "unwind")] + let (unwind_info, fde) = { + let unwind_info = self.machine.gen_unwind_info(body_len); + match (self.calling_convention, unwind_info) { + (CallingConvention::SystemV, Some(unwind)) => { + let fde = unwind.to_fde(Address::Symbol { + symbol: WriterRelocate::FUNCTION_SYMBOL, + addend: self.fsm.local_function_id as _, + }); + (Some(CompiledFunctionUnwindInfo::Dwarf), Some(fde)) + } + (_, _) => (None, None), + } + }; + #[cfg(not(feature = "unwind"))] + let (unwind_info, fde) = (None, None); + let address_map = get_function_address_map(self.machine.instructions_address_map(), data, body_len); let traps = self.machine.collect_trap_information(); @@ -5907,7 +5929,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { CompiledFunction { body: FunctionBody { body: body, - unwind_info: None, + unwind_info, }, relocations: self.relocations.clone(), jt_offsets: SecondaryMap::new(), @@ -5916,7 +5938,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { address_map, }, }, - None, + fde, ) } // FIXME: This implementation seems to be not enough to resolve all kinds of register dependencies diff --git a/lib/compiler-singlepass/src/dwarf.rs b/lib/compiler-singlepass/src/dwarf.rs index 8a472f310c0..07e67bbdb00 100644 --- a/lib/compiler-singlepass/src/dwarf.rs +++ b/lib/compiler-singlepass/src/dwarf.rs @@ -1,102 +1,102 @@ -use gimli::write::{Address, EndianVec, Result, Writer}; -use gimli::{RunTimeEndian, SectionId}; -use wasmer_compiler::{CustomSection, CustomSectionProtection, SectionBody}; -use wasmer_compiler::{Endianness, Relocation, RelocationKind, RelocationTarget}; -use wasmer_types::entity::EntityRef; -use wasmer_types::LocalFunctionIndex; - -#[derive(Clone, Debug)] -pub struct WriterRelocate { - pub relocs: Vec, - writer: EndianVec, -} - -impl WriterRelocate { - pub const FUNCTION_SYMBOL: usize = 0; - pub fn new(endianness: Option) -> Self { - let endianness = match endianness { - Some(Endianness::Little) => RunTimeEndian::Little, - Some(Endianness::Big) => RunTimeEndian::Big, - // We autodetect it, based on the host - None => RunTimeEndian::default(), - }; - WriterRelocate { - relocs: Vec::new(), - writer: EndianVec::new(endianness), - } - } - - pub fn into_section(mut self) -> CustomSection { - // GCC expects a terminating "empty" length, so write a 0 length at the end of the table. - self.writer.write_u32(0).unwrap(); - let data = self.writer.into_vec(); - CustomSection { - protection: CustomSectionProtection::Read, - bytes: SectionBody::new_with_vec(data), - relocations: self.relocs, - } - } -} - -impl Writer for WriterRelocate { - type Endian = RunTimeEndian; - - fn endian(&self) -> Self::Endian { - self.writer.endian() - } - - fn len(&self) -> usize { - self.writer.len() - } - - fn write(&mut self, bytes: &[u8]) -> Result<()> { - self.writer.write(bytes) - } - - fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> { - self.writer.write_at(offset, bytes) - } - - fn write_address(&mut self, address: Address, size: u8) -> Result<()> { - match address { - Address::Constant(val) => self.write_udata(val, size), - Address::Symbol { symbol, addend } => { - // Is a function relocation - if symbol == Self::FUNCTION_SYMBOL { - // We use the addend to detect the function index - let function_index = LocalFunctionIndex::new(addend as _); - let reloc_target = RelocationTarget::LocalFunc(function_index); - let offset = self.len() as u32; - let kind = match size { - 8 => RelocationKind::Abs8, - _ => unimplemented!("dwarf relocation size not yet supported: {}", size), - }; - let addend = 0; - self.relocs.push(Relocation { - kind, - reloc_target, - offset, - addend, - }); - self.write_udata(addend as u64, size) - } else { - unreachable!("Symbol {} in DWARF not recognized", symbol); - } - } - } - } - - fn write_offset(&mut self, _val: usize, _section: SectionId, _size: u8) -> Result<()> { - unimplemented!("write_offset not yet implemented"); - } - - fn write_offset_at( - &mut self, - _offset: usize, - _val: usize, - _section: SectionId, - _size: u8, - ) -> Result<()> { - unimplemented!("write_offset_at not yet implemented"); - } -} +use gimli::write::{Address, EndianVec, Result, Writer}; +use gimli::{RunTimeEndian, SectionId}; +use wasmer_compiler::{CustomSection, CustomSectionProtection, SectionBody}; +use wasmer_compiler::{Endianness, Relocation, RelocationKind, RelocationTarget}; +use wasmer_types::entity::EntityRef; +use wasmer_types::LocalFunctionIndex; + +#[derive(Clone, Debug)] +pub struct WriterRelocate { + pub relocs: Vec, + writer: EndianVec, +} + +impl WriterRelocate { + pub const FUNCTION_SYMBOL: usize = 0; + pub fn new(endianness: Option) -> Self { + let endianness = match endianness { + Some(Endianness::Little) => RunTimeEndian::Little, + Some(Endianness::Big) => RunTimeEndian::Big, + // We autodetect it, based on the host + None => RunTimeEndian::default(), + }; + WriterRelocate { + relocs: Vec::new(), + writer: EndianVec::new(endianness), + } + } + + pub fn into_section(mut self) -> CustomSection { + // GCC expects a terminating "empty" length, so write a 0 length at the end of the table. + self.writer.write_u32(0).unwrap(); + let data = self.writer.into_vec(); + CustomSection { + protection: CustomSectionProtection::Read, + bytes: SectionBody::new_with_vec(data), + relocations: self.relocs, + } + } +} + +impl Writer for WriterRelocate { + type Endian = RunTimeEndian; + + fn endian(&self) -> Self::Endian { + self.writer.endian() + } + + fn len(&self) -> usize { + self.writer.len() + } + + fn write(&mut self, bytes: &[u8]) -> Result<()> { + self.writer.write(bytes) + } + + fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> { + self.writer.write_at(offset, bytes) + } + + fn write_address(&mut self, address: Address, size: u8) -> Result<()> { + match address { + Address::Constant(val) => self.write_udata(val, size), + Address::Symbol { symbol, addend } => { + // Is a function relocation + if symbol == Self::FUNCTION_SYMBOL { + // We use the addend to detect the function index + let function_index = LocalFunctionIndex::new(addend as _); + let reloc_target = RelocationTarget::LocalFunc(function_index); + let offset = self.len() as u32; + let kind = match size { + 8 => RelocationKind::Abs8, + _ => unimplemented!("dwarf relocation size not yet supported: {}", size), + }; + let addend = 0; + self.relocs.push(Relocation { + kind, + reloc_target, + offset, + addend, + }); + self.write_udata(addend as u64, size) + } else { + unreachable!("Symbol {} in DWARF not recognized", symbol); + } + } + } + } + + fn write_offset(&mut self, _val: usize, _section: SectionId, _size: u8) -> Result<()> { + unimplemented!("write_offset not yet implemented"); + } + + fn write_offset_at( + &mut self, + _offset: usize, + _val: usize, + _section: SectionId, + _size: u8, + ) -> Result<()> { + unimplemented!("write_offset_at not yet implemented"); + } +} diff --git a/lib/compiler-singlepass/src/location.rs b/lib/compiler-singlepass/src/location.rs index ca55828fcb3..4992fbf03af 100644 --- a/lib/compiler-singlepass/src/location.rs +++ b/lib/compiler-singlepass/src/location.rs @@ -44,6 +44,7 @@ pub trait Reg: Copy + Clone + Eq + PartialEq + Debug + Hash + Ord { fn into_index(self) -> usize; fn from_index(i: usize) -> Result; fn iterator() -> Iter<'static, Self>; + fn to_dwarf(self) -> u16; } pub trait Descriptor { diff --git a/lib/compiler-singlepass/src/machine.rs b/lib/compiler-singlepass/src/machine.rs index d7359342e9f..5a992227e2c 100644 --- a/lib/compiler-singlepass/src/machine.rs +++ b/lib/compiler-singlepass/src/machine.rs @@ -2,6 +2,7 @@ use crate::common_decl::*; use crate::location::{Location, Reg}; use crate::machine_arm64::MachineARM64; use crate::machine_x64::MachineX86_64; +use crate::unwind::UnwindInstructions; use dynasmrt::{AssemblyOffset, DynamicLabel}; use std::collections::BTreeMap; use std::fmt::Debug; @@ -2190,6 +2191,8 @@ pub trait Machine { sig: &FunctionType, calling_convention: CallingConvention, ) -> CustomSection; + /// generate eh_frame instruction (or None if not possible / supported) + fn gen_unwind_info(&mut self, code_len: usize) -> Option; } /// Standard entry trampoline generation diff --git a/lib/compiler-singlepass/src/machine_arm64.rs b/lib/compiler-singlepass/src/machine_arm64.rs index 98254944b47..b9dd533cc47 100644 --- a/lib/compiler-singlepass/src/machine_arm64.rs +++ b/lib/compiler-singlepass/src/machine_arm64.rs @@ -5,6 +5,7 @@ use crate::emitter_arm64::*; use crate::location::Location as AbstractLocation; use crate::location::Reg; use crate::machine::*; +use crate::unwind::UnwindInstructions; use dynasmrt::{aarch64::Aarch64Relocation, VecAssembler}; use wasmer_compiler::wasmparser::Type as WpType; use wasmer_compiler::{ @@ -5108,4 +5109,7 @@ impl Machine for MachineARM64 { ) -> CustomSection { gen_import_call_trampoline_arm64(vmoffsets, index, sig, calling_convention) } + fn gen_unwind_info(&mut self, _code_len: usize) -> Option { + None + } } diff --git a/lib/compiler-singlepass/src/machine_x64.rs b/lib/compiler-singlepass/src/machine_x64.rs index 1f31f175011..606014c821c 100644 --- a/lib/compiler-singlepass/src/machine_x64.rs +++ b/lib/compiler-singlepass/src/machine_x64.rs @@ -3,10 +3,12 @@ use crate::emitter_x64::*; use crate::location::Location as AbstractLocation; use crate::location::Reg; use crate::machine::*; -use crate::unwind::UnwindOps; +use crate::unwind::{UnwindInstructions, UnwindOps}; use crate::x64_decl::new_machine_state; use crate::x64_decl::{ArgumentRegisterAllocator, X64Register, GPR, XMM}; use dynasmrt::{x64::X64Relocation, DynasmError, VecAssembler}; +#[cfg(feature = "unwind")] +use gimli::{write::CallFrameInstruction, X86_64}; use std::ops::{Deref, DerefMut}; use wasmer_compiler::wasmparser::Type as WpType; use wasmer_compiler::{ @@ -56,6 +58,51 @@ impl DerefMut for AssemblerX64 { type Location = AbstractLocation; +#[cfg(feature = "unwind")] +fn dwarf_index(reg: u16) -> gimli::Register { + static DWARF_GPR: [gimli::Register; 16] = [ + X86_64::RAX, + X86_64::RDX, + X86_64::RCX, + X86_64::RBX, + X86_64::RSI, + X86_64::RDI, + X86_64::RBP, + X86_64::RSP, + X86_64::R8, + X86_64::R9, + X86_64::R10, + X86_64::R11, + X86_64::R12, + X86_64::R13, + X86_64::R14, + X86_64::R15, + ]; + static DWARF_XMM: [gimli::Register; 16] = [ + X86_64::XMM0, + X86_64::XMM1, + X86_64::XMM2, + X86_64::XMM3, + X86_64::XMM4, + X86_64::XMM5, + X86_64::XMM6, + X86_64::XMM7, + X86_64::XMM8, + X86_64::XMM9, + X86_64::XMM10, + X86_64::XMM11, + X86_64::XMM12, + X86_64::XMM13, + X86_64::XMM14, + X86_64::XMM15, + ]; + match reg { + 0..=15 => DWARF_GPR[reg as usize], + 17..=24 => DWARF_XMM[reg as usize - 17], + _ => panic!("Unknown register index {}", reg), + } +} + pub struct MachineX86_64 { assembler: AssemblerX64, used_gprs: u32, @@ -1938,6 +1985,27 @@ impl Machine for MachineX86_64 { location, Location::Memory(GPR::RBP, -stack_offset), ); + match location { + Location::GPR(x) => { + self.unwind_ops.push(( + self.get_offset().0, + UnwindOps::SaveRegister { + reg: x.to_dwarf(), + bp_neg_offset: stack_offset, + }, + )); + } + Location::SIMD(x) => { + self.unwind_ops.push(( + self.get_offset().0, + UnwindOps::SaveRegister { + reg: x.to_dwarf(), + bp_neg_offset: stack_offset, + }, + )); + } + _ => (), + } } // List of register to save, depending on the CallingConvention @@ -2187,13 +2255,8 @@ impl Machine for MachineX86_64 { self.unwind_ops .push((self.get_offset().0, UnwindOps::PushFP { up_to_sp: 16 })); self.move_location(Size::S64, Location::GPR(GPR::RSP), Location::GPR(GPR::RBP)); - self.unwind_ops.push(( - self.get_offset().0, - UnwindOps::DefineNewFrame { - up_to_sp: 0, - down_to_clobber: 0, - }, - )); + self.unwind_ops + .push((self.get_offset().0, UnwindOps::DefineNewFrame)); } fn emit_function_epilog(&mut self) { @@ -7097,4 +7160,41 @@ impl Machine for MachineX86_64 { relocations: vec![], } } + #[cfg(feature = "unwind")] + fn gen_unwind_info(&mut self, code_len: usize) -> Option { + let mut instructions = vec![]; + for &(instruction_offset, ref inst) in &self.unwind_ops { + let instruction_offset = instruction_offset as u32; + match inst { + &UnwindOps::PushFP { up_to_sp } => { + instructions.push(( + instruction_offset, + CallFrameInstruction::CfaOffset(up_to_sp as i32), + )); + instructions.push(( + instruction_offset, + CallFrameInstruction::Offset(X86_64::RBP, -(up_to_sp as i32)), + )); + } + &UnwindOps::DefineNewFrame => { + instructions.push(( + instruction_offset, + CallFrameInstruction::CfaRegister(X86_64::RBP), + )); + } + &UnwindOps::SaveRegister { reg, bp_neg_offset } => instructions.push(( + instruction_offset, + CallFrameInstruction::Offset(dwarf_index(reg), -bp_neg_offset), + )), + } + } + Some(UnwindInstructions { + instructions, + len: code_len as u32, + }) + } + #[cfg(not(feature = "unwind"))] + fn gen_unwind_info(&mut self) -> Option { + None + } } diff --git a/lib/compiler-singlepass/src/unwind.rs b/lib/compiler-singlepass/src/unwind.rs index 1c7653ac234..4ae8e882900 100644 --- a/lib/compiler-singlepass/src/unwind.rs +++ b/lib/compiler-singlepass/src/unwind.rs @@ -1,12 +1,35 @@ #[cfg(feature = "unwind")] -use gimli::{write::CallFrameInstruction, write::CommonInformationEntry, Encoding, Format, X86_64}; +use gimli::write::{Address, CallFrameInstruction, CommonInformationEntry, FrameDescriptionEntry}; +#[cfg(feature = "unwind")] +use gimli::{Encoding, Format, X86_64}; use std::fmt::Debug; use wasmer_compiler::Architecture; #[derive(Clone, Debug)] pub enum UnwindOps { PushFP { up_to_sp: u32 }, - DefineNewFrame { up_to_sp: u32, down_to_clobber: u32 }, + DefineNewFrame, + SaveRegister { reg: u16, bp_neg_offset: i32 }, +} + +#[cfg(not(feature = "unwind"))] +pub type CallFrameInstruction = u32; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct UnwindInstructions { + pub instructions: Vec<(u32, CallFrameInstruction)>, + pub len: u32, +} + +impl UnwindInstructions { + /// Converts the unwind information into a `FrameDescriptionEntry`. + pub fn to_fde(&self, address: Address) -> gimli::write::FrameDescriptionEntry { + let mut fde = FrameDescriptionEntry::new(address, self.len); + for (offset, inst) in &self.instructions { + fde.add_instruction(*offset, inst.clone().into()); + } + fde + } } /// generate a default systemv cie diff --git a/lib/compiler-singlepass/src/x64_decl.rs b/lib/compiler-singlepass/src/x64_decl.rs index e6756e7b742..372a3b86886 100644 --- a/lib/compiler-singlepass/src/x64_decl.rs +++ b/lib/compiler-singlepass/src/x64_decl.rs @@ -94,6 +94,26 @@ impl AbstractReg for GPR { ]; GPRS.iter() } + fn to_dwarf(self) -> u16 { + match self { + GPR::RAX => 0, + GPR::RDX => 1, + GPR::RCX => 2, + GPR::RBX => 3, + GPR::RSI => 4, + GPR::RDI => 5, + GPR::RBP => 6, + GPR::RSP => 7, + GPR::R8 => 8, + GPR::R9 => 9, + GPR::R10 => 10, + GPR::R11 => 11, + GPR::R12 => 12, + GPR::R13 => 13, + GPR::R14 => 14, + GPR::R15 => 15, + } + } } impl AbstractReg for XMM { @@ -137,6 +157,9 @@ impl AbstractReg for XMM { ]; XMMS.iter() } + fn to_dwarf(self) -> u16 { + self.into_index() as u16 + 17 + } } /// A machine register under the x86-64 architecture. diff --git a/tests/ignores.txt b/tests/ignores.txt index a2efd9dbb3a..3eed3d12291 100644 --- a/tests/ignores.txt +++ b/tests/ignores.txt @@ -10,25 +10,20 @@ musl+dylib * # Dynamic loading not supported in Musl ## Traps. Tracing doesn't work properly in Singlepass ## Unwinding is not properly implemented in Singlepass # Needs investigation -singlepass traps::test_trap_trace dylib traps::test_trap_trace aarch64 traps::test_trap_trace -singlepass traps::test_trap_stack_overflow # Need to investigate dylib traps::test_trap_stack_overflow # Need to investigate aarch64 traps::test_trap_stack_overflow # Need to investigate -singlepass traps::trap_display_pretty llvm traps::trap_display_pretty dylib traps::trap_display_pretty aarch64 traps::trap_display_pretty -singlepass traps::trap_display_multi_module llvm traps::trap_display_multi_module dylib traps::trap_display_multi_module aarch64 traps::trap_display_multi_module -singlepass traps::call_signature_mismatch +singlepass traps::call_signature_mismatch # Need to investigate, get foo (a[0]:0x33) instead of 0x30 for inderect call llvm traps::call_signature_mismatch dylib traps::call_signature_mismatch macos+aarch64 traps::call_signature_mismatch -singlepass traps::start_trap_pretty llvm traps::start_trap_pretty dylib traps::start_trap_pretty aarch64 traps::start_trap_pretty From 8946f9933c201a4935d905aeb8209fdc7987aced Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Thu, 3 Mar 2022 15:44:33 +0100 Subject: [PATCH 05/14] Don't test windows+singlepass on unwind info, it's not implemented yet --- tests/ignores.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/ignores.txt b/tests/ignores.txt index 3eed3d12291..96d3f1dca23 100644 --- a/tests/ignores.txt +++ b/tests/ignores.txt @@ -10,13 +10,17 @@ musl+dylib * # Dynamic loading not supported in Musl ## Traps. Tracing doesn't work properly in Singlepass ## Unwinding is not properly implemented in Singlepass # Needs investigation +singlepass+windows traps::test_trap_trace dylib traps::test_trap_trace aarch64 traps::test_trap_trace +singlepass+windows traps::test_trap_stack_overflow # Need to investigate dylib traps::test_trap_stack_overflow # Need to investigate aarch64 traps::test_trap_stack_overflow # Need to investigate +singlepass+windows traps::trap_display_pretty llvm traps::trap_display_pretty dylib traps::trap_display_pretty aarch64 traps::trap_display_pretty +singlepass+windows traps::trap_display_multi_module llvm traps::trap_display_multi_module dylib traps::trap_display_multi_module aarch64 traps::trap_display_multi_module @@ -24,6 +28,7 @@ singlepass traps::call_signature_mismatch # Need to investigate, get foo (a[0] llvm traps::call_signature_mismatch dylib traps::call_signature_mismatch macos+aarch64 traps::call_signature_mismatch +singlepass+windows traps::start_trap_pretty llvm traps::start_trap_pretty dylib traps::start_trap_pretty aarch64 traps::start_trap_pretty From 9e56f563a9819415c4facb4ac375e2ef0819063f Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Thu, 3 Mar 2022 15:46:30 +0100 Subject: [PATCH 06/14] Fix for no-unwind build --- lib/compiler-singlepass/src/machine_x64.rs | 2 +- lib/compiler-singlepass/src/unwind.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/compiler-singlepass/src/machine_x64.rs b/lib/compiler-singlepass/src/machine_x64.rs index 606014c821c..c537f572b79 100644 --- a/lib/compiler-singlepass/src/machine_x64.rs +++ b/lib/compiler-singlepass/src/machine_x64.rs @@ -7194,7 +7194,7 @@ impl Machine for MachineX86_64 { }) } #[cfg(not(feature = "unwind"))] - fn gen_unwind_info(&mut self) -> Option { + fn gen_unwind_info(&mut self, _code_len: usize) -> Option { None } } diff --git a/lib/compiler-singlepass/src/unwind.rs b/lib/compiler-singlepass/src/unwind.rs index 4ae8e882900..0da609ff1ba 100644 --- a/lib/compiler-singlepass/src/unwind.rs +++ b/lib/compiler-singlepass/src/unwind.rs @@ -3,6 +3,7 @@ use gimli::write::{Address, CallFrameInstruction, CommonInformationEntry, FrameD #[cfg(feature = "unwind")] use gimli::{Encoding, Format, X86_64}; use std::fmt::Debug; +#[cfg(feature = "unwind")] use wasmer_compiler::Architecture; #[derive(Clone, Debug)] From e7fff40a278467bf0075d21c34cd5193a781b01e Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Thu, 3 Mar 2022 16:43:02 +0100 Subject: [PATCH 07/14] More fix for no-unwind build --- lib/compiler-singlepass/src/unwind.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/compiler-singlepass/src/unwind.rs b/lib/compiler-singlepass/src/unwind.rs index 0da609ff1ba..0809a6e14bd 100644 --- a/lib/compiler-singlepass/src/unwind.rs +++ b/lib/compiler-singlepass/src/unwind.rs @@ -22,6 +22,7 @@ pub struct UnwindInstructions { pub len: u32, } +#[cfg(feature = "unwind")] impl UnwindInstructions { /// Converts the unwind information into a `FrameDescriptionEntry`. pub fn to_fde(&self, address: Address) -> gimli::write::FrameDescriptionEntry { From d8c9f0ebdd8bf44b0a2b646f514e27de5d2950f0 Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Fri, 4 Mar 2022 16:41:05 +0100 Subject: [PATCH 08/14] Added a emit_unwind_op helper --- lib/compiler-singlepass/src/machine_x64.rs | 31 +++++++++------------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/lib/compiler-singlepass/src/machine_x64.rs b/lib/compiler-singlepass/src/machine_x64.rs index c537f572b79..35a20adecd7 100644 --- a/lib/compiler-singlepass/src/machine_x64.rs +++ b/lib/compiler-singlepass/src/machine_x64.rs @@ -1666,6 +1666,9 @@ impl MachineX86_64 { self.used_simd &= !(1 << r.into_index()); ret } + fn emit_unwind_op(&mut self, op: UnwindOps) { + self.unwind_ops.push((self.get_offset().0, op)); + } } impl Machine for MachineX86_64 { @@ -1987,22 +1990,16 @@ impl Machine for MachineX86_64 { ); match location { Location::GPR(x) => { - self.unwind_ops.push(( - self.get_offset().0, - UnwindOps::SaveRegister { - reg: x.to_dwarf(), - bp_neg_offset: stack_offset, - }, - )); + self.emit_unwind_op(UnwindOps::SaveRegister { + reg: x.to_dwarf(), + bp_neg_offset: stack_offset, + }); } Location::SIMD(x) => { - self.unwind_ops.push(( - self.get_offset().0, - UnwindOps::SaveRegister { - reg: x.to_dwarf(), - bp_neg_offset: stack_offset, - }, - )); + self.emit_unwind_op(UnwindOps::SaveRegister { + reg: x.to_dwarf(), + bp_neg_offset: stack_offset, + }); } _ => (), } @@ -2252,11 +2249,9 @@ impl Machine for MachineX86_64 { fn emit_function_prolog(&mut self) { self.emit_push(Size::S64, Location::GPR(GPR::RBP)); - self.unwind_ops - .push((self.get_offset().0, UnwindOps::PushFP { up_to_sp: 16 })); + self.emit_unwind_op(UnwindOps::PushFP { up_to_sp: 16 }); self.move_location(Size::S64, Location::GPR(GPR::RSP), Location::GPR(GPR::RBP)); - self.unwind_ops - .push((self.get_offset().0, UnwindOps::DefineNewFrame)); + self.emit_unwind_op(UnwindOps::DefineNewFrame); } fn emit_function_epilog(&mut self) { From 3bc9505cd724af129721e2e935fe9d4e5eccc346 Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Tue, 8 Mar 2022 14:24:43 +0100 Subject: [PATCH 09/14] Added some support for Eh_frame generation on Aarch64 singlpass --- Cargo.lock | 7 +- lib/compiler-singlepass/Cargo.toml | 2 +- lib/compiler-singlepass/src/machine_arm64.rs | 165 ++++++++++++++++++- lib/compiler-singlepass/src/machine_x64.rs | 1 + lib/compiler-singlepass/src/unwind.rs | 18 +- tests/ignores.txt | 10 +- 6 files changed, 193 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c835cd4843..d1a2933ba1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -985,6 +985,11 @@ name = "gimli" version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] [[package]] name = "glob" @@ -2989,7 +2994,7 @@ dependencies = [ "byteorder", "dynasm", "dynasmrt", - "gimli 0.25.0", + "gimli 0.26.1", "hashbrown 0.11.2", "lazy_static", "loupe", diff --git a/lib/compiler-singlepass/Cargo.toml b/lib/compiler-singlepass/Cargo.toml index 42662d94f9d..aeaf63e18a0 100644 --- a/lib/compiler-singlepass/Cargo.toml +++ b/lib/compiler-singlepass/Cargo.toml @@ -17,7 +17,7 @@ wasmer-vm = { path = "../vm", version = "=2.2.0" } wasmer-types = { path = "../types", version = "=2.2.0", default-features = false, features = ["std"] } rayon = { version = "1.5", optional = true } hashbrown = { version = "0.11", optional = true } -gimli = { version = "0.25", optional = true } +gimli = { version = "0.26", optional = true } more-asserts = "0.2" dynasm = "1.2.1" dynasmrt = "1.2.1" diff --git a/lib/compiler-singlepass/src/machine_arm64.rs b/lib/compiler-singlepass/src/machine_arm64.rs index b9dd533cc47..83d604b7acd 100644 --- a/lib/compiler-singlepass/src/machine_arm64.rs +++ b/lib/compiler-singlepass/src/machine_arm64.rs @@ -5,8 +5,10 @@ use crate::emitter_arm64::*; use crate::location::Location as AbstractLocation; use crate::location::Reg; use crate::machine::*; -use crate::unwind::UnwindInstructions; +use crate::unwind::{UnwindInstructions, UnwindOps}; use dynasmrt::{aarch64::Aarch64Relocation, VecAssembler}; +#[cfg(feature = "unwind")] +use gimli::{write::CallFrameInstruction, AArch64}; use wasmer_compiler::wasmparser::Type as WpType; use wasmer_compiler::{ CallingConvention, CustomSection, FunctionBody, InstructionAddressMap, Relocation, @@ -18,6 +20,83 @@ use wasmer_vm::{TrapCode, VMOffsets}; type Assembler = VecAssembler; type Location = AbstractLocation; +#[cfg(feature = "unwind")] +fn dwarf_index(reg: u16) -> gimli::Register { + static DWARF_GPR: [gimli::Register; 32] = [ + AArch64::X0, + AArch64::X1, + AArch64::X2, + AArch64::X3, + AArch64::X4, + AArch64::X5, + AArch64::X6, + AArch64::X7, + AArch64::X8, + AArch64::X9, + AArch64::X10, + AArch64::X11, + AArch64::X12, + AArch64::X13, + AArch64::X14, + AArch64::X15, + AArch64::X16, + AArch64::X17, + AArch64::X18, + AArch64::X19, + AArch64::X20, + AArch64::X21, + AArch64::X22, + AArch64::X23, + AArch64::X24, + AArch64::X25, + AArch64::X26, + AArch64::X27, + AArch64::X28, + AArch64::X29, + AArch64::X30, + AArch64::SP, + ]; + static DWARF_NEON: [gimli::Register; 32] = [ + AArch64::V0, + AArch64::V1, + AArch64::V2, + AArch64::V3, + AArch64::V4, + AArch64::V5, + AArch64::V6, + AArch64::V7, + AArch64::V8, + AArch64::V9, + AArch64::V10, + AArch64::V11, + AArch64::V12, + AArch64::V13, + AArch64::V14, + AArch64::V15, + AArch64::V16, + AArch64::V17, + AArch64::V18, + AArch64::V19, + AArch64::V20, + AArch64::V21, + AArch64::V22, + AArch64::V23, + AArch64::V24, + AArch64::V25, + AArch64::V26, + AArch64::V27, + AArch64::V28, + AArch64::V29, + AArch64::V30, + AArch64::V31, + ]; + match reg { + 0..=31 => DWARF_GPR[reg as usize], + 64..=95 => DWARF_NEON[reg as usize - 64], + _ => panic!("Unknown register index {}", reg), + } +} + pub struct MachineARM64 { assembler: Assembler, used_gprs: u32, @@ -31,6 +110,8 @@ pub struct MachineARM64 { src_loc: u32, /// is last push on a 8byte multiple or 16bytes? pushed: bool, + /// Vector of unwind operations with offset + unwind_ops: Vec<(usize, UnwindOps)>, } #[allow(dead_code)] @@ -64,6 +145,7 @@ impl MachineARM64 { instructions_address_map: vec![], src_loc: 0, pushed: false, + unwind_ops: vec![], } } fn compatible_imm(&self, imm: i64, ty: ImmType) -> bool { @@ -1166,6 +1248,9 @@ impl MachineARM64 { self.used_simd &= !(1 << r.into_index()); ret } + fn emit_unwind_op(&mut self, op: UnwindOps) { + self.unwind_ops.push((self.get_offset().0, op)); + } } impl Machine for MachineARM64 { @@ -1546,6 +1631,21 @@ impl Machine for MachineARM64 { self.assembler .emit_str(Size::S64, location, Location::GPR(tmp)); } + match location { + Location::GPR(x) => { + self.emit_unwind_op(UnwindOps::SaveRegister { + reg: x.to_dwarf(), + bp_neg_offset: stack_offset, + }); + } + Location::SIMD(x) => { + self.emit_unwind_op(UnwindOps::SaveRegister { + reg: x.to_dwarf(), + bp_neg_offset: stack_offset, + }); + } + _ => (), + } } // List of register to save, depending on the CallingConvention @@ -1982,7 +2082,17 @@ impl Machine for MachineARM64 { fn emit_function_prolog(&mut self) { self.emit_double_push(Size::S64, Location::GPR(GPR::X29), Location::GPR(GPR::X30)); // save LR too + self.emit_unwind_op(UnwindOps::Push2Regs { + reg1: GPR::X29.to_dwarf(), + reg2: GPR::X30.to_dwarf(), + up_to_sp: 16, + }); self.emit_double_push(Size::S64, Location::GPR(GPR::X27), Location::GPR(GPR::X28)); + self.emit_unwind_op(UnwindOps::Push2Regs { + reg1: GPR::X27.to_dwarf(), + reg2: GPR::X28.to_dwarf(), + up_to_sp: 32, + }); // cannot use mov, because XSP is XZR there. Need to use ADD with #0 self.assembler.emit_add( Size::S64, @@ -1990,6 +2100,7 @@ impl Machine for MachineARM64 { Location::Imm8(0), Location::GPR(GPR::X29), ); + self.emit_unwind_op(UnwindOps::DefineNewFrame); } fn emit_function_epilog(&mut self) { @@ -5109,6 +5220,58 @@ impl Machine for MachineARM64 { ) -> CustomSection { gen_import_call_trampoline_arm64(vmoffsets, index, sig, calling_convention) } + #[cfg(feature = "unwind")] + fn gen_unwind_info(&mut self, code_len: usize) -> Option { + let mut instructions = vec![]; + for &(instruction_offset, ref inst) in &self.unwind_ops { + let instruction_offset = instruction_offset as u32; + match inst { + &UnwindOps::PushFP { up_to_sp } => { + instructions.push(( + instruction_offset, + CallFrameInstruction::CfaOffset(up_to_sp as i32), + )); + instructions.push(( + instruction_offset, + CallFrameInstruction::Offset(AArch64::X29, -(up_to_sp as i32)), + )); + } + &UnwindOps::Push2Regs { + reg1, + reg2, + up_to_sp, + } => { + instructions.push(( + instruction_offset, + CallFrameInstruction::CfaOffset(up_to_sp as i32), + )); + instructions.push(( + instruction_offset, + CallFrameInstruction::Offset(dwarf_index(reg2), -(up_to_sp as i32) + 8), + )); + instructions.push(( + instruction_offset, + CallFrameInstruction::Offset(dwarf_index(reg1), -(up_to_sp as i32)), + )); + } + &UnwindOps::DefineNewFrame => { + instructions.push(( + instruction_offset, + CallFrameInstruction::CfaRegister(AArch64::X29), + )); + } + &UnwindOps::SaveRegister { reg, bp_neg_offset } => instructions.push(( + instruction_offset, + CallFrameInstruction::Offset(dwarf_index(reg), -bp_neg_offset), + )), + } + } + Some(UnwindInstructions { + instructions, + len: code_len as u32, + }) + } + #[cfg(not(feature = "unwind"))] fn gen_unwind_info(&mut self, _code_len: usize) -> Option { None } diff --git a/lib/compiler-singlepass/src/machine_x64.rs b/lib/compiler-singlepass/src/machine_x64.rs index 35a20adecd7..8431c6b6981 100644 --- a/lib/compiler-singlepass/src/machine_x64.rs +++ b/lib/compiler-singlepass/src/machine_x64.rs @@ -7181,6 +7181,7 @@ impl Machine for MachineX86_64 { instruction_offset, CallFrameInstruction::Offset(dwarf_index(reg), -bp_neg_offset), )), + &UnwindOps::Push2Regs { .. } => unimplemented!(), } } Some(UnwindInstructions { diff --git a/lib/compiler-singlepass/src/unwind.rs b/lib/compiler-singlepass/src/unwind.rs index 0809a6e14bd..2b2248de096 100644 --- a/lib/compiler-singlepass/src/unwind.rs +++ b/lib/compiler-singlepass/src/unwind.rs @@ -1,7 +1,7 @@ #[cfg(feature = "unwind")] use gimli::write::{Address, CallFrameInstruction, CommonInformationEntry, FrameDescriptionEntry}; #[cfg(feature = "unwind")] -use gimli::{Encoding, Format, X86_64}; +use gimli::{AArch64, Encoding, Format, X86_64}; use std::fmt::Debug; #[cfg(feature = "unwind")] use wasmer_compiler::Architecture; @@ -9,6 +9,7 @@ use wasmer_compiler::Architecture; #[derive(Clone, Debug)] pub enum UnwindOps { PushFP { up_to_sp: u32 }, + Push2Regs { reg1: u16, reg2: u16, up_to_sp: u32 }, DefineNewFrame, SaveRegister { reg: u16, bp_neg_offset: i32 }, } @@ -53,7 +54,20 @@ pub fn create_systemv_cie(arch: Architecture) -> Option None, + Architecture::Aarch64(_) => { + let mut entry = CommonInformationEntry::new( + Encoding { + address_size: 8, + format: Format::Dwarf32, + version: 1, + }, + 1, + -8, + AArch64::X30, + ); + entry.add_instruction(CallFrameInstruction::Cfa(AArch64::SP, 0)); + Some(entry) + } _ => None, } } diff --git a/tests/ignores.txt b/tests/ignores.txt index 96d3f1dca23..730d3ffeeb1 100644 --- a/tests/ignores.txt +++ b/tests/ignores.txt @@ -12,18 +12,18 @@ musl+dylib * # Dynamic loading not supported in Musl # Needs investigation singlepass+windows traps::test_trap_trace dylib traps::test_trap_trace -aarch64 traps::test_trap_trace +cranelift+aarch64 traps::test_trap_trace singlepass+windows traps::test_trap_stack_overflow # Need to investigate dylib traps::test_trap_stack_overflow # Need to investigate -aarch64 traps::test_trap_stack_overflow # Need to investigate +cranelift+aarch64 traps::test_trap_stack_overflow # Need to investigate singlepass+windows traps::trap_display_pretty llvm traps::trap_display_pretty dylib traps::trap_display_pretty -aarch64 traps::trap_display_pretty +cranelift+aarch64 traps::trap_display_pretty singlepass+windows traps::trap_display_multi_module llvm traps::trap_display_multi_module dylib traps::trap_display_multi_module -aarch64 traps::trap_display_multi_module +cranelift+aarch64 traps::trap_display_multi_module singlepass traps::call_signature_mismatch # Need to investigate, get foo (a[0]:0x33) instead of 0x30 for inderect call llvm traps::call_signature_mismatch dylib traps::call_signature_mismatch @@ -31,7 +31,7 @@ macos+aarch64 traps::call_signature_mismatch singlepass+windows traps::start_trap_pretty llvm traps::start_trap_pretty dylib traps::start_trap_pretty -aarch64 traps::start_trap_pretty +cranelift+aarch64 traps::start_trap_pretty singlepass multi_value_imports::dylib # Singlepass doesn't support multivalue singlepass multi_value_imports::dynamic # Singlepass doesn't support multivalue From ca6d30fd8e7b3b89f3ae1cb25905fb914ce27695 Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Tue, 8 Mar 2022 14:33:01 +0100 Subject: [PATCH 10/14] Disable the trap test on Aarch64 macOS, it doesn't seems to work at all --- tests/ignores.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/ignores.txt b/tests/ignores.txt index 730d3ffeeb1..55ec710e469 100644 --- a/tests/ignores.txt +++ b/tests/ignores.txt @@ -11,16 +11,20 @@ musl+dylib * # Dynamic loading not supported in Musl ## Unwinding is not properly implemented in Singlepass # Needs investigation singlepass+windows traps::test_trap_trace +singlepass+aarch64+macos traps::test_trap_trace dylib traps::test_trap_trace cranelift+aarch64 traps::test_trap_trace singlepass+windows traps::test_trap_stack_overflow # Need to investigate +singlepass+aarch64+macos traps::test_trap_stack_overflow # Need to investigate dylib traps::test_trap_stack_overflow # Need to investigate cranelift+aarch64 traps::test_trap_stack_overflow # Need to investigate singlepass+windows traps::trap_display_pretty +singlepass+aarch64+macos traps::trap_display_pretty llvm traps::trap_display_pretty dylib traps::trap_display_pretty cranelift+aarch64 traps::trap_display_pretty singlepass+windows traps::trap_display_multi_module +singlepass+aarch64+macos traps::trap_display_multi_module llvm traps::trap_display_multi_module dylib traps::trap_display_multi_module cranelift+aarch64 traps::trap_display_multi_module @@ -29,6 +33,7 @@ llvm traps::call_signature_mismatch dylib traps::call_signature_mismatch macos+aarch64 traps::call_signature_mismatch singlepass+windows traps::start_trap_pretty +singlepass+aarch64+macos traps::start_trap_pretty llvm traps::start_trap_pretty dylib traps::start_trap_pretty cranelift+aarch64 traps::start_trap_pretty From 408847ee75caf5499d1b908f83864a3c46eba44d Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Fri, 11 Mar 2022 16:01:07 +0100 Subject: [PATCH 11/14] Added support for Windows x64 in Singlepass for Unwind infos --- lib/compiler-singlepass/src/codegen.rs | 42 +-- lib/compiler-singlepass/src/compiler.rs | 6 +- lib/compiler-singlepass/src/lib.rs | 2 + lib/compiler-singlepass/src/machine.rs | 2 + lib/compiler-singlepass/src/machine_arm64.rs | 4 + lib/compiler-singlepass/src/machine_x64.rs | 20 ++ lib/compiler-singlepass/src/unwind.rs | 12 +- lib/compiler-singlepass/src/unwind_winx64.rs | 306 +++++++++++++++++++ tests/ignores.txt | 10 +- 9 files changed, 378 insertions(+), 26 deletions(-) create mode 100644 lib/compiler-singlepass/src/unwind_winx64.rs diff --git a/lib/compiler-singlepass/src/codegen.rs b/lib/compiler-singlepass/src/codegen.rs index 1c8b7f21245..1af305fb25a 100644 --- a/lib/compiler-singlepass/src/codegen.rs +++ b/lib/compiler-singlepass/src/codegen.rs @@ -3,9 +3,10 @@ use crate::address_map::get_function_address_map; use crate::dwarf::WriterRelocate; use crate::location::{Location, Reg}; use crate::machine::{CodegenError, Label, Machine, MachineStackOffset, NATIVE_PAGE_SIZE}; +use crate::unwind::UnwindFrame; use crate::{common_decl::*, config::Singlepass}; #[cfg(feature = "unwind")] -use gimli::write::{Address, FrameDescriptionEntry}; +use gimli::write::Address; use smallvec::{smallvec, SmallVec}; use std::cmp; use std::iter; @@ -26,9 +27,6 @@ use wasmer_types::{ }; use wasmer_vm::{MemoryStyle, TableStyle, TrapCode, VMBuiltinFunctionIndex, VMOffsets}; -#[cfg(not(feature = "unwind"))] -pub type FrameDescriptionEntry = u32; - /// The singlepass per-function code generator. pub struct FuncGen<'a, M: Machine> { // Immutable properties assigned at creation time. @@ -5859,10 +5857,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { Ok(()) } - pub fn finalize( - mut self, - data: &FunctionBodyData, - ) -> (CompiledFunction, Option) { + pub fn finalize(mut self, data: &FunctionBodyData) -> (CompiledFunction, Option) { // Generate actual code for special labels. self.machine .emit_label(self.special_labels.integer_division_by_zero); @@ -5905,16 +5900,29 @@ impl<'a, M: Machine> FuncGen<'a, M> { #[cfg(feature = "unwind")] let (unwind_info, fde) = { - let unwind_info = self.machine.gen_unwind_info(body_len); - match (self.calling_convention, unwind_info) { - (CallingConvention::SystemV, Some(unwind)) => { - let fde = unwind.to_fde(Address::Symbol { - symbol: WriterRelocate::FUNCTION_SYMBOL, - addend: self.fsm.local_function_id as _, - }); - (Some(CompiledFunctionUnwindInfo::Dwarf), Some(fde)) + match self.calling_convention { + CallingConvention::SystemV | CallingConvention::AppleAarch64 => { + let unwind_info = self.machine.gen_unwind_info(body_len); + if let Some(unwind) = unwind_info { + let fde = unwind.to_fde(Address::Symbol { + symbol: WriterRelocate::FUNCTION_SYMBOL, + addend: self.fsm.local_function_id as _, + }); + (Some(CompiledFunctionUnwindInfo::Dwarf), Some(fde)) + } else { + (None, None) + } + } + CallingConvention::WindowsFastcall => { + let unwind_info = self.machine.gen_windows_unwind_info(body_len); + match unwind_info { + Some(unwind) => { + (Some(CompiledFunctionUnwindInfo::WindowsX64(unwind)), None) + } + _ => (None, None), + } } - (_, _) => (None, None), + _ => (None, None), } }; #[cfg(not(feature = "unwind"))] diff --git a/lib/compiler-singlepass/src/compiler.rs b/lib/compiler-singlepass/src/compiler.rs index 03dcc996fa4..958a6b3fe7c 100644 --- a/lib/compiler-singlepass/src/compiler.rs +++ b/lib/compiler-singlepass/src/compiler.rs @@ -13,7 +13,7 @@ use crate::machine::{ use crate::machine_arm64::MachineARM64; use crate::machine_x64::MachineX86_64; #[cfg(feature = "unwind")] -use crate::unwind::create_systemv_cie; +use crate::unwind::{create_systemv_cie, UnwindFrame}; #[cfg(feature = "unwind")] use gimli::write::{EhFrame, FrameTable}; use loupe::MemoryUsage; @@ -249,7 +249,9 @@ impl Compiler for SinglepassCompiler { let dwarf = if let Some((mut dwarf_frametable, cie_id)) = dwarf_frametable { for fde in fdes { if let Some(fde) = fde { - dwarf_frametable.add_fde(cie_id, fde); + match fde { + UnwindFrame::SystemV(fde) => dwarf_frametable.add_fde(cie_id, fde), + } } } let mut eh_frame = EhFrame(WriterRelocate::new(target.triple().endianness().ok())); diff --git a/lib/compiler-singlepass/src/lib.rs b/lib/compiler-singlepass/src/lib.rs index ef2ca8d0599..fea110ab868 100644 --- a/lib/compiler-singlepass/src/lib.rs +++ b/lib/compiler-singlepass/src/lib.rs @@ -23,6 +23,8 @@ mod machine; mod machine_arm64; mod machine_x64; mod unwind; +#[cfg(feature = "unwind")] +mod unwind_winx64; mod x64_decl; pub use crate::compiler::SinglepassCompiler; diff --git a/lib/compiler-singlepass/src/machine.rs b/lib/compiler-singlepass/src/machine.rs index 5a992227e2c..8b557f3df79 100644 --- a/lib/compiler-singlepass/src/machine.rs +++ b/lib/compiler-singlepass/src/machine.rs @@ -2193,6 +2193,8 @@ pub trait Machine { ) -> CustomSection; /// generate eh_frame instruction (or None if not possible / supported) fn gen_unwind_info(&mut self, code_len: usize) -> Option; + /// generate Windows unwind instructions (or None if not possible / supported) + fn gen_windows_unwind_info(&mut self, code_len: usize) -> Option>; } /// Standard entry trampoline generation diff --git a/lib/compiler-singlepass/src/machine_arm64.rs b/lib/compiler-singlepass/src/machine_arm64.rs index 83d604b7acd..a36567c4a72 100644 --- a/lib/compiler-singlepass/src/machine_arm64.rs +++ b/lib/compiler-singlepass/src/machine_arm64.rs @@ -5275,4 +5275,8 @@ impl Machine for MachineARM64 { fn gen_unwind_info(&mut self, _code_len: usize) -> Option { None } + + fn gen_windows_unwind_info(&mut self, code_len: usize) -> Option> { + None + } } diff --git a/lib/compiler-singlepass/src/machine_x64.rs b/lib/compiler-singlepass/src/machine_x64.rs index 8431c6b6981..e955480b804 100644 --- a/lib/compiler-singlepass/src/machine_x64.rs +++ b/lib/compiler-singlepass/src/machine_x64.rs @@ -4,6 +4,8 @@ use crate::location::Location as AbstractLocation; use crate::location::Reg; use crate::machine::*; use crate::unwind::{UnwindInstructions, UnwindOps}; +#[cfg(feature = "unwind")] +use crate::unwind_winx64::create_unwind_info_from_insts; use crate::x64_decl::new_machine_state; use crate::x64_decl::{ArgumentRegisterAllocator, X64Register, GPR, XMM}; use dynasmrt::{x64::X64Relocation, DynasmError, VecAssembler}; @@ -7193,4 +7195,22 @@ impl Machine for MachineX86_64 { fn gen_unwind_info(&mut self, _code_len: usize) -> Option { None } + + #[cfg(feature = "unwind")] + fn gen_windows_unwind_info(&mut self, _code_len: usize) -> Option> { + let unwind_info = create_unwind_info_from_insts(&self.unwind_ops); + if let Some(unwind) = unwind_info { + let sz = unwind.emit_size(); + let mut tbl = vec![0; sz]; + unwind.emit(&mut tbl); + Some(tbl) + } else { + None + } + } + + #[cfg(not(feature = "unwind"))] + fn gen_windows_unwind_info(&mut self, _code_len: usize) -> Option> { + None + } } diff --git a/lib/compiler-singlepass/src/unwind.rs b/lib/compiler-singlepass/src/unwind.rs index 2b2248de096..03ffe6ee642 100644 --- a/lib/compiler-singlepass/src/unwind.rs +++ b/lib/compiler-singlepass/src/unwind.rs @@ -23,15 +23,23 @@ pub struct UnwindInstructions { pub len: u32, } +#[cfg(feature = "unwind")] +pub enum UnwindFrame { + SystemV(gimli::write::FrameDescriptionEntry), +} + +#[cfg(not(feature = "unwind"))] +pub type UnwindFrame = u32; + #[cfg(feature = "unwind")] impl UnwindInstructions { /// Converts the unwind information into a `FrameDescriptionEntry`. - pub fn to_fde(&self, address: Address) -> gimli::write::FrameDescriptionEntry { + pub fn to_fde(&self, address: Address) -> UnwindFrame { let mut fde = FrameDescriptionEntry::new(address, self.len); for (offset, inst) in &self.instructions { fde.add_instruction(*offset, inst.clone().into()); } - fde + UnwindFrame::SystemV(fde) } } diff --git a/lib/compiler-singlepass/src/unwind_winx64.rs b/lib/compiler-singlepass/src/unwind_winx64.rs new file mode 100644 index 00000000000..1e67bcb5db9 --- /dev/null +++ b/lib/compiler-singlepass/src/unwind_winx64.rs @@ -0,0 +1,306 @@ +//! Windows x64 ABI unwind information. + +use crate::unwind::UnwindOps; + +/// Maximum (inclusive) size of a "small" stack allocation +const SMALL_ALLOC_MAX_SIZE: u32 = 128; +/// Maximum (inclusive) size of a "large" stack allocation that can represented in 16-bits +const LARGE_ALLOC_16BIT_MAX_SIZE: u32 = 524280; + +struct Writer<'a> { + buf: &'a mut [u8], + offset: usize, +} + +impl<'a> Writer<'a> { + pub fn new(buf: &'a mut [u8]) -> Self { + Self { buf, offset: 0 } + } + + fn write_u8(&mut self, v: u8) { + self.buf[self.offset] = v; + self.offset += 1; + } + + fn write_u16_le(&mut self, v: u16) { + self.buf[self.offset..(self.offset + 2)].copy_from_slice(&v.to_le_bytes()); + self.offset += 2; + } + + fn write_u32_le(&mut self, v: u32) { + self.buf[self.offset..(self.offset + 4)].copy_from_slice(&v.to_le_bytes()); + self.offset += 4; + } +} + +/// The supported unwind codes for the x64 Windows ABI. +/// +/// See: +/// Only what is needed to describe the prologues generated by the Cranelift x86 ISA are represented here. +/// Note: the Cranelift x86 ISA RU enum matches the Windows unwind GPR encoding values. +#[allow(dead_code)] +#[derive(Clone, Debug, PartialEq, Eq)] +pub(crate) enum UnwindCode { + PushRegister { + instruction_offset: u8, + reg: u8, + }, + SaveReg { + instruction_offset: u8, + reg: u8, + stack_offset: u32, + }, + SaveXmm { + instruction_offset: u8, + reg: u8, + stack_offset: u32, + }, + StackAlloc { + instruction_offset: u8, + size: u32, + }, + SetFPReg { + instruction_offset: u8, + }, +} + +impl UnwindCode { + fn emit(&self, writer: &mut Writer) { + enum UnwindOperation { + PushNonvolatileRegister = 0, + LargeStackAlloc = 1, + SmallStackAlloc = 2, + SetFPReg = 3, + SaveNonVolatileRegister = 4, + SaveNonVolatileRegisterFar = 5, + SaveXmm128 = 8, + SaveXmm128Far = 9, + } + + match self { + Self::PushRegister { + instruction_offset, + reg, + } => { + writer.write_u8(*instruction_offset); + writer.write_u8((*reg << 4) | (UnwindOperation::PushNonvolatileRegister as u8)); + } + Self::SaveReg { + instruction_offset, + reg, + stack_offset, + } + | Self::SaveXmm { + instruction_offset, + reg, + stack_offset, + } => { + let is_xmm = match self { + Self::SaveXmm { .. } => true, + _ => false, + }; + let (op_small, op_large) = if is_xmm { + (UnwindOperation::SaveXmm128, UnwindOperation::SaveXmm128Far) + } else { + ( + UnwindOperation::SaveNonVolatileRegister, + UnwindOperation::SaveNonVolatileRegisterFar, + ) + }; + writer.write_u8(*instruction_offset); + let scaled_stack_offset = stack_offset / 16; + if scaled_stack_offset <= core::u16::MAX as u32 { + writer.write_u8((*reg << 4) | (op_small as u8)); + writer.write_u16_le(scaled_stack_offset as u16); + } else { + writer.write_u8((*reg << 4) | (op_large as u8)); + writer.write_u16_le(*stack_offset as u16); + writer.write_u16_le((stack_offset >> 16) as u16); + } + } + Self::StackAlloc { + instruction_offset, + size, + } => { + // Stack allocations on Windows must be a multiple of 8 and be at least 1 slot + assert!(*size >= 8); + assert!((*size % 8) == 0); + + writer.write_u8(*instruction_offset); + if *size <= SMALL_ALLOC_MAX_SIZE { + writer.write_u8( + ((((*size - 8) / 8) as u8) << 4) | UnwindOperation::SmallStackAlloc as u8, + ); + } else if *size <= LARGE_ALLOC_16BIT_MAX_SIZE { + writer.write_u8(UnwindOperation::LargeStackAlloc as u8); + writer.write_u16_le((*size / 8) as u16); + } else { + writer.write_u8((1 << 4) | (UnwindOperation::LargeStackAlloc as u8)); + writer.write_u32_le(*size); + } + } + Self::SetFPReg { instruction_offset } => { + writer.write_u8(*instruction_offset); + writer.write_u8(UnwindOperation::SetFPReg as u8); + } + } + } + + fn node_count(&self) -> usize { + match self { + Self::StackAlloc { size, .. } => { + if *size <= SMALL_ALLOC_MAX_SIZE { + 1 + } else if *size <= LARGE_ALLOC_16BIT_MAX_SIZE { + 2 + } else { + 3 + } + } + Self::SaveXmm { stack_offset, .. } | Self::SaveReg { stack_offset, .. } => { + if *stack_offset <= core::u16::MAX as u32 { + 2 + } else { + 3 + } + } + _ => 1, + } + } +} + +/// Represents Windows x64 unwind information. +/// +/// For information about Windows x64 unwind info, see: +/// +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct UnwindInfo { + pub(crate) flags: u8, + pub(crate) prologue_size: u8, + pub(crate) frame_register: Option, + pub(crate) frame_register_offset: u8, + pub(crate) unwind_codes: Vec, +} + +impl UnwindInfo { + /// Gets the emit size of the unwind information, in bytes. + pub fn emit_size(&self) -> usize { + let node_count = self.node_count(); + + // Calculation of the size requires no SEH handler or chained info + assert!(self.flags == 0); + + // Size of fixed part of UNWIND_INFO is 4 bytes + // Then comes the UNWIND_CODE nodes (2 bytes each) + // Then comes 2 bytes of padding for the unwind codes if necessary + // Next would come the SEH data, but we assert above that the function doesn't have SEH data + + 4 + (node_count * 2) + if (node_count & 1) == 1 { 2 } else { 0 } + } + + /// Emits the unwind information into the given mutable byte slice. + /// + /// This function will panic if the slice is not at least `emit_size` in length. + pub fn emit(&self, buf: &mut [u8]) { + const UNWIND_INFO_VERSION: u8 = 1; + + let node_count = self.node_count(); + assert!(node_count <= 256); + + let mut writer = Writer::new(buf); + + writer.write_u8((self.flags << 3) | UNWIND_INFO_VERSION); + writer.write_u8(self.prologue_size); + writer.write_u8(node_count as u8); + + if let Some(reg) = self.frame_register { + writer.write_u8((self.frame_register_offset << 4) | reg); + } else { + writer.write_u8(0); + } + + // Unwind codes are written in reverse order (prologue offset descending) + for code in self.unwind_codes.iter().rev() { + code.emit(&mut writer); + } + + // To keep a 32-bit alignment, emit 2 bytes of padding if there's an odd number of 16-bit nodes + if (node_count & 1) == 1 { + writer.write_u16_le(0); + } + + // Ensure the correct number of bytes was emitted + assert_eq!(writer.offset, self.emit_size()); + } + + fn node_count(&self) -> usize { + self.unwind_codes + .iter() + .fold(0, |nodes, c| nodes + c.node_count()) + } +} + +const UNWIND_RBP_REG: u8 = 5; + +pub(crate) fn create_unwind_info_from_insts(insts: &Vec<(usize, UnwindOps)>) -> Option { + let mut unwind_codes = vec![]; + let mut frame_register_offset = 0; + let mut max_unwind_offset = 0; + for &(instruction_offset, ref inst) in insts { + let instruction_offset = ensure_unwind_offset(instruction_offset as u32)?; + match inst { + &UnwindOps::PushFP { .. } => { + unwind_codes.push(UnwindCode::PushRegister { + instruction_offset, + reg: UNWIND_RBP_REG, + }); + } + &UnwindOps::DefineNewFrame => { + frame_register_offset = ensure_unwind_offset(32)?; + unwind_codes.push(UnwindCode::SetFPReg { instruction_offset }); + } + &UnwindOps::SaveRegister { reg, bp_neg_offset } => match reg { + 0..=15 => { + // GPR reg + static FROM_DWARF: [u8; 16] = + [0, 2, 1, 3, 6, 7, 5, 4, 8, 9, 10, 11, 12, 13, 14, 15]; + unwind_codes.push(UnwindCode::SaveReg { + instruction_offset, + reg: FROM_DWARF[reg as usize], + stack_offset: bp_neg_offset as u32, + }); + } + 17..=32 => { + unwind_codes.push(UnwindCode::SaveXmm { + instruction_offset, + reg: reg as u8 - 17, + stack_offset: bp_neg_offset as u32, + }); + } + _ => { + unreachable!("unknown register index {}", reg); + } + }, + &UnwindOps::Push2Regs { .. } => { + unreachable!("no aarch64 on x64"); + } + } + max_unwind_offset = instruction_offset; + } + + Some(UnwindInfo { + flags: 0, + prologue_size: max_unwind_offset, + frame_register: Some(UNWIND_RBP_REG), + frame_register_offset, + unwind_codes, + }) +} + +fn ensure_unwind_offset(offset: u32) -> Option { + if offset > 255 { + panic!("function prologues cannot exceed 255 bytes in size for Windows x64"); + } + Some(offset as u8) +} diff --git a/tests/ignores.txt b/tests/ignores.txt index 55ec710e469..69979157879 100644 --- a/tests/ignores.txt +++ b/tests/ignores.txt @@ -10,20 +10,20 @@ musl+dylib * # Dynamic loading not supported in Musl ## Traps. Tracing doesn't work properly in Singlepass ## Unwinding is not properly implemented in Singlepass # Needs investigation -singlepass+windows traps::test_trap_trace +#singlepass+windows traps::test_trap_trace singlepass+aarch64+macos traps::test_trap_trace dylib traps::test_trap_trace cranelift+aarch64 traps::test_trap_trace -singlepass+windows traps::test_trap_stack_overflow # Need to investigate +#singlepass+windows traps::test_trap_stack_overflow # Need to investigate singlepass+aarch64+macos traps::test_trap_stack_overflow # Need to investigate dylib traps::test_trap_stack_overflow # Need to investigate cranelift+aarch64 traps::test_trap_stack_overflow # Need to investigate -singlepass+windows traps::trap_display_pretty +#singlepass+windows traps::trap_display_pretty singlepass+aarch64+macos traps::trap_display_pretty llvm traps::trap_display_pretty dylib traps::trap_display_pretty cranelift+aarch64 traps::trap_display_pretty -singlepass+windows traps::trap_display_multi_module +#singlepass+windows traps::trap_display_multi_module singlepass+aarch64+macos traps::trap_display_multi_module llvm traps::trap_display_multi_module dylib traps::trap_display_multi_module @@ -32,7 +32,7 @@ singlepass traps::call_signature_mismatch # Need to investigate, get foo (a[0] llvm traps::call_signature_mismatch dylib traps::call_signature_mismatch macos+aarch64 traps::call_signature_mismatch -singlepass+windows traps::start_trap_pretty +#singlepass+windows traps::start_trap_pretty singlepass+aarch64+macos traps::start_trap_pretty llvm traps::start_trap_pretty dylib traps::start_trap_pretty From f1b23b3af1c4479291c19e109a437a2dc057aa60 Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Fri, 11 Mar 2022 16:06:09 +0100 Subject: [PATCH 12/14] Small cleanup --- lib/compiler-singlepass/src/machine_arm64.rs | 2 +- tests/ignores.txt | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/compiler-singlepass/src/machine_arm64.rs b/lib/compiler-singlepass/src/machine_arm64.rs index a36567c4a72..55a432c5e3f 100644 --- a/lib/compiler-singlepass/src/machine_arm64.rs +++ b/lib/compiler-singlepass/src/machine_arm64.rs @@ -5276,7 +5276,7 @@ impl Machine for MachineARM64 { None } - fn gen_windows_unwind_info(&mut self, code_len: usize) -> Option> { + fn gen_windows_unwind_info(&mut self, _code_len: usize) -> Option> { None } } diff --git a/tests/ignores.txt b/tests/ignores.txt index 69979157879..9250068ae3c 100644 --- a/tests/ignores.txt +++ b/tests/ignores.txt @@ -10,20 +10,16 @@ musl+dylib * # Dynamic loading not supported in Musl ## Traps. Tracing doesn't work properly in Singlepass ## Unwinding is not properly implemented in Singlepass # Needs investigation -#singlepass+windows traps::test_trap_trace singlepass+aarch64+macos traps::test_trap_trace dylib traps::test_trap_trace cranelift+aarch64 traps::test_trap_trace -#singlepass+windows traps::test_trap_stack_overflow # Need to investigate singlepass+aarch64+macos traps::test_trap_stack_overflow # Need to investigate dylib traps::test_trap_stack_overflow # Need to investigate cranelift+aarch64 traps::test_trap_stack_overflow # Need to investigate -#singlepass+windows traps::trap_display_pretty singlepass+aarch64+macos traps::trap_display_pretty llvm traps::trap_display_pretty dylib traps::trap_display_pretty cranelift+aarch64 traps::trap_display_pretty -#singlepass+windows traps::trap_display_multi_module singlepass+aarch64+macos traps::trap_display_multi_module llvm traps::trap_display_multi_module dylib traps::trap_display_multi_module @@ -32,7 +28,6 @@ singlepass traps::call_signature_mismatch # Need to investigate, get foo (a[0] llvm traps::call_signature_mismatch dylib traps::call_signature_mismatch macos+aarch64 traps::call_signature_mismatch -#singlepass+windows traps::start_trap_pretty singlepass+aarch64+macos traps::start_trap_pretty llvm traps::start_trap_pretty dylib traps::start_trap_pretty From aebcb3e693a219c7823c9eb9319411fb28acb710 Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Thu, 17 Mar 2022 12:03:25 +0100 Subject: [PATCH 13/14] Renamed 'gen_unwind_info' to 'gen_dwarf_unwind_info' for better clarity --- lib/compiler-singlepass/src/codegen.rs | 2 +- lib/compiler-singlepass/src/machine.rs | 2 +- lib/compiler-singlepass/src/machine_arm64.rs | 4 ++-- lib/compiler-singlepass/src/machine_x64.rs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/compiler-singlepass/src/codegen.rs b/lib/compiler-singlepass/src/codegen.rs index 9ddca6cc4fb..c44ffb7f7f0 100644 --- a/lib/compiler-singlepass/src/codegen.rs +++ b/lib/compiler-singlepass/src/codegen.rs @@ -5903,7 +5903,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { let (unwind_info, fde) = { match self.calling_convention { CallingConvention::SystemV | CallingConvention::AppleAarch64 => { - let unwind_info = self.machine.gen_unwind_info(body_len); + let unwind_info = self.machine.gen_dwarf_unwind_info(body_len); if let Some(unwind) = unwind_info { let fde = unwind.to_fde(Address::Symbol { symbol: WriterRelocate::FUNCTION_SYMBOL, diff --git a/lib/compiler-singlepass/src/machine.rs b/lib/compiler-singlepass/src/machine.rs index 8b557f3df79..f2804f584c9 100644 --- a/lib/compiler-singlepass/src/machine.rs +++ b/lib/compiler-singlepass/src/machine.rs @@ -2192,7 +2192,7 @@ pub trait Machine { calling_convention: CallingConvention, ) -> CustomSection; /// generate eh_frame instruction (or None if not possible / supported) - fn gen_unwind_info(&mut self, code_len: usize) -> Option; + fn gen_dwarf_unwind_info(&mut self, code_len: usize) -> Option; /// generate Windows unwind instructions (or None if not possible / supported) fn gen_windows_unwind_info(&mut self, code_len: usize) -> Option>; } diff --git a/lib/compiler-singlepass/src/machine_arm64.rs b/lib/compiler-singlepass/src/machine_arm64.rs index 55a432c5e3f..a610a64b6b2 100644 --- a/lib/compiler-singlepass/src/machine_arm64.rs +++ b/lib/compiler-singlepass/src/machine_arm64.rs @@ -5221,7 +5221,7 @@ impl Machine for MachineARM64 { gen_import_call_trampoline_arm64(vmoffsets, index, sig, calling_convention) } #[cfg(feature = "unwind")] - fn gen_unwind_info(&mut self, code_len: usize) -> Option { + fn gen_dwarf_unwind_info(&mut self, code_len: usize) -> Option { let mut instructions = vec![]; for &(instruction_offset, ref inst) in &self.unwind_ops { let instruction_offset = instruction_offset as u32; @@ -5272,7 +5272,7 @@ impl Machine for MachineARM64 { }) } #[cfg(not(feature = "unwind"))] - fn gen_unwind_info(&mut self, _code_len: usize) -> Option { + fn gen_dwarf_unwind_info(&mut self, _code_len: usize) -> Option { None } diff --git a/lib/compiler-singlepass/src/machine_x64.rs b/lib/compiler-singlepass/src/machine_x64.rs index e955480b804..1944b3f862e 100644 --- a/lib/compiler-singlepass/src/machine_x64.rs +++ b/lib/compiler-singlepass/src/machine_x64.rs @@ -7158,7 +7158,7 @@ impl Machine for MachineX86_64 { } } #[cfg(feature = "unwind")] - fn gen_unwind_info(&mut self, code_len: usize) -> Option { + fn gen_dwarf_unwind_info(&mut self, code_len: usize) -> Option { let mut instructions = vec![]; for &(instruction_offset, ref inst) in &self.unwind_ops { let instruction_offset = instruction_offset as u32; @@ -7192,7 +7192,7 @@ impl Machine for MachineX86_64 { }) } #[cfg(not(feature = "unwind"))] - fn gen_unwind_info(&mut self, _code_len: usize) -> Option { + fn gen_dwarf_unwind_info(&mut self, _code_len: usize) -> Option { None } From 32603a2f4ccb7fcf1b9248607b5846e1d6276843 Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Thu, 17 Mar 2022 12:20:57 +0100 Subject: [PATCH 14/14] Simplifed generation of unwind info in singlepass codegen --- lib/compiler-singlepass/src/codegen.rs | 41 +++++++++++--------------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/lib/compiler-singlepass/src/codegen.rs b/lib/compiler-singlepass/src/codegen.rs index c44ffb7f7f0..fbced2e1e62 100644 --- a/lib/compiler-singlepass/src/codegen.rs +++ b/lib/compiler-singlepass/src/codegen.rs @@ -5899,35 +5899,28 @@ impl<'a, M: Machine> FuncGen<'a, M> { let body_len = self.machine.assembler_get_offset().0; + let mut unwind_info = None; + let mut fde = None; #[cfg(feature = "unwind")] - let (unwind_info, fde) = { - match self.calling_convention { - CallingConvention::SystemV | CallingConvention::AppleAarch64 => { - let unwind_info = self.machine.gen_dwarf_unwind_info(body_len); - if let Some(unwind) = unwind_info { - let fde = unwind.to_fde(Address::Symbol { - symbol: WriterRelocate::FUNCTION_SYMBOL, - addend: self.fsm.local_function_id as _, - }); - (Some(CompiledFunctionUnwindInfo::Dwarf), Some(fde)) - } else { - (None, None) - } + match self.calling_convention { + CallingConvention::SystemV | CallingConvention::AppleAarch64 => { + let unwind = self.machine.gen_dwarf_unwind_info(body_len); + if let Some(unwind) = unwind { + fde = Some(unwind.to_fde(Address::Symbol { + symbol: WriterRelocate::FUNCTION_SYMBOL, + addend: self.fsm.local_function_id as _, + })); + unwind_info = Some(CompiledFunctionUnwindInfo::Dwarf); } - CallingConvention::WindowsFastcall => { - let unwind_info = self.machine.gen_windows_unwind_info(body_len); - match unwind_info { - Some(unwind) => { - (Some(CompiledFunctionUnwindInfo::WindowsX64(unwind)), None) - } - _ => (None, None), - } + } + CallingConvention::WindowsFastcall => { + let unwind = self.machine.gen_windows_unwind_info(body_len); + if let Some(unwind) = unwind { + unwind_info = Some(CompiledFunctionUnwindInfo::WindowsX64(unwind)); } - _ => (None, None), } + _ => (), }; - #[cfg(not(feature = "unwind"))] - let (unwind_info, fde) = (None, None); let address_map = get_function_address_map(self.machine.instructions_address_map(), data, body_len);