Fix build errors in x86 unwind info when building no_std. (#1214)

This commit fixes the build errors in the unwind info implementation for
the x86 ABI by changing `byteorder` to build `no_std`.

This copies two simple functions from the `WriteBytesExt` trait so that
we can easily write to a `Vec<u8>` with a particular endianness.

Fixes #1203.
This commit is contained in:
Peter Huene
2019-11-07 16:41:32 -08:00
committed by Dan Gohman
parent cf82863ea9
commit 4ccf0fdfa3
3 changed files with 40 additions and 40 deletions

View File

@@ -22,7 +22,7 @@ log = { version = "0.4.6", default-features = false }
serde = { version = "1.0.94", features = ["derive"], optional = true } serde = { version = "1.0.94", features = ["derive"], optional = true }
smallvec = { version = "1.0.0" } smallvec = { version = "1.0.0" }
thiserror = "1.0.4" thiserror = "1.0.4"
byteorder = { version = "1.3.2" } byteorder = { version = "1.3.2", default-features = false }
# It is a goal of the cranelift-codegen crate to have minimal external dependencies. # 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 # 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 # machine code. Integration tests that need external dependencies can be

View File

@@ -836,6 +836,6 @@ pub fn emit_unwind_info(func: &ir::Function, isa: &dyn TargetIsa, mem: &mut Vec<
// Assumption: RBP is being used as the frame pointer // Assumption: RBP is being used as the frame pointer
// In the future, Windows fastcall codegen should usually omit 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())) { if let Some(info) = UnwindInfo::try_from_func(func, isa, Some(RU::rbp.into())) {
info.emit(mem).expect("failed to emit unwind information"); info.emit(mem);
} }
} }

View File

