1 //! Defines `DataContext`. 2 3 use cranelift_codegen::binemit::{Addend, CodeOffset, Reloc}; 4 use cranelift_codegen::entity::PrimaryMap; 5 use cranelift_codegen::ir; 6 use std::borrow::ToOwned; 7 use std::boxed::Box; 8 use std::string::String; 9 use std::vec::Vec; 10 11 use crate::module::ModuleReloc; 12 use crate::ModuleExtName; 13 14 /// This specifies how data is to be initialized. 15 #[derive(Clone, PartialEq, Eq, Debug)] 16 #[cfg_attr(feature = "enable-serde", derive(serde::Serialize, serde::Deserialize))] 17 pub enum Init { 18 /// This indicates that no initialization has been specified yet. 19 Uninitialized, 20 /// Initialize the data with all zeros. 21 Zeros { 22 /// The size of the data. 23 size: usize, 24 }, 25 /// Initialize the data with the specified contents. 26 Bytes { 27 /// The contents, which also implies the size of the data. 28 contents: Box<[u8]>, 29 }, 30 } 31 32 impl Init { 33 /// Return the size of the data to be initialized. 34 pub fn size(&self) -> usize { 35 match *self { 36 Self::Uninitialized => panic!("data size not initialized yet"), 37 Self::Zeros { size } => size, 38 Self::Bytes { ref contents } => contents.len(), 39 } 40 } 41 } 42 43 /// A description of a data object. 44 #[derive(Clone, Debug)] 45 #[cfg_attr(feature = "enable-serde", derive(serde::Serialize, serde::Deserialize))] 46 pub struct DataDescription { 47 /// How the data should be initialized. 48 pub init: Init, 49 /// External function declarations. 50 pub function_decls: PrimaryMap<ir::FuncRef, ModuleExtName>, 51 /// External data object declarations. 52 pub data_decls: PrimaryMap<ir::GlobalValue, ModuleExtName>, 53 /// Function addresses to write at specified offsets. 54 pub function_relocs: Vec<(CodeOffset, ir::FuncRef)>, 55 /// Data addresses to write at specified offsets. 56 pub data_relocs: Vec<(CodeOffset, ir::GlobalValue, Addend)>, 57 /// Object file section 58 pub custom_segment_section: Option<(String, String)>, 59 /// Alignment in bytes. `None` means that the default alignment of the respective module should 60 /// be used. 61 pub align: Option<u64>, 62 } 63 64 impl DataDescription { 65 /// Allocate a new `DataDescription`. 66 pub fn new() -> Self { 67 Self { 68 init: Init::Uninitialized, 69 function_decls: PrimaryMap::new(), 70 data_decls: PrimaryMap::new(), 71 function_relocs: vec![], 72 data_relocs: vec![], 73 custom_segment_section: None, 74 align: None, 75 } 76 } 77 78 /// Clear all data structures in this `DataDescription`. 79 pub fn clear(&mut self) { 80 self.init = Init::Uninitialized; 81 self.function_decls.clear(); 82 self.data_decls.clear(); 83 self.function_relocs.clear(); 84 self.data_relocs.clear(); 85 self.custom_segment_section = None; 86 self.align = None; 87 } 88 89 /// Define a zero-initialized object with the given size. 90 pub fn define_zeroinit(&mut self, size: usize) { 91 debug_assert_eq!(self.init, Init::Uninitialized); 92 self.init = Init::Zeros { size }; 93 } 94 95 /// Define an object initialized with the given contents. 96 /// 97 /// TODO: Can we avoid a Box here? 98 pub fn define(&mut self, contents: Box<[u8]>) { 99 debug_assert_eq!(self.init, Init::Uninitialized); 100 self.init = Init::Bytes { contents }; 101 } 102 103 /// Override the segment/section for data, only supported on Object backend 104 pub fn set_segment_section(&mut self, seg: &str, sec: &str) { 105 self.custom_segment_section = Some((seg.to_owned(), sec.to_owned())) 106 } 107 108 /// Set the alignment for data. The alignment must be a power of two. 109 pub fn set_align(&mut self, align: u64) { 110 assert!(align.is_power_of_two()); 111 self.align = Some(align); 112 } 113 114 /// Declare an external function import. 115 /// 116 /// Users of the `Module` API generally should call 117 /// `Module::declare_func_in_data` instead, as it takes care of generating 118 /// the appropriate `ExternalName`. 119 pub fn import_function(&mut self, name: ModuleExtName) -> ir::FuncRef { 120 self.function_decls.push(name) 121 } 122 123 /// Declares a global value import. 124 /// 125 /// TODO: Rename to import_data? 126 /// 127 /// Users of the `Module` API generally should call 128 /// `Module::declare_data_in_data` instead, as it takes care of generating 129 /// the appropriate `ExternalName`. 130 pub fn import_global_value(&mut self, name: ModuleExtName) -> ir::GlobalValue { 131 self.data_decls.push(name) 132 } 133 134 /// Write the address of `func` into the data at offset `offset`. 135 pub fn write_function_addr(&mut self, offset: CodeOffset, func: ir::FuncRef) { 136 self.function_relocs.push((offset, func)) 137 } 138 139 /// Write the address of `data` into the data at offset `offset`. 140 pub fn write_data_addr(&mut self, offset: CodeOffset, data: ir::GlobalValue, addend: Addend) { 141 self.data_relocs.push((offset, data, addend)) 142 } 143 144 /// An iterator over all relocations of the data object. 145 pub fn all_relocs<'a>( 146 &'a self, 147 pointer_reloc: Reloc, 148 ) -> impl Iterator<Item = ModuleReloc> + 'a { 149 let func_relocs = self 150 .function_relocs 151 .iter() 152 .map(move |&(offset, id)| ModuleReloc { 153 kind: pointer_reloc, 154 offset, 155 name: self.function_decls[id].clone(), 156 addend: 0, 157 }); 158 let data_relocs = self 159 .data_relocs 160 .iter() 161 .map(move |&(offset, id, addend)| ModuleReloc { 162 kind: pointer_reloc, 163 offset, 164 name: self.data_decls[id].clone(), 165 addend, 166 }); 167 func_relocs.chain(data_relocs) 168 } 169 } 170 171 #[cfg(test)] 172 mod tests { 173 use crate::ModuleExtName; 174 175 use super::{DataDescription, Init}; 176 177 #[test] 178 fn basic_data_context() { 179 let mut data = DataDescription::new(); 180 assert_eq!(data.init, Init::Uninitialized); 181 assert!(data.function_decls.is_empty()); 182 assert!(data.data_decls.is_empty()); 183 assert!(data.function_relocs.is_empty()); 184 assert!(data.data_relocs.is_empty()); 185 186 data.define_zeroinit(256); 187 188 let _func_a = data.import_function(ModuleExtName::user(0, 0)); 189 let func_b = data.import_function(ModuleExtName::user(0, 1)); 190 let func_c = data.import_function(ModuleExtName::user(0, 2)); 191 let _data_a = data.import_global_value(ModuleExtName::user(0, 3)); 192 let data_b = data.import_global_value(ModuleExtName::user(0, 4)); 193 194 data.write_function_addr(8, func_b); 195 data.write_function_addr(16, func_c); 196 data.write_data_addr(32, data_b, 27); 197 198 assert_eq!(data.init, Init::Zeros { size: 256 }); 199 assert_eq!(data.function_decls.len(), 3); 200 assert_eq!(data.data_decls.len(), 2); 201 assert_eq!(data.function_relocs.len(), 2); 202 assert_eq!(data.data_relocs.len(), 1); 203 204 data.clear(); 205 206 assert_eq!(data.init, Init::Uninitialized); 207 assert!(data.function_decls.is_empty()); 208 assert!(data.data_decls.is_empty()); 209 assert!(data.function_relocs.is_empty()); 210 assert!(data.data_relocs.is_empty()); 211 212 let contents = vec![33, 34, 35, 36]; 213 let contents_clone = contents.clone(); 214 data.define(contents.into_boxed_slice()); 215 216 assert_eq!( 217 data.init, 218 Init::Bytes { 219 contents: contents_clone.into_boxed_slice() 220 } 221 ); 222 assert_eq!(data.function_decls.len(), 0); 223 assert_eq!(data.data_decls.len(), 0); 224 assert_eq!(data.function_relocs.len(), 0); 225 assert_eq!(data.data_relocs.len(), 0); 226 } 227 } 228