Path: blob/main/cranelift/module/src/data_context.rs
1692 views
//! Defines `DataDescription`.12use cranelift_codegen::binemit::{Addend, CodeOffset, Reloc};3use cranelift_codegen::entity::PrimaryMap;4use cranelift_codegen::ir;5use std::borrow::ToOwned;6use std::boxed::Box;7use std::string::String;8use std::vec::Vec;910use crate::ModuleRelocTarget;11use crate::module::ModuleReloc;1213/// This specifies how data is to be initialized.14#[derive(Clone, PartialEq, Eq, Debug)]15#[cfg_attr(16feature = "enable-serde",17derive(serde_derive::Serialize, serde_derive::Deserialize)18)]19pub enum Init {20/// This indicates that no initialization has been specified yet.21Uninitialized,22/// Initialize the data with all zeros.23Zeros {24/// The size of the data.25size: usize,26},27/// Initialize the data with the specified contents.28Bytes {29/// The contents, which also implies the size of the data.30contents: Box<[u8]>,31},32}3334impl Init {35/// Return the size of the data to be initialized.36pub fn size(&self) -> usize {37match *self {38Self::Uninitialized => panic!("data size not initialized yet"),39Self::Zeros { size } => size,40Self::Bytes { ref contents } => contents.len(),41}42}43}4445/// A description of a data object.46#[derive(Clone, Debug)]47#[cfg_attr(48feature = "enable-serde",49derive(serde_derive::Serialize, serde_derive::Deserialize)50)]51pub struct DataDescription {52/// How the data should be initialized.53pub init: Init,54/// External function declarations.55pub function_decls: PrimaryMap<ir::FuncRef, ModuleRelocTarget>,56/// External data object declarations.57pub data_decls: PrimaryMap<ir::GlobalValue, ModuleRelocTarget>,58/// Function addresses to write at specified offsets.59pub function_relocs: Vec<(CodeOffset, ir::FuncRef)>,60/// Data addresses to write at specified offsets.61pub data_relocs: Vec<(CodeOffset, ir::GlobalValue, Addend)>,62/// Object file section63pub custom_segment_section: Option<(String, String)>,64/// Alignment in bytes. `None` means that the default alignment of the65/// respective module should be used.66pub align: Option<u64>,67/// Whether or not to request the linker to preserve this data object even68/// if not referenced.69pub used: bool,70}7172impl DataDescription {73/// Allocate a new `DataDescription`.74pub fn new() -> Self {75Self {76init: Init::Uninitialized,77function_decls: PrimaryMap::new(),78data_decls: PrimaryMap::new(),79function_relocs: vec![],80data_relocs: vec![],81custom_segment_section: None,82align: None,83used: false,84}85}8687/// Clear all data structures in this `DataDescription`.88pub fn clear(&mut self) {89self.init = Init::Uninitialized;90self.function_decls.clear();91self.data_decls.clear();92self.function_relocs.clear();93self.data_relocs.clear();94self.custom_segment_section = None;95self.align = None;96self.used = false;97}9899/// Define a zero-initialized object with the given size.100pub fn define_zeroinit(&mut self, size: usize) {101debug_assert_eq!(self.init, Init::Uninitialized);102self.init = Init::Zeros { size };103}104105/// Define an object initialized with the given contents.106///107/// TODO: Can we avoid a Box here?108pub fn define(&mut self, contents: Box<[u8]>) {109debug_assert_eq!(self.init, Init::Uninitialized);110self.init = Init::Bytes { contents };111}112113/// Override the segment/section for data, only supported on Object backend114pub fn set_segment_section(&mut self, seg: &str, sec: &str) {115self.custom_segment_section = Some((seg.to_owned(), sec.to_owned()))116}117118/// Set the alignment for data. The alignment must be a power of two.119pub fn set_align(&mut self, align: u64) {120assert!(align.is_power_of_two());121self.align = Some(align);122}123124/// Set whether or not the linker should preserve this data object even if125/// not referenced.126pub fn set_used(&mut self, used: bool) {127self.used = used;128}129130/// Declare an external function import.131///132/// Users of the `Module` API generally should call133/// `Module::declare_func_in_data` instead, as it takes care of generating134/// the appropriate `ExternalName`.135pub fn import_function(&mut self, name: ModuleRelocTarget) -> ir::FuncRef {136self.function_decls.push(name)137}138139/// Declares a global value import.140///141/// TODO: Rename to import_data?142///143/// Users of the `Module` API generally should call144/// `Module::declare_data_in_data` instead, as it takes care of generating145/// the appropriate `ExternalName`.146pub fn import_global_value(&mut self, name: ModuleRelocTarget) -> ir::GlobalValue {147self.data_decls.push(name)148}149150/// Write the address of `func` into the data at offset `offset`.151pub fn write_function_addr(&mut self, offset: CodeOffset, func: ir::FuncRef) {152self.function_relocs.push((offset, func))153}154155/// Write the address of `data` into the data at offset `offset`.156pub fn write_data_addr(&mut self, offset: CodeOffset, data: ir::GlobalValue, addend: Addend) {157self.data_relocs.push((offset, data, addend))158}159160/// An iterator over all relocations of the data object.161pub fn all_relocs<'a>(162&'a self,163pointer_reloc: Reloc,164) -> impl Iterator<Item = ModuleReloc> + 'a {165let func_relocs = self166.function_relocs167.iter()168.map(move |&(offset, id)| ModuleReloc {169kind: pointer_reloc,170offset,171name: self.function_decls[id].clone(),172addend: 0,173});174let data_relocs = self175.data_relocs176.iter()177.map(move |&(offset, id, addend)| ModuleReloc {178kind: pointer_reloc,179offset,180name: self.data_decls[id].clone(),181addend,182});183func_relocs.chain(data_relocs)184}185}186187#[cfg(test)]188mod tests {189use crate::ModuleRelocTarget;190191use super::{DataDescription, Init};192193#[test]194fn basic_data_context() {195let mut data = DataDescription::new();196assert_eq!(data.init, Init::Uninitialized);197assert!(data.function_decls.is_empty());198assert!(data.data_decls.is_empty());199assert!(data.function_relocs.is_empty());200assert!(data.data_relocs.is_empty());201202data.define_zeroinit(256);203204let _func_a = data.import_function(ModuleRelocTarget::user(0, 0));205let func_b = data.import_function(ModuleRelocTarget::user(0, 1));206let func_c = data.import_function(ModuleRelocTarget::user(0, 2));207let _data_a = data.import_global_value(ModuleRelocTarget::user(0, 3));208let data_b = data.import_global_value(ModuleRelocTarget::user(0, 4));209210data.write_function_addr(8, func_b);211data.write_function_addr(16, func_c);212data.write_data_addr(32, data_b, 27);213214assert_eq!(data.init, Init::Zeros { size: 256 });215assert_eq!(data.function_decls.len(), 3);216assert_eq!(data.data_decls.len(), 2);217assert_eq!(data.function_relocs.len(), 2);218assert_eq!(data.data_relocs.len(), 1);219220data.clear();221222assert_eq!(data.init, Init::Uninitialized);223assert!(data.function_decls.is_empty());224assert!(data.data_decls.is_empty());225assert!(data.function_relocs.is_empty());226assert!(data.data_relocs.is_empty());227228let contents = vec![33, 34, 35, 36];229let contents_clone = contents.clone();230data.define(contents.into_boxed_slice());231232assert_eq!(233data.init,234Init::Bytes {235contents: contents_clone.into_boxed_slice()236}237);238assert_eq!(data.function_decls.len(), 0);239assert_eq!(data.data_decls.len(), 0);240assert_eq!(data.function_relocs.len(), 0);241assert_eq!(data.data_relocs.len(), 0);242}243}244245246