@@ -4,13 +4,25 @@ use super::registers::RU;
use crate::ir::{Function, InstructionData, Opcode}; use crate::ir::{Function, InstructionData, Opcode};
use crate::isa::{CallConv, RegUnit, TargetIsa}; use crate::isa::{CallConv, RegUnit, TargetIsa};
use alloc::vec::Vec; use alloc::vec::Vec;
use byteorder::{LittleEndian, WriteBytesExt}; use byteorder::{ByteOrder, LittleEndian};
/// Maximum (inclusive) size of a "small" stack allocation /// Maximum (inclusive) size of a "small" stack allocation
const SMALL_ALLOC_MAX_SIZE: u32 = 128; const SMALL_ALLOC_MAX_SIZE: u32 = 128;
/// Maximum (inclusive) size of a "large" stack allocation that can represented in 16-bits /// Maximum (inclusive) size of a "large" stack allocation that can represented in 16-bits
const LARGE_ALLOC_16BIT_MAX_SIZE: u32 = 524280; const LARGE_ALLOC_16BIT_MAX_SIZE: u32 = 524280;
fn write_u16<T: ByteOrder>(mem: &mut Vec<u8>, v: u16) {
let mut buf = [0; 2];
T::write_u16(&mut buf, v);
mem.extend(buf.iter());
}
fn write_u32<T: ByteOrder>(mem: &mut Vec<u8>, v: u32) {
let mut buf = [0; 4];
T::write_u32(&mut buf, v);
mem.extend(buf.iter());
}
/// The supported unwind codes for the x64 Windows ABI. /// The supported unwind codes for the x64 Windows ABI.
/// ///
/// See: https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64 /// See: https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64
@@ -24,7 +36,7 @@ enum UnwindCode {
} }
impl UnwindCode { impl UnwindCode {
fn emit(&self, mem: &mut Vec<u8>) -> std::io::Result<()> { fn emit(&self, mem: &mut Vec<u8>) {
enum UnwindOperation { enum UnwindOperation {
PushNonvolatileRegister, PushNonvolatileRegister,
LargeStackAlloc, LargeStackAlloc,
@@ -34,36 +46,32 @@ impl UnwindCode {
match self { match self {
Self::PushRegister { offset, reg } => { Self::PushRegister { offset, reg } => {
mem.write_u8(*offset)?; mem.push(*offset);
mem.write_u8( mem.push(((*reg as u8) << 4) | (UnwindOperation::PushNonvolatileRegister as u8));
((*reg as u8) << 4) | (UnwindOperation::PushNonvolatileRegister as u8),
)?;
} }
Self::StackAlloc { offset, size } => { Self::StackAlloc { offset, size } => {
// Stack allocations on Windows must be a multiple of 8 and be at least 1 slot // Stack allocations on Windows must be a multiple of 8 and be at least 1 slot
assert!(*size >= 8); assert!(*size >= 8);
assert!((*size % 8) == 0); assert!((*size % 8) == 0);
mem.write_u8(*offset)?; mem.push(*offset);
if *size <= SMALL_ALLOC_MAX_SIZE { if *size <= SMALL_ALLOC_MAX_SIZE {
mem.write_u8( mem.push(
((((*size - 8) / 8) as u8) << 4) | UnwindOperation::SmallStackAlloc as u8, ((((*size - 8) / 8) as u8) << 4) | UnwindOperation::SmallStackAlloc as u8,
)?; );
} else if *size <= LARGE_ALLOC_16BIT_MAX_SIZE { } else if *size <= LARGE_ALLOC_16BIT_MAX_SIZE {
mem.write_u8(UnwindOperation::LargeStackAlloc as u8)?; mem.push(UnwindOperation::LargeStackAlloc as u8);
mem.write_u16::<LittleEndian>((*size / 8) as u16)?; write_u16::<LittleEndian>(mem, (*size / 8) as u16);
} else { } else {
mem.write_u8((1 << 4) | (UnwindOperation::LargeStackAlloc as u8))?; mem.push((1 << 4) | (UnwindOperation::LargeStackAlloc as u8));
mem.write_u32::<LittleEndian>(*size)?; write_u32::<LittleEndian>(mem, *size);
} }
} }
Self::SetFramePointer { offset, sp_offset } => { Self::SetFramePointer { offset, sp_offset } => {
mem.write_u8(*offset)?; mem.push(*offset);
mem.write_u8((*sp_offset << 4) | (UnwindOperation::SetFramePointer as u8))?; mem.push((*sp_offset << 4) | (UnwindOperation::SetFramePointer as u8));
} }
}; };
Ok(())
} }
fn node_count(&self) -> usize { fn node_count(&self) -> usize {
@@ -160,7 +168,7 @@ impl UnwindInfo {
match opcode { match opcode {
Opcode::Iconst => { Opcode::Iconst => {
let imm: i64 = imm.into(); let imm: i64 = imm.into();
assert!(imm <= std::u32::MAX as i64); assert!(imm <= core::u32::MAX as i64);
assert!(stack_size.is_none()); assert!(stack_size.is_none());
// This instruction should only appear in a prologue to pass an // This instruction should only appear in a prologue to pass an
@@ -171,7 +179,7 @@ impl UnwindInfo {
} }
Opcode::AdjustSpDownImm => { Opcode::AdjustSpDownImm => {
let imm: i64 = imm.into(); let imm: i64 = imm.into();
assert!(imm <= std::u32::MAX as i64); assert!(imm <= core::u32::MAX as i64);
unwind_codes.push(UnwindCode::StackAlloc { unwind_codes.push(UnwindCode::StackAlloc {
offset: unwind_offset, offset: unwind_offset,
@@ -223,7 +231,7 @@ impl UnwindInfo {
.fold(0, |nodes, c| nodes + c.node_count()) .fold(0, |nodes, c| nodes + c.node_count())
} }
pub fn emit(&self, mem: &mut Vec<u8>) -> std::io::Result<()> { pub fn emit(&self, mem: &mut Vec<u8>) {
const UNWIND_INFO_VERSION: u8 = 1; const UNWIND_INFO_VERSION: u8 = 1;
let size = self.size(); let size = self.size();
@@ -237,30 +245,28 @@ impl UnwindInfo {
let node_count = self.node_count(); let node_count = self.node_count();
assert!(node_count <= 256); assert!(node_count <= 256);
mem.write_u8((self.flags << 3) | UNWIND_INFO_VERSION)?; mem.push((self.flags << 3) | UNWIND_INFO_VERSION);
mem.write_u8(self.prologue_size)?; mem.push(self.prologue_size);
mem.write_u8(node_count as u8)?; mem.push(node_count as u8);
if let Some(reg) = self.frame_register { if let Some(reg) = self.frame_register {
mem.write_u8((self.frame_register_offset << 4) | reg as u8)?; mem.push((self.frame_register_offset << 4) | reg as u8);
} else { } else {
mem.write_u8(0)?; mem.push(0);
} }
// Unwind codes are written in reverse order (prologue offset descending) // Unwind codes are written in reverse order (prologue offset descending)
for code in self.unwind_codes.iter().rev() { for code in self.unwind_codes.iter().rev() {
code.emit(mem)?; code.emit(mem);
} }
// To keep a 32-bit alignment, emit 2 bytes of padding if there's an odd number of 16-bit nodes // 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 { if (node_count & 1) == 1 {
mem.write_u16::<LittleEndian>(0)?; write_u16::<LittleEndian>(mem, 0);
} }
// Ensure the correct number of bytes was emitted // Ensure the correct number of bytes was emitted
assert_eq!(mem.len() - offset, size); assert_eq!(mem.len() - offset, size);
Ok(())
} }
} }
@@ -331,9 +337,7 @@ mod tests {
assert_eq!(unwind.size(), 12); assert_eq!(unwind.size(), 12);
let mut mem = Vec::new(); let mut mem = Vec::new();
unwind unwind.emit(&mut mem);
.emit(&mut mem)
.expect("failed to emit unwind information");
assert_eq!( assert_eq!(
mem, mem,
@@ -397,9 +401,7 @@ mod tests {
assert_eq!(unwind.size(), 12); assert_eq!(unwind.size(), 12);
let mut mem = Vec::new(); let mut mem = Vec::new();
unwind unwind.emit(&mut mem);
.emit(&mut mem)
.expect("failed to emit unwind information");
assert_eq!( assert_eq!(
mem, mem,
@@ -463,9 +465,7 @@ mod tests {
assert_eq!(unwind.size(), 16); assert_eq!(unwind.size(), 16);
let mut mem = Vec::new(); let mut mem = Vec::new();
unwind unwind.emit(&mut mem);
.emit(&mut mem)
.expect("failed to emit unwind information");
assert_eq!( assert_eq!(
mem, mem,