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