Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Commit

Permalink
Refactor unwind; add FDE support.
Browse files Browse the repository at this point in the history
  • Loading branch information
yurydelendik committed Jan 7, 2020
1 parent d3ab6ed commit 29b824e
Show file tree
Hide file tree
Showing 9 changed files with 348 additions and 19 deletions.
6 changes: 5 additions & 1 deletion cranelift-codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ hashbrown = { version = "0.6", optional = true }
target-lexicon = "0.9"
log = { version = "0.4.6", default-features = false }
serde = { version = "1.0.94", features = ["derive"], optional = true }
gimli = { version = "0.19.0", optional = true }
smallvec = { version = "1.0.0" }
thiserror = "1.0.4"
byteorder = { version = "1.3.2", default-features = false }
Expand All @@ -32,7 +33,7 @@ byteorder = { version = "1.3.2", default-features = false }
cranelift-codegen-meta = { path = "meta", version = "0.52.0" }

[features]
default = ["std", "basic-blocks"]
default = ["std", "basic-blocks", "unwind"]

# The "std" feature enables use of libstd. The "core" feature enables use
# of some minimal std-like replacement libraries. At least one of these two
Expand All @@ -47,6 +48,9 @@ core = ["hashbrown"]
# can significantly increase the size of the library.
testing_hooks = []

# This enables unwind info generation functionality.
unwind = ["gimli"]

# ISA targets for which we should build.
# If no ISA targets are explicitly enabled, the ISA target for the host machine is enabled.
x86 = []
Expand Down
23 changes: 23 additions & 0 deletions cranelift-codegen/src/binemit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,29 @@ pub trait CodeSink {
fn add_stackmap(&mut self, _: &[Value], _: &Function, _: &dyn TargetIsa);
}

/// Type of the frame unwind information.
pub enum FrameUnwindKind {
/// Windows fastcall unwinding (as in .pdata).
Fastcall,
/// FDE entry (as in .eh_frame or .debug_frame).
EhFrame,
}

/// Sink for frame unwind information.
pub trait FrameUnwindSink {
/// Get the current position.
fn offset(&self) -> CodeOffset;

/// Add bytes to the code section.
fn bytes(&mut self, _: &[u8]);

/// Add a relocation entry.
fn reloc(&mut self, _: Reloc, _: CodeOffset);

/// Specified offset to main structure.
fn set_entry_offset(&mut self, _: CodeOffset);
}

/// Report a bad encoding error.
#[cold]
pub fn bad_encoding(func: &Function, inst: Inst) -> ! {
Expand Down
13 changes: 9 additions & 4 deletions cranelift-codegen/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
//! single ISA instance.
use crate::binemit::{
relax_branches, shrink_instructions, CodeInfo, MemoryCodeSink, RelocSink, StackmapSink,
TrapSink,
relax_branches, shrink_instructions, CodeInfo, FrameUnwindKind, FrameUnwindSink,
MemoryCodeSink, RelocSink, StackmapSink, TrapSink,
};
use crate::dce::do_dce;
use crate::dominator_tree::DominatorTree;
Expand Down Expand Up @@ -201,8 +201,13 @@ impl Context {
///
/// Only some calling conventions (e.g. Windows fastcall) will have unwind information.
/// This is a no-op if the function has no unwind information.
pub fn emit_unwind_info(&self, isa: &dyn TargetIsa, mem: &mut Vec<u8>) {
isa.emit_unwind_info(&self.func, mem);
pub fn emit_unwind_info(
&self,
isa: &dyn TargetIsa,
kind: FrameUnwindKind,
sink: &mut dyn FrameUnwindSink,
) {
isa.emit_unwind_info(&self.func, kind, sink);
}

/// Run the verifier on the function.
Expand Down
5 changes: 5 additions & 0 deletions cranelift-codegen/src/ir/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,11 @@ impl Function {
/// Starts collection of debug information.
pub fn collect_debug_info(&mut self) {
self.dfg.collect_debug_info();
self.collect_frame_layout_info();
}

/// Starts collection of frame layout information.
pub fn collect_frame_layout_info(&mut self) {
self.frame_layout = Some(FrameLayout::new());
}

Expand Down
8 changes: 6 additions & 2 deletions cranelift-codegen/src/isa/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ use crate::settings::SetResult;
use crate::timing;
use alloc::borrow::Cow;
use alloc::boxed::Box;
use alloc::vec::Vec;
use core::fmt;
use target_lexicon::{triple, Architecture, PointerWidth, Triple};
use thiserror::Error;
Expand Down Expand Up @@ -382,7 +381,12 @@ pub trait TargetIsa: fmt::Display + Sync {
/// Emit unwind information for the given function.
///
/// Only some calling conventions (e.g. Windows fastcall) will have unwind information.
fn emit_unwind_info(&self, _func: &ir::Function, _mem: &mut Vec<u8>) {
fn emit_unwind_info(
&self,
_func: &ir::Function,
_kind: binemit::FrameUnwindKind,
_sink: &mut dyn binemit::FrameUnwindSink,
) {
// No-op by default
}
}
33 changes: 28 additions & 5 deletions cranelift-codegen/src/isa/x86/abi.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
//! x86 ABI implementation.
use super::super::settings as shared_settings;
use super::fde::emit_fde;
use super::registers::{FPR, GPR, RU};
use super::settings as isa_settings;
use super::unwind::UnwindInfo;
use crate::abi::{legalize_args, ArgAction, ArgAssigner, ValueConversion};
use crate::binemit::{FrameUnwindKind, FrameUnwindSink};
use crate::cursor::{Cursor, CursorPosition, EncCursor};
use crate::ir;
use crate::ir::immediates::Imm64;
Expand Down Expand Up @@ -947,10 +949,31 @@ fn insert_common_epilogue(
}
}

pub fn emit_unwind_info(func: &ir::Function, isa: &dyn TargetIsa, mem: &mut Vec<u8>) {
// Assumption: RBP is being used as the frame pointer
// In the future, Windows fastcall codegen should usually omit the frame pointer
if let Some(info) = UnwindInfo::try_from_func(func, isa, Some(RU::rbp.into())) {
info.emit(mem);
pub fn emit_unwind_info(
func: &ir::Function,
isa: &dyn TargetIsa,
kind: FrameUnwindKind,
sink: &mut dyn FrameUnwindSink,
) {
match kind {
FrameUnwindKind::Fastcall => {
let mut mem = Vec::new();
// Assumption: RBP is being used as the frame pointer
// In the future, Windows fastcall codegen should usually omit the frame pointer
if let Some(info) = UnwindInfo::try_from_func(func, isa, Some(RU::rbp.into())) {
info.emit(&mut mem);
}
sink.bytes(&mem);
}
FrameUnwindKind::EhFrame => {
if func.frame_layout.is_some() {
let (data, entry, relocs) = emit_fde(func, isa);
sink.bytes(&data);
sink.set_entry_offset(entry as u32);
for (off, r) in relocs {
sink.reloc(r, off);
}
}
}
}
}
Loading

0 comments on commit 29b824e

Please sign in to comment.