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

Implement emitting Windows unwind information for fastcall functions. #1155

Merged
merged 3 commits into from
Nov 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cranelift-codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ log = { version = "0.4.6", default-features = false }
serde = { version = "1.0.94", features = ["derive"], optional = true }
smallvec = { version = "0.6.10" }
thiserror = "1.0.4"
byteorder = { version = "1.3.2", default-features = false }
# It is a goal of the cranelift-codegen crate to have minimal external dependencies.
# Please don't add any unless they are essential to the task of creating binary
# machine code. Integration tests that need external dependencies can be
Expand Down
10 changes: 10 additions & 0 deletions cranelift-codegen/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,16 @@ impl Context {
sink.info
}

/// Emit unwind information.
///
/// Requires that the function layout be calculated (see `relax_branches`).
///
/// 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);
}

/// Run the verifier on the function.
///
/// Also check that the dominator tree and control flow graph are consistent with the function.
Expand Down
7 changes: 7 additions & 0 deletions cranelift-codegen/src/ir/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ pub struct Function {
/// Track the original source location for each instruction. The source locations are not
/// interpreted by Cranelift, only preserved.
pub srclocs: SourceLocs,

/// Instruction that marks the end (inclusive) of the function's prologue.
///
/// This is used for some calling conventions to track the end of unwind information.
pub prologue_end: Option<Inst>,
}

impl Function {
Expand All @@ -104,6 +109,7 @@ impl Function {
offsets: SecondaryMap::new(),
jt_offsets: SecondaryMap::new(),
srclocs: SecondaryMap::new(),
prologue_end: None,
}
}

Expand All @@ -123,6 +129,7 @@ impl Function {
self.offsets.clear();
self.jt_offsets.clear();
self.srclocs.clear();
self.prologue_end = None;
}

/// Create a new empty, anonymous function with a Fast calling convention.
Expand Down
8 changes: 8 additions & 0 deletions cranelift-codegen/src/isa/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ use crate::settings;
use crate::settings::SetResult;
use crate::timing;
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 @@ -377,4 +378,11 @@ pub trait TargetIsa: fmt::Display + Sync {

/// IntCC condition for Unsigned Subtraction Overflow (Borrow/Carry).
fn unsigned_sub_overflow_condition(&self) -> ir::condcodes::IntCC;

/// 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>) {
// No-op by default
}
}
18 changes: 14 additions & 4 deletions cranelift-codegen/src/isa/x86/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use super::super::settings as shared_settings;
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::cursor::{Cursor, CursorPosition, EncCursor};
use crate::ir;
Expand All @@ -16,6 +17,7 @@ use crate::isa::{CallConv, RegClass, RegUnit, TargetIsa};
use crate::regalloc::RegisterSet;
use crate::result::CodegenResult;
use crate::stack_layout::layout_stack;
use alloc::vec::Vec;
use core::i32;
use target_lexicon::{PointerWidth, Triple};

Expand Down Expand Up @@ -269,7 +271,7 @@ fn callee_saved_gprs(isa: &dyn TargetIsa, call_conv: CallConv) -> &'static [RU]
if call_conv.extends_windows_fastcall() {
// "registers RBX, RBP, RDI, RSI, RSP, R12, R13, R14, R15 are considered nonvolatile
// and must be saved and restored by a function that uses them."
// as per https://msdn.microsoft.com/en-us/library/6t169e9c.aspx
// as per https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention
// RSP & RSB are not listed below, since they are restored automatically during
// a function call. If that wasn't the case, function calls (RET) would not work.
&[
Expand Down Expand Up @@ -372,7 +374,7 @@ fn baldrdash_prologue_epilogue(func: &mut ir::Function, isa: &dyn TargetIsa) ->
}

/// Implementation of the fastcall-based Win64 calling convention described at [1]
/// [1] https://msdn.microsoft.com/en-us/library/ms235286.aspx
/// [1] https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention
fn fastcall_prologue_epilogue(func: &mut ir::Function, isa: &dyn TargetIsa) -> CodegenResult<()> {
if isa.triple().pointer_width().unwrap() != PointerWidth::U64 {
panic!("TODO: windows-fastcall: x86-32 not implemented yet");
Expand Down Expand Up @@ -580,11 +582,11 @@ fn insert_common_prologue(
if !isa.flags().probestack_func_adjusts_sp() {
let result = pos.func.dfg.inst_results(call)[0];
pos.func.locations[result] = rax_val;
pos.ins().adjust_sp_down(result);
pos.func.prologue_end = Some(pos.ins().adjust_sp_down(result));
}
} else {
// Simply decrement the stack pointer.
pos.ins().adjust_sp_down_imm(Imm64::new(stack_size));
pos.func.prologue_end = Some(pos.ins().adjust_sp_down_imm(Imm64::new(stack_size)));
}
}
}
Expand Down Expand Up @@ -658,3 +660,11 @@ fn insert_common_epilogue(
pos.func.dfg.append_inst_arg(inst, csr_ret);
}
}

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).expect("failed to emit unwind information");
}
}
9 changes: 9 additions & 0 deletions cranelift-codegen/src/isa/x86/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod binemit;
mod enc_tables;
mod registers;
pub mod settings;
mod unwind;

use super::super::settings as shared_settings;
#[cfg(feature = "testing_hooks")]
Expand All @@ -18,6 +19,7 @@ use crate::regalloc;
use crate::result::CodegenResult;
use crate::timing;
use alloc::boxed::Box;
use alloc::vec::Vec;
use core::fmt;
use target_lexicon::{PointerWidth, Triple};

Expand Down Expand Up @@ -150,6 +152,13 @@ impl TargetIsa for Isa {
fn unsigned_sub_overflow_condition(&self) -> ir::condcodes::IntCC {
ir::condcodes::IntCC::UnsignedLessThan
}

/// 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>) {
abi::emit_unwind_info(func, self, mem);
}
}

impl fmt::Display for Isa {
Expand Down
Loading